共计 3575 个字符,预计需要花费 9 分钟才能阅读完成。
作者:Eric Fu\
链接:https://ericfu.me/yugabyte-db…
Yugabyte DB 是一个寰球部署的分布式数据库,和国内的 TiDB 和国外的 CockroachDB 相似,也是受到 Spanner 论文启发,所以在很多中央这几个数据库存在不少相似之处。
与 Cockroach 相似,Yugabyte 也主打寰球分布式的事务数据库——不仅能把节点部署到寰球各地,还能残缺反对 ACID 事务,这是他最大的卖点。除此以外还有一些独特的个性,比方反对文档数据库接口。如果我猜的没错,Yugabyte 晚期被设计成一个文档数据库,起初才调整技术路线开始主打 SQL 接口。
本文信息次要来自于 Yugabyte 的官网文档:
https://docs.yugabyte.com/
以及其 GitHub 主页:
https://github.com/yugabyte/y…
零碎架构
逻辑上,Yugabyte 采纳两层架构:查问层和存储层。不过这个架构仅仅是逻辑上的,部署构造中,这两层都位于 TServer 过程中。这一点和 TiDB 不同。
Yugabyte 的查问层反对同时 SQL 和 CQL 两种 API,其中 CQL 是兼容 Cassandra 的一种方言语法,对应于文档数据库的存储模型;而 SQL API 是间接基于 PostgresQL 魔改的,能比拟好地兼容 PG 语法,据官网说这样能够更不便地追随 PG 新个性,有没有官网说的这么美妙咱们就不得而知了。
Yugabyte 的存储层才是重头戏。其中 TServer 负责存储 tablet,每个 tablet 对应一个 Raft Group,散布在三个不同的节点上,以此保障高可用性。Master 负责元数据管理,除了 tablet 的地位信息,还包含表构造等信息。Master 自身也依附 Raft 实现高可用。
基于 Tablet 的分布式存储
这一部分是 HBase/Spanner 精华局部,Cockroach/TiDB 的做法简直也是截然不同的。如下图所示,每张表被分成很多个 tablet,tablet 是数据分布的最小单元,通过在节点间搬运 tablet 以及 tablet 的决裂与合并,就能够实现简直无下限的 scale out。每个 tablet 有多个正本,造成一个 Raft Group,通过 Raft 协定保证数据的高可用和持久性,Group Leader 负责解决所有的写入负载,其余 Follower 作为备份。
下图是一个例子:一张表被分成 16 个 tablet,tablet 的正本和 Raft Group leader 均匀分布在各个节点上,别离保障了数据的平衡和负载的平衡。
和其余产品一样,Master 节点会负责协调 tablet 的搬运、决裂等操作,保障集群的负载平衡。这些操作是间接基于 Raft Group 实现的。这里就不再开展了。
乏味的是,Yugabyte 采纳哈希和范畴联合的分区形式:能够只有哈希分区、也能够只有范畴分区、也能够先按哈希再按范畴分区。之所以这么设计,猜想也是因为 Cassandra 的影响。相比之下,TiDB 和 Cockroach 都只反对范畴分区。
哈希分区的形式是将 key 哈希映射到 2 字节的空间中(即 0x0000
到 0xFFFF
),这个空间又被划分成多个范畴,比方下图的例子中被划分为 16 个范畴,每个范畴的 key 落在一个 tablet 中。实践上说最多可能有 64K 个 tablet,这对理论应用足够了。
哈希分区的益处是插入数据(尤其是从尾部 append 数据)时不会呈现热点;害处是对于小范畴的范畴扫描(例如 pk BETWEEN 1 AND 10
)性能会比拟吃亏。
基于 RocksDB 的本地存储
每个 TServer 节点上的本地存储称为 DocDB。和 TiDB/Cockroach 一样,Yugabyte 也用 RocksDB 来做本地存储。这一层须要将关系型 tuple 以及文档编码为 key-value 保留到 RocksDB 中,下图是对文档数据的编码方式,其中有不少是为了兼容 Cassandra 设计的,咱们疏忽这些,次要关注以下几个局部:
key 中蕴含
- 16-bit hash:依附这个值能力做到哈希分区
- 主键数据(对应图中 hash/range columns)
- column ID:因为每个 tuple 有多个列,每个列在这里须要用一个 key-value 来示意
- hybrid timestamp:用于 MVCC 的工夫戳
value 中蕴含
- column 的值
如果撇开文档模型,key-value 的设计很像 Cockroach:每个 cell(一行中的一列数据)对应一个 key-value。而 TiDB 是每个 tuple 打包成一个 key-value。集体比拟偏好 TiDB 的做法。
分布式事务:2PC & MVCC
和 TiDB/Cockroach 一样,Yugabyte 也采纳了 MVCC 联合 2PC 的事务实现。
工夫戳
工夫戳是分布式事务的要害选型之一。Yugabyte 和 Cockroach 一样抉择的是 Hybrid Logical Clock (HLC)。
HLC 将工夫戳分成物理(高位)和逻辑(低位)两局部,物理局部对应 UNIX 工夫戳,逻辑局部对应 Lamport 时钟。在同一毫秒以内,物理时钟不变,而逻辑时钟就和 Lamport 时钟一样解决——每当产生信息替换(RPC)就须要更新工夫戳,从而确保操作与操作之间可能造成一个偏序关系;当下一个毫秒到来时,逻辑时钟局部归零。
不难看出,HLC 的正确性其实是由 Logical Clock 来保障的:它相比 Logical Clock 只是在每个毫秒引入了一个额定的增量,显然这不会毁坏 Logical Clock 的正确性。然而,物理局部的存在将本来无意义的工夫戳赋予了物理意义,进步了实用性。
集体认为,HLC 是除了 TrueTime 以外最好的工夫戳实现了,惟一的毛病是不能提供真正意义上的内部一致性,仅仅能保障相干事务之间的“内部一致性”。另一种计划是引入核心授时节点(TSO),也就是 TiDB 应用的计划。TSO 计划要求所有事务必须从 TSO 获取工夫戳,实现绝对简略,但引入了更多的网络 RPC,而且 TSO 过于要害——短时间的不可用也是极为危险的。
HLC 的实现中有一些很 tricky 的中央,比方文档中提到的 Safe timestamp assignment for a read request。对于同一事务中的屡次 read,问题还要更简单,有趣味的读者能够看 Cockroach 团队的这篇博客 Living Without Atomic Clocks:
https://www.cockroachlabs.com…
事务提交
毫不惊奇,Yugabyte 的分布式事务同样是基于 2PC 的。他的做法靠近 Cockroach。事务提交过程中,他会在 DocDB 存储外面写入一些长期的记录(provisional records),包含以下三种类型:
- Primary provisional records:还未提交实现的数据,多了一个事务 ID,也表演锁的角色
- Transaction metadata:事务状态所在的 tablet ID。因为事务状态表很非凡,不是依照 hash key 分片的,所以须要在这里记录一下它的地位。
- Reverse Index:所有本事务中的 primary provisional records,便于复原应用
事务的状态信息保留在另一个 tablet 上,包含三种可能的状态:Pending、Committed 或 Aborted。事务从 Pending 状态开始,终结于 Committed 或 Aborted。
事务状态就是 Commit Point 的那个“开关”,当事务状态切换到 Commited 的一瞬间,就意味着事务的胜利提交。这是保障整个事务原子性的要害。
残缺的提交流程如下图所示:
另外,Yugabyte 文档中提到它除了 Snapshot Isolation 还反对 Serializable 隔离级别,然而仿佛没有看到他是如何躲避 Write Skew 问题的。从 Release Notes 看来这应该是 2.0 GA 中新减少的性能,等更多信息放出后再钻研吧!
竞品比照
以下表格摘自 Compare YugabyteDB to other databases:
https://docs.yugabyte.com/lat…
References
- https://www.yugabyte.com/
- https://docs.yugabyte.com/
- https://www.cockroachlabs.com…
近期热文举荐:
1.600+ 道 Java 面试题及答案整顿 (2021 最新版)
2. 终于靠开源我的项目弄到 IntelliJ IDEA 激活码了,真香!
3. 阿里 Mock 工具正式开源,干掉市面上所有 Mock 工具!
4.Spring Cloud 2020.0.0 正式公布,全新颠覆性版本!
5.《Java 开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞 + 转发哦!