CockroachDB架构的分布式层提供了集群数据的统一视图。

如果你还没阅读过架构概览,建议你先阅读该篇。

概览

为了使集群中的所有数据都可以从任何节点访问,CockroachDB将数据存储在KV对的整体有序map中。 此keyspace描述了集群中的所有数据及其位置,并分为我们称之为“ranges”的keyspace的连续块,以便我们可以在单个range内找到key。

CockroachDB实现有序map以允许:

Monolithic Sorted Map 结构

Monolithic Sorted Map由两个基本要素组成:

Meta Ranges(meta range)

群集中所有range的位置都存储在keyspace开头的两级索引中,称为meta range(meta ranges),其中第一级(meta1)寻址第二级,第二级(meta2)索引集群中的数据。 重要的是,每个节点都有关于meta1 range的位置信息(称为其range描述符,详见下文),并且该range从不分割。

这个meta range结构默认允许存储最多4EiB的用户数据:我们可以有2 ^(18 + 18)= 2 ^ 36个range; 每个range寻址2 ^ 26 B,并且我们总共寻址2 ^(36 + 26)B = 2 ^ 62 B = 4EiB。 但是,如果range较大,则可以进一步扩展此容量。

meta range被视为正常range,并且可以像群集的KV数据的其他元素一样进行访问和复制。

每个节点都缓存它之前访问过的meta2的range的值,这将优化未来对该数据的访问。 每当节点发现其meta2缓存对于特定key无效时,通过对meta2range执行常规读取来更新缓存。

Table Data(表数据)

在节点的meta range后面就是集群中存储的KV数据。

该数据被切分为64MiB大小的连续的部分,称为range。 64MiB足够小以满足在节点间快速移动,也足够大用来存储有意义的连续的数据集,key可能会一起被访问到。 这些range可以在集群内进行shuffle,以确保可用性(to ensure survivability)。

这些range被复制(在Replication层中),并且每个副本的地址存储在meta2 range内。

使用Monolithic Sorted Map

当节点收到请求时,它会查看Meta range,通过将请求中的key与其meta2 range内的key进行比较,找出将请求路由到哪个节点。

这些meta range被高度缓存,因此通常在不必将RPC发送到实际包含meta2range的节点来进行处理。

然后,节点将这些KV操作发送到meta2 range中标识要访问range的Leaseholder。 但是,数据位置可能发生了变化,这样的话该节点就不存在请求的数据, 在这种情况下,我们会回到meta2 range以获取更多最新信息,然后再重试一次。

与其他层的交互

与CockroachDB中的其他层的关联中,Distribution层:

技术细节和组成

gRPC

gRPC是用于彼此通信的软件节点。 由于Distribution层是与其他节点通信的第一层,因此CockroachDB在此处实现了gRPC。

gRPC要求输入和输出格式化为protocol buffers(protobufs)。 为了使用gRPC,CockroachDB实现了api.proto中定义的protocol-buffer-based的API。

更多关于gRPC的信息,查看official gRPC documentation.

BatchRequest

所有KV操作请求都捆绑在protobuf中,称为BatchRequest。 此batch的目的以及指向请求的事务记录的指针在BatchRequest的header中标识。(另一方面,当一个节点回复BatchRequest时,它也使用protobuf --BatchResponse。)

这个BatchRequest也是使用gRPC在节点之间发送请求的,gRPC接受和发送 protocol buffers。

DistSender

网关/协调节点的DistSender从其自己的TxnCoordSender接收BatchRequest,然后DistSender负责拆分BatchRequests并将一组新的BatchRequests,然后依据meta2 range,路由到对应的包含请求数据的节点。 使用缓存的meta2` range将请求发送给Leaseholder,但它也准备按照远近的顺序尝试其他副本。 缓存所说的副本是Leaseholder,它会被移动到副本的列表的最前面,然后按顺序将RPC发送给所有副本。

非Leaseholder收到的请求会失败,错误指向副本的Leaseholder。 这些请求会使用更新后的lease,在网关节点重试,并且该错误不会报告给客户端。

当节点开始回复这些命令时,DistSender也会聚合结果,准备将它们返回给客户端。

Meta Range KV 结构

与群集中的所有其他数据一样,meta range构造为KV对。 这两个meta range都具有类似的结构:

metaX/successorKey -> LeaseholderAddress, [list of other nodes containing data]
Element Description
metaX meta range的层次。 这里我们使用简化的meta1meta2,但这些实际上分别在cockroach中表示为\ x02\ x03
successorKey 大于你正在查找的key的第一个key。 这使得CockroachDB的扫描效率很高; 它只是扫描key,直到它找到一个大于它正在寻找的键的值,这就是它找到相关数据的地方。

用于键空间结尾的successorKey被标识为maxKey
LeaseholderAddress 主要负责读写的副本,称为Leaseholder。 Replication层包含更多关于Lease的信息:Leases.

这是一个例子:

meta2/M -> node1:26257, node2:26257, node3:26257

在这种情况下,node1上的副本是Leaseholder,而节点2和3也包含副本。

示例

假设我们有一个按字母顺序排序的列,我们将其用于查找。 meta range内容大致如下:

# Points to meta2 range for keys [A-M)
meta1/M -> node1:26257, node2:26257, node3:26257

# Points to meta2 range for keys [M-Z]
meta1/maxKey -> node4:26257, node5:26257, node6:26257
# Contains [A-G)
meta2/G -> node1:26257, node2:26257, node3:26257

# Contains [G-M)
meta2/M -> node1:26257, node2:26257, node3:26257

#Contains [M-Z)
meta2/Z -> node4:26257, node5:26257, node6:26257

#Contains [Z-maxKey)
meta2/maxKey->  node4:26257, node5:26257, node6:26257

Table Data KV 结构

KV数据,使用以下结构表示表中的数据:

/<table Id>/<index id>/<indexed column values> -> <non-indexed/STORING column values>

表本身存储的index_id为1的PRIMARY KEY列,表中的其余列被视为存储/覆盖列(stored/covered columns.)。

Range描述符

CockroachDB中的每个range都包含元数据,称为range描述符。 range描述符由以下内容组成:

因为range描述符包含meta2 range的kv数据,所以每个节点的meta2缓存也存储range描述符。

只要有以下情况,range描述符就会更新:

range描述符的所有这些更新都在本地range内发生,然后传播到meta2range。

Range分裂

默认情况下,CockroachDB会尝试将range/副本保持在64MiB。 一旦range达到该限制,我们将其分成两个32 MiB范围(由连续的keyspace组成)。

在此range 分裂期间,节点会创建一个新的Raft组,它包含与拆分range相同的所有数据。 现在有两个range也意味着有一个事务使用新的keyspace边界更新meta2,以及使用range描述符更新节点的地址。

与其他层的交互

Distribution & Transaction Layer(分布式层和事务层)

Distribution层的DistSender从自己的节点TxnCoordSender接收BatchRequests,它位于Transaction层中。

Distribution & Replication Layer(分布式层和复制层)

Distribution层将BatchRequests路由到包含数据range的节点,这些节点最终路由到Raft组leader或Leaseholder,这些数据在Replication层中处理。

What's Next?

了解CockroachDB如何复制数据并确保数据的一致性: Replication Layer