CockroachDB架构的分布层提供了集群数据的统一视图。
--注意:
1)如果您还没有准备好,我们建议先阅读架构概览部分。
一.概览
为了从任何节点访问集群中的所有数据,CockroachDB按照整体排序映射来存储键值对。该键空间描述集群中数据的所有信息及其位置,并将其分为我们称为的"范围",其为连续的键空间块,以便每个键值总是能在单个范围内找到。
CockroachDB实施排序映射以开启:
1)简化查找(Simple lookups):因为我们要鉴别哪个节点复制某部分数据,查询能快速定位其需要的数据的位置。
2)高效扫描(Efficient scans):通过定义数据的顺序,扫描期间发现特定范围内的数据变的容易。
1.整体排序的映射结构
整体排序的映射包括连个基本元素:
1)系统数据,其包括描述集群中数据位置的元范围(在很多其他集群范围和本地数据元素中)。
2)用户数据,其存储集群的表数据。
1)元范围
集群中所有范围的位置存储于键空间开始部分的一个两级索引中,称为元范围,其一级(meta1)寻址二级,二级(meta2)寻址集群中的数据。重要的是,每个节点有定位meta1范围(称为其范围描述符,下面详述)位置的信息,且该范围从不会被拆分。
该元范围结构默认可以对4EiB的用户数据进行寻址:我们可以寻址2^(18+18)=2^36个范围;每个范围寻址2^26B,这样,我们可以对2^(36+26)B=2^62B=4EiB的数据进行寻址。但是,如果范围更大,这个容量可能得到进一步扩展。
元范围几乎像常规范围一样处理,且就像集群中KV数据的其他元素一样进行访问和复制。
每个节点缓冲之前访问的meta2范围数值,这会将来对这些数据的访问。无论何时节点发现其缓冲的某个meta2特定键值无效,就会通过该meta2范围的常规读取对该缓冲进行更新。
2)表数据
节点元范围之后是集群存储的KV数据。
每张表及其二级索引最初映射到单个范围,该范围内的每个键值对表示该表(因为该表按照主键排序,因此,也称为主键)或二级索引中的一个数据行。一旦范围达到512MiB,其将拆分为两个范围。当表及其索引持续增长时,该过程也会继续下去。一旦一张表拆分为多个范围,表和二级索引将可能分别存储到单独的范围内。但是,一个范围还是可能包含表和二级索引的数据。
默认的512MiB范围大小对我们来说是一个合适的点,其足够小,以便其在节点间进行快速移动,但又足够大,以便存储一套更可能被一起访问的有意义的连续数据集。这些范围在集群内调动以确保数据在意外事件中的生存性。
这些表的范围被复制(在适当命名的复制层中),并有存储于meta2范围内的每个副本的地址。
2.使用整体排序的映射
当某个节点接收到一个请求时,其将查看元范围并对请求中的键值与meta2范围内的键值进行对比以发现需要将该请求路由到哪个节点。
这些元数据会被大量缓冲,因此,这通常会被本地处理而无需发送RPC到实际包含该meta2范围的节点。
该节点接着将那些KV操作发送到前面meta2范围内识别到的租约持有者。但是,这些数据可能已发生移动,因此,不再存储这些数据的节点将向请求节点返回数据目前的存储位置。这种情况下,我们必须回到meta2范围获取最新信息并进行重试。
3.与其他层的交互
CockroachDB中,分布层与其他层的关系为:
1)从同一节点的事务层接收请求。
2)鉴别哪些节点应该接收该请求,并将该请求发送到相应节点的复制层。
二.技术细节与组件
1.gRPC
gRPC是节点间用于通信的软件。因为分布层是与其他节点通信的第一层,所以,CockroachDB将gRPC实施在该层。
gRPC需要将输入和输出格式化为协议缓冲(protobufs)。为了利用gRPC,CockroachDB实施了定义在api.proto中的基于协议缓冲的API。
有关gRPC更多的信息,可以参考官方gRPC文档。
2.BatchRequest
所有的KV操作请求都被绑定到一个protobuf,称为BatchRequest。这些批处理的目的地通过BatchRequest头部标识,以及指向该请求事务记录的指针。(另一方面,当一个节点响应一个BatchRequest时,其使用一个protobuf--BatchRequest。)
该BatchRequest也被用于在节点间用gRPC发送请求,gRPC接收和发送协议缓冲(protocol buffers)。
3.DistSender
网关/协调节点的DistSender从其自己的TxnCoorSender接收BatchRequests。DistSender接着负责分解BatchRequests并将一套新BatchRequests路由到其通过meta2范围识别出包含这些数据的节点。其使用缓冲将请求发送到相应的租约持有者,但也准备试验其他副本,按照"proximity"顺序。仅将缓冲说是租约持有者的副本移到副本的前面进行试验,接着,按顺序给它们发送一个RPC。
非租约持有者接收的请求失败,并报出指向副本最后已知租约持有者的错误。这些请求通过网关节点更改的租约进行透明重试,且从来不会到达客户端。
当节点开始相应这些命令时,DiskSender也对这些结果进行汇聚并准备将其返回客户端。
4.元范围KV结构
就像集群中所有其他数据一样,元范围作为KV对被构造。元范围有类似结构:
metaX/successorKey -> LeaseholderAddress, [list of other nodes containing data]
其中,元素及描述如下:
1)metaX:元范围的级别。这里,我们使用简化的meta1和meta2,但这些在cockroach中实际分别表示为x02和\x03。
2)successorKey:比您扫描的键值更大的第一个键值。这使得CockroachDB的扫描效率更高;其仅仅扫描键值直到发现一个比要找的键值大的数值,且那是其发现相关数据的位置。
键值空间末端的successorKey被标识为maxKey。
3)LeaseholderAddress:主要负责读写的副本,称为租约持有者。复制层包含有关租约的更多信息。
下面是一个例子:
meta2/M -> node1:26257, node2:26257, node3:26257
这种情况下,节点1上的副本为租约持有者,节点2和节点3也包含副本。
例子:
我们想象有一个按字母顺序排序的列,我们用它来进行查找。这里是元范围近似的样子:
meta1包含meta2副本所在节点的地址。
#指向键值[A-M)的meta2范围
meta1/M -> node1:26257, node2:26257, node3:26257
#指向键值[M-Z]的meta2范围
meta1/maxKey -> node4:26257, node5:26257, node6:26257
meta2包含集群中每个范围的副本所在节点的地址,其中,第一个为租约持有者。
#包含[A-G)
meta2/G -> node1:26257, node2:26257, node3:26257
#包含[G-M)
meta2/M -> node1:26257, node2:26257, node3:26257
#包含[M-Z)
meta2/Z -> node4:26257, node5:26257, node6:26257
#包含[Z-maxKey)
meta2/maxKey-> node4:26257, node5:26257, node6:26257
5.表数据KV结构
键-值数据,其用下面的结构表示表中的数据:
/<table Id>/<index id>/<indexed column values> -> <non-indexed/STORING column values>
表本身以主键列上的index_id为1的索引存储,表中其他列被认作存储/覆盖列。
6.范围描述符
CockroachDB中的每个范围包含元数据,称为范围描述符。一个范围描述符包含下列内容:
1)一个连续RangeID
2)该范围包含的键值空间(即,包含的键值);例如:在上述表数据KV结构中的第一个和最后一个<索引列值>。这决定了meta2范围的键值。
3)包含该范围副本节点的地址,及第一个位置的租约持有者(其负责读写)。这决定了meta2范围的键值。
因为范围描述符包含meta2范围的键值数据,所以,每个节点的meta2缓冲也存储范围描述符。
当发生如下事件时,范围描述符被更新:
1)更改范围的Raft组成员(更多细节将在复制层讨论)。
2)租约持有者发生改变。
3)范围拆分。
所有这些对范围描述符的更新发生在本地该范围上,接着,传播到meta2范围。
7.范围拆分
默认地,CockroachDB试图保持范围/副本的大小为512MiB。一旦范围达到该限制,将被拆分成两个更小的范围(由连续的键值空间组成)。
范围拆分期间,节点创建一个新的Raft组,其包含与被拆分的范围的所有相同成员。现在有两个范围的事实也意味着有一个用新键值空间边界更新meta2的事务,也包括用范围描述符的节点的地址。
三.与其他层的技术交互
1.分布和事务层
分布层的DistSender接收来自本身节点TxnCoordSender的BatchRequests,其驻留在事务层。
2.分布和复制层
分布层将BatchRequests路由到包含数据范围的节点,其最终被路由到Raft组领导者或租约持有者,其在复制层被处理。
四.个人观点
1.分布层的作用真的是承上启下,上面接收来自事务层的请求,下面将这些请求分解后再发给复制层进行处理。
1.分布层在每款NewSQL产品中都会存在,虽然叫法可能不同,但类似的功能层应该都是存在的,这是数据分布式存储的基础和关键,所以,也没什么好说的。