PolarDB 卷来卷去 云原生低延迟强一致性读 2 (SCC READ 译 跟踪层次优化)

2023-11-13 11:48:12 浏览数 (1)

分层修改跟踪器

在基本的读等待方案中,在处理RO节点上的读请求之前,总是要等待发生在特定时间戳之前的日志被应用,这意味着即使此请求仅访问数据的一个小子集也必须等待所有本地内存数据更新为最新,为避免对于读请求中无关的日志应用而产生的等待,我们提出一种新的修改跟踪协议,以不同的层次来跟踪RW节点最新修改时间戳,使RO节点能够在不同的层级上检查时间戳,并且只需要等待请求的数据更新为最新。

关系数据库通常在逻辑层级上将数据组织成表,并以页面为单位管理物理数据,因此三个层级上跟踪RW节点最新修改,主要分为三个层次,全局层,表层,和页面层级,顶层维护全局数据库最新修改时间戳,下面两层表层,和 页面层,基于一致性通常在事务级别上考虑,我们使用全局提交时间戳作为全局级别时间戳,但跟踪表/页提交时间说会引入更多额外的开销,因为要跟踪每个事务所有修改过的页和表,并在提交时更新他们提交的时间戳,主流数据库总是为每个表/页每次更新生成响应的日志,因此我们利用现有的日志序号作为表和页修改时间戳,并不会产生额外的开销。

上图显示了分层修改干总起的架构,顶层只需要维护一个时间戳,而第二第三层必须为不同的表/页维护许多的时间戳,所以添加了修改跟踪表MTT,用于记录页和表最新修改时间戳,MTT以哈希表形式组织,哈希表的键是表ID (TID),或页ID PID的哈希值,值是响应的最新修改的时间戳,当事务提交时RW节点将更新顶层时间戳,并在相关页/表更新时更改相应的MTT,RO 节点可以从RW节点获取这三个层级的时间戳,并与本地时间戳一起在本地缓存,一遍重新使用,所以RO节点具有与RW节点相同的三个级别的时间戳数据结构,但每个级别行会多一个字段存储本地时间戳。

要在RO 节点上执行强一致读取,首先谁检查全局级别的时间戳,然后是素有请求的表和页的时间戳,一旦满足了一个级别将直接处理请求,不会检查下一个级别的,只有在最后一个级别不满足的情况下,才需要等待日志应用,全局和表级别满足,这些请求只需要一次性的时间戳检查,与每个请求都需要请求时间戳相比,可以节省时间戳检查的时间,但当RO节点的日志应用无法跟上RW节点的更新时,RO 节点可能需要为大多数读请求等待日志应用。

因此这三个级别的时间戳共同在不同的情况下实现在只读节点上的低延迟,同时可以从linear Lamport时间戳中获益,对于每个级别的时间戳检查本地缓存有效的情况下,可以直接使用他,MTT的实现为了避免过多占用内存,将所有的页面/表,的最新修改时间戳存储到MTT中是不大实际的,我们将MTT组织成一个HASH表,在读写节点上,多个页面或表会被HASH到同一个MTT的插槽,当制度节点根据HASH的PID/TID,从读写节点的MTT总获取一个时间戳时,制度节点才会更新MTT记录的时间戳,只有当心的时间戳大于先行的值,制度节点才会更新MTT记录的时间戳,MTT槽中的时间戳始终是映射到该槽中所有时间戳中的最大值。

通常MTT的大小只有几百个字节,远小于缓冲池的大小,基于单边RDMA不需要远程主机参与,并且通常具有比双边RDMA操作更低的延迟,因此在时间戳获取中充分利用单边RDMA通过HASH 表实现MTT的考虑之一是从RDMA单边访问内存数据结构的时候,必须要知道远程主机的内存地址,因此读写节点在运行时不应动态更改数据结构大小或删除添加元素通过hash表的设计,当数据库启动时,读写节点可以为hash表分配内存空间,HASH表的大小在启动时固定,当只读节点尝试取页面/表的时间戳时,可以通过偏移量来计算目标远程的内存地址,通过单边RDMA可以进行时间戳的获取,以节省读写节点的CPU资源并减少时间戳获取的网络开销。只有当新的值大约当前的值,才进行更新时间戳,这仍然满足SCC的强一致特性,在POLARDB-SCC中MTT的大小通常在启动时就固定了,大多数操作是更新和读取操作,因此我们使用普通的hash表来实现MTT。

与传统的单边时间戳相比,分层修改跟踪的方式设计需要更多操作来获取不同级别的时间戳,同时也缺失避免不了不必要的等待日志应用,时间戳还可以在只读节点上缓存来进行复用,这种额外开销可以在多个请求中摊销,时间戳获取是通过快速的单边RDMA完成,统称在几个微妙完成。

待......

0 人点赞