一、引言:NewSQL 时代的三驾马车
自 Google 在 2012 年发表 Spanner 论文以来,分布式数据库领域掀起了一场深刻的变革。Spanner 向世界证明了一个长期被认为不可能的命题:在分布式系统中,我们可以同时获得水平扩展能力、强一致性和 SQL 语义。这打破了传统 NoSQL 系统”为了扩展性而牺牲一致性”的惯例,开启了所谓的 NewSQL 运动。
在 Spanner 的启发下,开源社区涌现出三个最具代表性的分布式数据库系统:TiDB、CockroachDB 和 YugabyteDB。它们都致力于在开源世界中重现 Spanner 的核心能力,但由于技术路线选择、设计权衡和生态定位的不同,三者各自走出了独特的道路。
TiDB 由 PingCAP 团队开发,选择了 MySQL 兼容路线,采用分层架构设计,通过中心化的 Placement Driver(PD)进行调度和时间戳分配。CockroachDB 则是 Cockroach Labs 的作品,选择了 PostgreSQL 兼容路线,采用完全对等的无中心架构,使用混合逻辑时钟(Hybrid Logical Clock,HLC)来避免中心化的时钟服务。YugabyteDB 由 Yugabyte 公司开发,同时提供 PostgreSQL 和 Cassandra 兼容的 API,采用了混合架构,在时间戳机制上与 Spanner 最为接近。
这三个系统的对比具有重要意义。首先,它们代表了从 Spanner 论文到工程实践的不同路径,展示了理论设计如何在实际约束下演化。其次,它们在生产环境中经过了大量验证,各自形成了稳定的用户群体和成熟的生态系统。最后,通过对比这三个系统,我们可以更深刻地理解分布式事务的核心挑战和不同的解决方案权衡。
本文作为第六部分「分布式事务」的收官之作,将从架构、事务模型、时间戳机制、性能特征、跨数据中心部署、生态兼容性等多个维度,对这三个系统进行深入对比分析,为技术选型提供参考依据。
二、架构对比:不同的设计哲学
TiDB:分层架构与角色分离
TiDB 采用了清晰的三层架构设计,实现了计算与存储分离的理念。最上层是 TiDB Server,作为无状态的 SQL 层,负责接收客户端连接、解析 SQL、生成执行计划、协调分布式事务。中间层是 Placement Driver(PD),作为整个集群的”大脑”,负责元数据管理、Region 调度、负载均衡,以及至关重要的时间戳分配(Timestamp Oracle,TSO)。最底层是 TiKV,基于 RocksDB 构建的分布式键值存储引擎,数据按照 Region(默认 96MB)进行分片,每个 Region 有多个副本组成一个 Raft Group。
这种分层设计带来了明确的职责划分。TiDB Server 可以水平扩展,因为它是无状态的,多个 TiDB Server 之间不需要协调。PD 作为有状态的中心节点,通常部署 3 到 5 个实例组成 Raft 集群保证高可用。TiKV 负责数据的持久化和复制,每个 Region 的三副本分布在不同的物理节点上。
TiDB 的架构优势在于角色清晰、易于理解和运维。SQL 层和存储层的分离使得两者可以独立扩展和优化。缺点是 PD 成为了潜在的瓶颈点,特别是 TSO 服务在高并发场景下可能成为性能瓶颈。为了缓解这个问题,TiDB 引入了 TSO 批量分配和本地缓存机制。
CockroachDB:完全对等的无中心设计
CockroachDB 采用了完全不同的设计哲学,它的每个节点都是对等的,既包含 SQL 层,也包含存储层,还负责事务协调。整个系统没有中心化的协调节点,所有的元数据通过 Gossip 协议在节点间传播。
数据按照 Range(默认 64MB)进行分片,每个 Range 的副本组成一个 Raft Group。与 TiDB 不同的是,CockroachDB 的 Range 可以包含多个表的数据,因为它使用的是连续的键空间。每个 Range 的 Leaseholder 负责处理该 Range 的读写请求,并协调本地事务。
在时间戳分配上,CockroachDB 不依赖中心化的时间戳服务,而是使用 HLC。每个节点维护自己的 HLC,通过 NTP 保持物理时钟同步,逻辑时钟部分则在节点间通信时进行同步。这种设计避免了中心化服务的瓶颈,但引入了”不确定性窗口”(Uncertainty Window)的概念来处理时钟偏移。
CockroachDB 的架构优势在于真正的去中心化,没有单点瓶颈,任何节点都可以处理任何请求。系统的弹性更好,节点的加入和离开对整体影响较小。缺点是架构复杂度较高,所有节点都需要维护完整的功能栈,资源利用率可能不如角色分离的架构。
YugabyteDB:混合架构与双 API 支持
YugabyteDB 采用了介于 TiDB 和 CockroachDB 之间的混合架构。上层是 YB-TServer,每个 TServer 节点包含查询层和存储层。查询层支持两种 API:YSQL(PostgreSQL 兼容)和 YCQL(Cassandra 兼容)。存储层使用 DocDB,这是一个基于 RocksDB 构建的文档存储引擎,支持文档数据模型和时间序列数据。
YB-Master 是控制平面组件,负责元数据管理、表的创建和删除、Tablet 分片的分配和负载均衡。与 TiDB 的 PD 不同,YB-Master 不负责时间戳分配。YugabyteDB 使用混合时间(Hybrid Time),这是一种结合物理时钟和逻辑时钟的机制,类似于 Spanner 的 TrueTime,但不依赖特殊硬件。
数据按照 Tablet 进行分片,每个 Tablet 对应一个 Raft Group。YugabyteDB 支持两种分片策略:Hash 分片(类似一致性哈希)和 Range 分片(按键范围分片)。用户可以根据访问模式选择合适的分片策略。
YugabyteDB 的架构优势在于灵活性,支持多种 API 和数据模型,可以满足不同的应用场景。混合架构在保持一定程度的角色分离的同时,避免了中心化的瓶颈。缺点是双 API 支持增加了维护成本,YSQL 和 YCQL 的一致性模型略有差异,需要用户理解其差异。
与 Spanner 的关系
作为这三个系统的精神源头,Spanner 的架构更加复杂和完整。Spanner 有明确的层次划分:Spanserver 负责数据存储和 Paxos 复制,Placement Driver 负责数据在 Spanserver 之间的移动,Location Proxy 负责客户端定位数据。最重要的是,Spanner 依赖 TrueTime API,通过 GPS 和原子钟提供全局时间界限。
TiDB、CockroachDB 和 YugabyteDB 都无法使用类似 TrueTime 的硬件支持(这在开源软件中不现实),因此各自设计了不同的时间戳机制。TiDB 选择了中心化 TSO,用单点换取全局严格递增的时间戳。CockroachDB 选择了 HLC,用不确定性窗口换取去中心化。YugabyteDB 选择了 Hybrid Time,在假设时钟偏移有界的前提下提供类似 TrueTime 的语义。
三、事务模型对比:从理论到实践
TiDB:Percolator 模型的工程实现
TiDB 的事务模型深受 Google Percolator 论文的影响。Percolator 是建立在 BigTable 之上的分布式事务系统,使用两阶段提交(Two-Phase Commit,2PC)和多版本并发控制(Multi-Version Concurrency Control,MVCC)实现快照隔离(Snapshot Isolation,SI)级别的事务。
TiDB 最初只支持乐观事务。在乐观事务模型中,事务在执行过程中不加锁,所有的写操作都缓存在本地,直到提交时才进行冲突检测。如果发现冲突(即读集和写集与其他已提交事务有交集),则事务失败回滚。乐观事务适合冲突较少的场景,可以减少锁等待时间,提高并发性能。
但乐观事务的缺点也很明显。在高冲突场景下,大量事务会在提交阶段失败,导致重试风暴。为了解决这个问题,TiDB
在 3.0 版本引入了悲观事务模型。在悲观事务中,当执行
SELECT ... FOR UPDATE 或
UPDATE/DELETE 语句时,TiDB
会立即对相关行加锁,阻止其他事务修改。这样可以在事务执行过程中尽早发现冲突,避免在提交阶段失败。
TiDB 的事务隔离级别默认是 Repeatable Read,但实际上提供的是快照隔离。快照隔离保证事务看到的是一个一致的快照,不会出现脏读、不可重复读和部分幻读。但快照隔离不能防止写偏斜(Write Skew)异常,这是与 Serializable 隔离级别的主要区别。
在实现层面,TiDB 的每个写操作会写入多个版本的列:Data 列存储实际数据,Lock 列存储锁信息,Write 列存储提交信息。事务提交时,首先从 PD 获取一个 start_ts,然后在执行过程中读取 start_ts 时刻的快照。提交时再获取一个 commit_ts,通过 2PC 协议将 commit_ts 写入所有涉及的 Region。如果任何 Region 返回冲突,整个事务回滚。
CockroachDB:基于 HLC 的可序列化事务
CockroachDB 在事务模型上最大的特点是默认提供 Serializable 隔离级别,这是 SQL 标准定义的最高隔离级别。可序列化事务保证并发事务的执行结果等价于某个串行执行顺序,完全避免了所有异常现象,包括写偏斜。
为了实现可序列化,CockroachDB 使用了序列化快照隔离(Serializable Snapshot Isolation,SSI)算法。SSI 基于快照隔离,但额外跟踪读写依赖关系,检测可能导致非序列化行为的危险结构(Dangerous Structure)。如果检测到这种结构,事务会被中止并重试。
CockroachDB 的时间戳来自 HLC。每个节点维护一个 HLC,包含物理部分和逻辑部分。物理部分来自本地系统时钟,逻辑部分用于在物理时钟相同时提供全序。当节点间通信时,HLC 会进行同步,确保因果关系得到保持。
一个关键的概念是”不确定性窗口”。由于不同节点的时钟可能存在偏移(假设最大偏移为 max_offset,默认 500ms),当一个事务以时间戳 t 读取数据时,如果发现某个版本的时间戳在 [t, t+max_offset] 区间内,这个版本对于当前事务来说是”不确定的”——它可能发生在事务开始之前(应该可见),也可能发生在之后(不应该可见)。此时事务会被推迟到一个更晚的时间戳重试,以消除不确定性。
CockroachDB 还使用了 Write Intent 机制来处理写冲突。当一个事务写入数据时,它首先写入一个 Intent,表示”我打算在这里写入数据”。如果另一个事务读取到 Intent,它会检查持有 Intent 的事务状态。如果该事务已提交,则读取提交后的数据;如果仍在进行中,则根据时间戳顺序决定是等待还是推进。这种机制使得 CockroachDB 可以在不持有长期锁的情况下协调并发事务。
YugabyteDB:灵活的隔离级别支持
YugabyteDB 在事务模型上追求灵活性,针对 YSQL 和 YCQL 两种 API 提供不同的事务语义。YSQL 事务基于 PostgreSQL 的事务模型,支持 Read Committed、Repeatable Read 和 Serializable 三种隔离级别。YCQL 事务则提供轻量级的 Conditional Update 和 Batch 操作。
对于 YSQL,YugabyteDB 使用了类似于 Spanner 的事务协议。每个事务从 Hybrid Time 获取一个开始时间戳,读取该时间戳的快照。YugabyteDB 实现了 MVCC,每个键维护多个带时间戳的版本。快照读取时,选择时间戳小于等于事务开始时间戳的最新版本。
在 Serializable 隔离级别下,YugabyteDB 使用了类似 SSI 的技术。它跟踪事务的读写集合,检测可能的冲突。与 CockroachDB 不同的是,YugabyteDB 的 Hybrid Time 假设时钟偏移在一个很小的界限内(通过 NTP 同步,误差通常小于几毫秒),因此不需要像 CockroachDB 那样大的不确定性窗口。
YugabyteDB 的提交协议使用了 2PC,但做了优化。对于单分片事务(所有操作都在同一个 Tablet 内),使用单分片事务优化,避免 2PC 的开销。对于跨分片事务,选择一个 Tablet 作为事务协调者,协调 2PC 过程。事务记录写入协调者 Tablet,包含事务状态和参与者列表。
在死锁处理上,YugabyteDB 使用了超时和死锁检测的组合。当检测到潜在的死锁时,会选择一个事务作为牺牲品回滚,打破死锁循环。超时机制确保即使死锁检测失败,事务也不会永久阻塞。
冲突检测与死锁处理
三个系统在冲突检测和死锁处理上各有特点。TiDB 的乐观事务在提交时进行冲突检测,悲观事务在加锁时检测。死锁通过超时机制处理,事务等待锁的时间超过阈值后会回滚。TiDB 还引入了死锁检测器,可以主动发现和打破死锁循环。
CockroachDB 的 Intent 机制使得冲突检测可以在事务执行过程中进行。当事务遇到其他事务的 Intent 时,会根据时间戳顺序决定行为。如果当前事务的时间戳较大(发生较晚),它会等待较早的事务完成。如果当前事务较早,它会推进(Push)较晚的事务,使其使用更大的时间戳或直接中止。死锁通过事务优先级和推进机制解决,最终会有一个事务被中止。
YugabyteDB 的冲突检测发生在事务执行过程中。当事务尝试获取锁时,如果锁已被其他事务持有,会进入等待队列。YugabyteDB 维护了一个等待图(Wait-for Graph),当检测到环时,选择一个事务回滚。这是经典的死锁检测算法,在分布式环境下需要额外的协调开销。
同一事务在三个系统中的执行轨迹
为了更直观地理解三个系统的事务模型差异,我们以一个简单但具有代表性的操作为例:从账户 A 向账户 B 转账 100 元(A 和 B 位于不同分片)。下面分别展示该事务在 TiDB(Percolator 模型)、CockroachDB(Spanner 风格)和 YugabyteDB(Hybrid Time + 2PC)中的执行时序。
sequenceDiagram
participant Client as 客户端
participant TiDB as TiDB Server
participant PD as PD (TSO)
participant TiKV_A as TiKV Region-A
participant TiKV_B as TiKV Region-B
Note over Client,TiKV_B: TiDB(Percolator 模型):转账 A→B 100元
Client->>TiDB: BEGIN; 读A; 读B; A-=100; B+=100; COMMIT
TiDB->>PD: 获取 start_ts
PD-->>TiDB: start_ts = 100
TiDB->>TiKV_A: 读取 A @ts=100
TiKV_A-->>TiDB: A = 500
TiDB->>TiKV_B: 读取 B @ts=100
TiKV_B-->>TiDB: B = 300
TiDB->>PD: 获取 commit_ts
PD-->>TiDB: commit_ts = 105
Note over TiDB: 2PC Prewrite:A 为 Primary Key
TiDB->>TiKV_A: Prewrite A=400(Primary Lock)
TiKV_A-->>TiDB: OK
TiDB->>TiKV_B: Prewrite B=400(Secondary Lock → A)
TiKV_B-->>TiDB: OK
Note over TiDB: 2PC Commit
TiDB->>TiKV_A: Commit Primary A @ts=105
TiKV_A-->>TiDB: OK(事务已提交)
TiDB-->>Client: COMMIT 成功
TiDB->>TiKV_B: 异步 Commit Secondary B @ts=105
sequenceDiagram
participant Client as 客户端
participant GW as Gateway Node
participant Leaseholder_A as Leaseholder Range-A
participant Leaseholder_B as Leaseholder Range-B
participant Follower_A as Follower Range-A
participant Follower_B as Follower Range-B
Note over Client,Follower_B: CockroachDB(Spanner 风格 SSI):转账 A→B 100元
Client->>GW: BEGIN; 读A; 读B; A-=100; B+=100; COMMIT
Note over GW: 分配 HLC 时间戳(本地,无需中心服务)
GW->>Leaseholder_A: 读取 A @hlc_ts
Leaseholder_A-->>GW: A=500(检查不确定性窗口)
GW->>Leaseholder_B: 读取 B @hlc_ts
Leaseholder_B-->>GW: B=300
Note over GW: 并行写入 Write Intents
GW->>Leaseholder_A: Write Intent A=400
GW->>Leaseholder_B: Write Intent B=400
Leaseholder_A-->>GW: Intent OK
Leaseholder_B-->>GW: Intent OK
Note over GW: Parallel Commit(1PC 优化)
GW->>Leaseholder_A: EndTxn(Staging)+ Raft 复制
Leaseholder_A->>Follower_A: Raft Append
Follower_A-->>Leaseholder_A: ACK
Leaseholder_A-->>GW: Txn Staged
GW-->>Client: COMMIT 成功(无需等待 Resolve Intent)
Note over Leaseholder_A,Leaseholder_B: 异步 Resolve Intents
sequenceDiagram
participant Client as 客户端
participant YSQL as YB-TServer (YSQL)
participant Tablet_A as Tablet-A Leader
participant Tablet_B as Tablet-B Leader
participant Follower_A2 as Tablet-A Follower
participant Follower_B2 as Tablet-B Follower
Note over Client,Follower_B2: YugabyteDB(Hybrid Time + 2PC):转账 A→B 100元
Client->>YSQL: BEGIN; 读A; 读B; A-=100; B+=100; COMMIT
Note over YSQL: 从本地 Hybrid Time 获取 start_ht
YSQL->>Tablet_A: 读取 A @start_ht
Tablet_A-->>YSQL: A=500
YSQL->>Tablet_B: 读取 B @start_ht
Tablet_B-->>YSQL: B=300
Note over YSQL: 选择 Tablet_A 为事务协调者
YSQL->>Tablet_A: 创建事务记录(status=PENDING)
Tablet_A-->>YSQL: 事务 ID 分配
Note over YSQL: 2PC Prepare 阶段
YSQL->>Tablet_A: 写入 A=400 + Raft 复制
Tablet_A->>Follower_A2: Raft Append
Follower_A2-->>Tablet_A: ACK
Tablet_A-->>YSQL: Prepare OK
YSQL->>Tablet_B: 写入 B=400 + Raft 复制
Tablet_B->>Follower_B2: Raft Append
Follower_B2-->>Tablet_B: ACK
Tablet_B-->>YSQL: Prepare OK
Note over YSQL: 2PC Commit 阶段
YSQL->>Tablet_A: 更新事务状态 → COMMITTED
Tablet_A-->>YSQL: OK
YSQL-->>Client: COMMIT 成功
上述三组时序图展示了同一笔转账事务在三个系统中截然不同的执行路径。TiDB 依赖中心化 TSO 获取全局有序的时间戳,通过 Percolator 的 Primary/Secondary Lock 机制实现原子提交;CockroachDB 利用本地 HLC 避免中心服务调用,通过 Write Intent 和 Parallel Commit 优化减少延迟;YugabyteDB 则通过本地 Hybrid Time 和标准 2PC 流程实现分布式事务。三者在时间戳获取、锁机制和提交协议上的差异,直接决定了其延迟特征和冲突处理策略。
高竞争场景下的行为差异
当多个事务并发操作同一行数据时,三个系统的表现差异更加显著:
TiDB(悲观事务模式):事务在执行 UPDATE 时立即对行加锁,后续事务阻塞等待锁释放。锁等待超时(默认 50 秒)后事务回滚。在高竞争场景下,锁排队导致事务延迟线性增长。乐观事务模式下则在提交阶段才检测冲突,高竞争时会出现大量提交失败和重试风暴。
CockroachDB:事务写入 Write Intent 后,后续事务读到 Intent 时通过 Push 机制协调。低优先级事务可能被高优先级事务推迟或中止。SSI 的 rw-antidependency 检测在高竞争下可能导致更高的中止率(10%-20%),但通过自动重试机制对应用透明。
YugabyteDB:行级锁与等待队列结合。高竞争时等待图检测算法确保不会出现死锁,但跨分片的等待图构建需要额外的网络通信,增加了检测延迟。
四、时间戳与一致性:时间的艺术
TiDB:中心化 TSO 的权衡
TiDB 的时间戳方案最为直接:使用 PD 作为中心化的时间戳分配服务(TSO)。每个事务开始和提交时都需要从 PD 获取时间戳。PD 维护一个单调递增的计数器,确保分配的时间戳全局唯一且严格递增。
这种方案的优点是简单可靠。时间戳的全局顺序保证了事务的因果关系得到正确维护。不存在时钟偏移带来的不确定性,事务语义清晰易懂。实现上也相对简单,不需要复杂的时钟同步协议。
缺点同样明显。PD 的 TSO 服务成为了潜在的性能瓶颈和单点故障。虽然 PD 本身是一个 Raft 集群,具有高可用性,但 TSO 服务只能由 Leader 节点提供,无法水平扩展。在高并发场景下,TSO 的吞吐量可能成为整个系统的上限。
为了缓解这个问题,TiDB 做了多项优化。首先是批量分配,TiDB Server 一次性从 PD 获取一批时间戳,缓存在本地使用,减少 RPC 次数。其次是本地时间戳分配,对于某些类型的读操作,可以使用本地时钟生成时间戳,避免访问 PD。第三是 TSO 异步预取,在后台预先获取时间戳,减少前台延迟。
在跨数据中心部署时,TSO 的延迟问题会被放大。如果 TiDB Server 和 PD 不在同一个数据中心,获取时间戳的延迟可能达到几十甚至上百毫秒,严重影响事务性能。为此,TiDB 引入了 Local TSO 机制,允许在每个数据中心部署独立的 TSO 服务,生成局部唯一的时间戳。跨数据中心事务需要使用 Global TSO,单数据中心事务可以使用 Local TSO,从而降低延迟。
CockroachDB:HLC 与不确定性窗口
CockroachDB 的 HLC 机制避免了中心化的时间戳服务,但引入了新的复杂性。HLC 由两部分组成:物理时钟 pt(physical time)和逻辑时钟 l(logical)。HLC 的值表示为 (pt, l)。当事件发生时,节点会取当前物理时钟和已知最大 HLC 的较大者作为新的 pt,如果 pt 相同则递增 l。
当节点间通信时,HLC 会进行同步。发送方在消息中包含自己的 HLC,接收方更新自己的 HLC 为 max(本地 HLC, 消息中的 HLC)。这确保了因果关系的保持:如果事件 A happens-before 事件 B,则 HLC(A) < HLC(B)。
但 HLC 不能保证物理时间顺序。如果两个事件在不同节点上发生,没有因果关系,它们的 HLC 顺序可能与实际物理时间顺序相反。这是因为不同节点的物理时钟可能存在偏移。CockroachDB 假设时钟偏移有一个上界 max_offset(默认 500ms),并通过 NTP 保持时钟同步。
不确定性窗口就是为了处理这个问题。当事务以时间戳 t 读取数据时,如果发现某个版本的时间戳 v 满足 t < v < t + max_offset,这个版本是”不确定的”。因为 v 可能是由于时钟偏移导致的,实际发生时间可能早于 t。此时事务必须推迟到 v 或更晚的时间戳重试。
不确定性窗口带来了性能开销。在跨数据中心环境下,时钟偏移可能更大,不确定性窗口也更大,导致更多的事务重启。CockroachDB 引入了”确定性边界”(Certainty Bound)优化,跟踪节点间最近一次通信的时间,缩小不确定性窗口的范围。
YugabyteDB:Hybrid Time 的精确控制
YugabyteDB 的 Hybrid Time 机制最接近 Spanner 的 TrueTime。它同样由物理时间和逻辑时间两部分组成,但使用方式与 HLC 略有不同。Hybrid Time 的物理部分是微秒级的时间戳,逻辑部分是一个计数器,用于在同一微秒内区分多个事件。
YugabyteDB 对时钟同步的要求比 CockroachDB 更严格。它假设通过 NTP 可以将时钟偏移控制在几毫秒以内(通常是 1-5ms)。在这个假设下,Hybrid Time 可以提供类似 TrueTime 的保证,而不需要 GPS 或原子钟硬件。
每个事务从 Hybrid Time 获取一个开始时间戳,这个时间戳保证大于之前所有已提交事务的提交时间戳。在读取数据时,选择时间戳小于等于开始时间戳的最新版本。在提交时,选择一个提交时间戳,确保它大于事务的开始时间戳和所有读取的数据版本的时间戳。
与 CockroachDB 不同,YugabyteDB 不使用不确定性窗口机制。相反,它依赖于严格的时钟同步和时间戳选择算法来保证正确性。如果时钟偏移超过假设的界限,可能会出现正确性问题,因此 YugabyteDB 对运维环境的要求更高,需要确保 NTP 配置正确且网络延迟稳定。
YugabyteDB 还支持混合云和跨数据中心部署。在这种场景下,它允许为不同的数据中心配置不同的时钟误差界限,并在路由查询时考虑这些因素。例如,对于延迟敏感的查询,可以优先路由到本地数据中心,使用局部快照读取。
与 Spanner TrueTime 的对比
Spanner 的 TrueTime 是一个时间 API,返回一个时间区间 [earliest, latest],保证真实时间在这个区间内。TrueTime 通过 GPS 和原子钟实现,误差界限通常在几毫秒以内。Spanner 的事务协议利用 TrueTime 的保证,在提交时等待一个安全边界(commit wait),确保事务的提交时间戳已经成为”过去”,从而保证外部一致性(External Consistency)。
外部一致性是比线性一致性更强的保证。它不仅保证单个操作的原子性和顺序,还保证事务级别的因果关系。如果事务 T1 提交后,事务 T2 开始,则 T2 一定能看到 T1 的结果。这对于跨系统的一致性至关重要。
TiDB、CockroachDB 和 YugabyteDB 都无法完全实现 TrueTime 的语义,因为它们缺乏硬件支持。TiDB 的 TSO 可以提供类似的保证,但需要中心化服务。CockroachDB 通过不确定性窗口和重启机制部分弥补时钟不确定性,但在极端情况下可能违反外部一致性。YugabyteDB 通过严格的时钟同步要求尽可能接近 TrueTime,但仍然依赖于 NTP 的可靠性。
五、性能特征分析:理论与实践的距离
基准测试方法论
评估分布式数据库的性能是一个复杂的问题。标准基准测试如 TPC-C、Sysbench 和 YCSB 提供了可对比的指标,但它们往往无法完全反映真实场景的复杂性。TPC-C 模拟 OLTP 工作负载,包含多种事务类型和复杂的业务逻辑。Sysbench 提供了一系列简化的测试场景,如点查询、范围查询、更新等。YCSB 最初为 NoSQL 系统设计,提供了不同的读写比例和访问模式。
在解读性能数据时需要注意几个因素。首先是硬件配置,不同的 CPU、内存、存储和网络配置会显著影响结果。其次是部署模式,单数据中心、同城多中心、跨地域部署的性能特征完全不同。第三是工作负载特征,高冲突与低冲突、读多写少与写多读少、短事务与长事务,都会导致不同的性能表现。第四是系统调优,默认配置往往不是最优的,针对特定场景的调优可能带来数倍的性能提升。
TiDB 的性能特点
TiDB 在 OLTP 场景下表现出以下特征。对于点查询和简单事务,性能主要受 TSO 获取延迟影响。在单数据中心部署中,TSO 延迟通常在 1-2ms,这成为事务延迟的基线。通过批量获取时间戳和异步预取,可以将这个开销摊薄。
在读多写少的场景下,TiDB 可以利用 Follower Read 功能,将读请求分散到 Raft Follower 节点,降低 Leader 节点的压力。Follower Read 提供的是稍微滞后的快照(通常几百毫秒),适合对实时性要求不高的查询。对于分析型查询,TiDB 提供了 TiFlash 列存引擎,可以将热数据同步到列存,大幅提升分析性能。
在高并发写入场景下,热点问题是 TiDB 面临的主要挑战。如果大量写入集中在少数几个 Region,这些 Region 的 Leader 会成为瓶颈。TiDB 引入了多种热点优化机制,包括自动分裂热点 Region、打散小表、随机化自增 ID 等。但在某些场景下(如秒杀、抢购),热点问题仍然难以完全避免。
根据 PingCAP 官方发布的测试数据,在 TPC-C 测试中,TiDB 5.0 使用三节点部署(每节点 16 核 64GB),可以达到约 1.2 万 tpmC。在 Sysbench 的 OLTP 测试中,点查询 QPS 可以达到数十万级别,但事务型负载受 TSO 影响较大。
CockroachDB 的性能特点
CockroachDB 的默认 Serializable 隔离级别提供了最强的一致性保证,但也带来了性能开销。在高冲突场景下,SSI 的冲突检测可能导致较高的事务中止率。为了缓解这个问题,CockroachDB 提供了 Read Committed 隔离级别选项(在较新版本中),牺牲一部分一致性换取性能。
CockroachDB 的无中心架构在某些场景下带来优势。由于没有中心化的 TSO 服务,获取时间戳的开销为零。在低冲突、分布式负载的场景下,这种架构可以充分利用集群的并行能力。但在高冲突场景下,HLC 的不确定性窗口可能导致频繁的事务重启,抵消了时间戳优势。
不确定性窗口的大小直接影响性能。在单数据中心部署中,时钟偏移通常较小(几毫秒),不确定性窗口的影响有限。但在跨数据中心部署中,时钟偏移可能达到几十毫秒,不确定性窗口也相应增大,导致更多的事务重启和更高的延迟。
根据 Cockroach Labs 官方数据,在 TPC-C 测试中,CockroachDB 20.2 版本使用三节点部署,可以达到约 1.4 万 tpmC。在 YCSB 测试中,读取密集型负载(Read-Heavy)表现较好,但写入密集型负载受 Raft 复制延迟影响。
YugabyteDB 的性能特点
YugabyteDB 的双 API 支持带来了灵活性,但性能特征在不同 API 下有所差异。YSQL 提供完整的事务支持,性能类似于传统的 PostgreSQL,但需要额外的分布式协调开销。YCQL 提供的是轻量级事务语义,性能更接近 Cassandra,适合对一致性要求不那么严格的场景。
YugabyteDB 的 Hybrid Time 机制在理论上比 HLC 更高效,因为它避免了不确定性窗口带来的重启开销。但这个优势的前提是时钟同步良好。如果 NTP 配置不当或网络抖动导致时钟偏移超过假设界限,可能出现正确性问题。因此 YugabyteDB 对运维质量的要求较高。
在单分片事务优化方面,YugabyteDB 做了特别的优化。如果事务的所有操作都在同一个 Tablet 内,可以避免 2PC 的开销,性能接近单机数据库。这对于使用地理分区(Geo-Partitioning)的应用特别有利,可以将相关数据放在同一个 Tablet,大部分事务变成单分片事务。
根据 Yugabyte 官方数据,在 TPC-C 测试中,YugabyteDB 2.8 版本使用三节点部署,可以达到约 1.5 万 tpmC。在 YCSB 测试中,YCQL API 的性能显著优于 YSQL API,因为它避免了完整的事务协议开销。
跨数据中心性能对比
在跨数据中心部署中,网络延迟成为主导因素。三个系统都需要通过 Raft 协议将数据复制到多个副本,这要求至少一次跨数据中心的往返通信。在三数据中心部署中(每个中心一个副本),写入延迟至少是两个数据中心之间的单程延迟(因为 Raft 需要多数派确认)。
TiDB 在跨数据中心场景下的额外开销来自 TSO。如果 TiDB Server 和 PD Leader 不在同一个数据中心,每个事务需要额外两次跨数据中心往返(获取 start_ts 和 commit_ts)。Local TSO 机制可以缓解这个问题,但只适用于单数据中心事务。
CockroachDB 没有中心化的时间戳服务,但不确定性窗口在跨数据中心场景下会显著增大。如果两个数据中心之间的延迟是 50ms,时钟偏移可能达到数十毫秒,不确定性窗口也相应增大,导致更高的事务重启率。
YugabyteDB 在跨数据中心场景下的表现取决于时钟同步质量。如果能够保持良好的时钟同步,Hybrid Time 可以避免不确定性窗口的开销。但在跨洲部署等高延迟场景下,保持严格的时钟同步是一个挑战。
所有三个系统都支持 Follower Read 或 Stale Read,允许从本地副本读取略微滞后的数据,避免跨数据中心的往返。这对于读多写少且能容忍一定延迟的应用非常有价值。
六、跨数据中心部署:从单机房到全球分布
多区域部署模式
现代分布式数据库的一个核心能力是支持跨数据中心部署,提供高可用性和灾难恢复能力。三个系统都支持多种部署模式,从同城多中心到跨地域甚至跨洲部署。
最基本的模式是三数据中心部署,每个数据中心放置一个副本,组成 Raft 或 Paxos 集群。这种模式可以容忍任意一个数据中心的故障,继续提供服务。写入性能取决于数据中心之间的延迟,通常在几毫秒到几十毫秒之间。
更复杂的模式是 5 副本或更多副本部署,分布在多个地理位置。例如 5 副本可以分布在 3 个数据中心,某些中心有 2 个副本。这提供了更高的可用性和读取性能(更多副本可以服务读请求),但写入性能可能下降(需要更多确认)。
地理分区(Geo-Partitioning)是一种高级部署模式。将不同的数据分区放在不同的地理位置,每个分区的副本靠近主要访问该数据的用户。例如,欧洲用户的数据副本在欧洲数据中心,亚洲用户的数据副本在亚洲数据中心。这可以显著降低读取延迟,但跨区域事务仍然需要跨数据中心通信。
TiDB 的多中心方案
TiDB 通过 Placement Rules 机制支持灵活的副本放置策略。用户可以为不同的表、分区或 Region 指定副本数量、放置位置、角色(Leader/Follower)等。例如,可以指定某个表的 Leader 必须在数据中心 A,Follower 分布在数据中心 B 和 C。
PD 的放置调度器根据 Placement Rules 自动调度 Region 的位置。当检测到 Region 的副本分布不符合规则时,调度器会生成迁移操作,将副本移动到合适的位置。这个过程是在线进行的,不影响业务运行。
TiDB 支持 Follower Read,允许从 Follower 副本读取数据。这对于多地部署特别有用,可以将读请求路由到本地数据中心的 Follower,避免跨数据中心访问 Leader。Follower Read 提供的是稍微滞后的快照,滞后时间取决于 Raft 日志复制的延迟。
在跨数据中心部署中,TiDB 的 TSO 延迟是一个重要考虑因素。TiDB 4.0 引入的 Local TSO 功能允许在每个数据中心部署独立的 TSO 服务。对于单数据中心内的事务,使用 Local TSO,延迟低。对于跨数据中心事务,使用 Global TSO,延迟高但保证全局顺序。应用需要根据业务逻辑选择合适的 TSO 类型。
CockroachDB 的多区域特性
CockroachDB 通过 Zone Configs 和 Multi-Region SQL 特性支持跨数据中心部署。Zone Configs 允许为不同的数据库、表或分区指定副本数量、放置约束、租户亲和性等。例如,可以指定某个表的副本必须分布在三个特定的地理位置。
CockroachDB 21.1 引入的 Multi-Region SQL 提供了更高层次的抽象。用户可以将数据库标记为 multi-region,并为每个表指定 locality(REGIONAL、GLOBAL)。REGIONAL 表的数据绑定到特定区域,访问该区域的延迟低。GLOBAL 表的数据分布在所有区域,读取快但写入慢。
CockroachDB 的 Follower Read 称为 Follower Reads for Geo-Distributed Deployments。它允许读取操作访问本地的 Follower 副本,而不需要访问 Leaseholder。这通过指定 AS OF SYSTEM TIME 语法实现,读取一个历史快照。时间戳越旧,越有可能在本地 Follower 找到数据。
在处理时钟偏移上,CockroachDB 在多区域部署中面临更大挑战。跨洲部署的时钟偏移可能达到几十毫秒,不确定性窗口也相应增大。CockroachDB 使用确定性边界优化来缩小窗口,但在极端情况下仍可能出现较高的重启率。
YugabyteDB 的地理分布能力
YugabyteDB 通过 Tablespaces 和 Geo-Partitioning 支持跨数据中心部署。Tablespace 定义了副本的放置位置,可以为不同的表或分区创建不同的 Tablespace。Geo-Partitioning 允许根据数据的地理属性(如用户的国家)自动将数据分布到相应的区域。
YugabyteDB 的 Follower Read 称为 Consistent Reads from Followers。与 CockroachDB 类似,它允许读取历史快照,从本地 Follower 获取数据。YugabyteDB 保证读取的数据是一致的,即使有少量滞后。
在时钟同步上,YugabyteDB 对跨数据中心部署有较高要求。它依赖 NTP 或 PTP(Precision Time Protocol)来保持时钟同步。在跨洲部署中,网络延迟和抖动可能影响时钟同步质量,需要特别注意 NTP 配置和监控。
YugabyteDB 还支持 xCluster 异步复制,允许在不同的集群之间复制数据。这可以用于灾难恢复或跨大洲的低延迟读取。异步复制不保证实时一致性,但可以显著降低跨地域访问的延迟。
RPO 和 RTO 特征
RPO(Recovery Point Objective)和 RTO(Recovery Time Objective)是衡量灾难恢复能力的关键指标。RPO 表示可接受的数据丢失量,RTO 表示可接受的恢复时间。
对于使用 Raft 或 Paxos 复制的系统,如果多数派副本存活,RPO 理论上为零——不会丢失已确认提交的数据。但如果同时失去多数派副本(如同时失去两个数据中心),则可能丢失尚未复制到剩余副本的数据。
三个系统都通过 Raft 复制实现强一致性,因此在正常故障场景下(单个节点或数据中心故障)RPO 为零。RTO 取决于故障检测和恢复的速度。Raft 的选举过程通常在几秒内完成,之后系统可以继续服务。
在极端灾难场景下(如多数派副本同时失效),三个系统都可能需要手动干预来恢复服务。此时 RPO 和 RTO 取决于备份策略和恢复流程。定期备份到对象存储(如 S3)可以在极端情况下提供最后的保障。
七、生态与兼容性:开发者体验
TiDB:MySQL 协议的无缝对接
TiDB 最大的生态优势是对 MySQL 协议的兼容。这使得大量现有的 MySQL 应用可以几乎无需修改地迁移到 TiDB。TiDB 实现了 MySQL 5.7 和 8.0 的大部分语法和功能,包括 SQL 语句、数据类型、函数、视图、存储过程(部分支持)等。
大多数 MySQL 客户端驱动可以直接连接 TiDB,包括 JDBC、Python MySQL Connector、Go MySQL Driver 等。这意味着现有的应用代码、ORM 框架(如 Hibernate、Django ORM、GORM)、数据库工具(如 Navicat、MySQL Workbench)都可以无缝使用。
但兼容性不是 100%。TiDB 不支持外键约束(可以定义但不强制执行)、触发器、某些存储引擎特性。事务语义也有差异,TiDB 的快照隔离不完全等同于 MySQL 的 Repeatable Read。在迁移时需要仔细测试这些差异点。
TiDB 的工具链生态也相当成熟。TiDB Lightning 用于大规模数据导入,可以从 MySQL dump 或 CSV 快速加载数据。TiDB Data Migration(DM)提供 MySQL 到 TiDB 的实时同步,支持分库分表合并。TiDB Binlog 和 TiCDC 提供 TiDB 的变更数据捕获(CDC),可以将数据同步到下游系统。
CockroachDB:PostgreSQL 兼容的选择
CockroachDB 选择了 PostgreSQL 兼容路线,这是另一个极为流行的开源数据库。PostgreSQL 以其丰富的特性、严格的标准遵循和活跃的社区著称。CockroachDB 实现了 PostgreSQL 的线路协议,可以使用 PostgreSQL 客户端驱动连接。
CockroachDB 支持 PostgreSQL 的大部分 SQL 语法,包括 CTE(Common Table Expressions)、窗口函数、JSON/JSONB 类型等。许多 PostgreSQL 的 ORM 和工具可以与 CockroachDB 配合使用,包括 SQLAlchemy、TypeORM、Prisma、pg_dump 等。
但同样存在兼容性差异。CockroachDB 不支持 PostgreSQL 的某些高级特性,如 PostGIS 地理扩展、全文搜索、某些数组操作。序列(SEQUENCE)的行为也有差异,CockroachDB 的序列不保证严格连续,可能出现间隙。
CockroachDB 的工具链包括 IMPORT 命令用于批量数据导入,支持 CSV、PostgreSQL dump 等格式。Changefeeds 功能提供 CDC 能力,可以将变更事件发送到 Kafka 或 Webhook。CockroachDB Cloud 提供托管服务,简化部署和运维。
YugabyteDB:双 API 的灵活性
YugabyteDB 的独特之处在于同时支持两种 API:YSQL(PostgreSQL 兼容)和 YCQL(Cassandra 兼容)。这使得它可以服务于不同的应用场景和迁移路径。
YSQL 基于 PostgreSQL 11 代码库,兼容性很高。许多 PostgreSQL 的扩展和工具可以直接使用。YSQL 提供完整的事务支持和 SQL 功能,适合需要强一致性和复杂查询的 OLTP 应用。
YCQL 兼容 Cassandra 的 CQL(Cassandra Query Language),使用类似的表模型和查询语法。YCQL 提供轻量级事务和灵活的数据模型,适合从 Cassandra 迁移的应用或需要 wide-column 数据模型的场景。
双 API 的好处是灵活性,可以在同一个集群中混合使用。例如,核心业务使用 YSQL 保证强一致性,监控日志使用 YCQL 提高吞吐量。缺点是增加了复杂性,两种 API 的一致性模型和功能特性不完全相同,需要开发者理解其差异。
YugabyteDB 的工具链包括 yugabyted(单节点开发模式)、yb-admin(集群管理)、ysql_dump/ysql_dumpall(数据导出)等。它也提供 Yugabyte Cloud 托管服务,支持多云部署。
迁移成本与学习曲线
从单机数据库迁移到分布式数据库是一个复杂的过程,不仅涉及数据的物理迁移,还包括应用逻辑的调整、性能调优、运维流程的重建等。
TiDB 的 MySQL 兼容性大大降低了迁移成本。许多应用可以通过简单的配置更改连接字符串即可切换到 TiDB。但仍需要注意事务语义的差异,特别是在高冲突场景下,可能需要将乐观事务改为悲观事务,或者调整业务逻辑减少冲突。
CockroachDB 的迁移相对复杂。虽然它兼容 PostgreSQL,但 Serializable 隔离级别可能导致更多的事务重试。应用需要正确处理重试逻辑,这在单机数据库中往往不是问题。CockroachDB 推荐使用自动重试的驱动或显式实现重试逻辑。
YugabyteDB 的迁移路径取决于选择的 API。从 PostgreSQL 迁移到 YSQL 相对平滑,从 Cassandra 迁移到 YCQL 也较为直接。但如果想利用双 API 能力,需要设计合理的数据分层和访问模式。
学习曲线方面,TiDB 对熟悉 MySQL 的开发者最友好,CockroachDB 对 PostgreSQL 用户友好,YugabyteDB 则需要学习两种 API 的差异。三个系统都需要学习分布式数据库特有的概念,如数据分片、副本放置、跨数据中心事务等。
八、选型建议:找到适合的工具
量化对比记分卡
下表从七个关键维度对三个系统进行量化评估(5 分制,5 分为最优):
| 维度 | TiDB | CockroachDB | YugabyteDB | 评估说明 |
|---|---|---|---|---|
| 写入延迟(单 DC) | 4 | 5 | 4.5 | CockroachDB 无需 TSO 调用;TiDB 受 TSO RTT 影响 |
| 写入延迟(跨 DC) | 3 | 3.5 | 4 | TiDB 需跨 DC 访问 TSO;CRDB 不确定性窗口增大 |
| 高竞争吞吐量 | 4 | 3 | 3.5 | TiDB 悲观锁排队高效;CRDB SSI 中止率高 |
| 低竞争吞吐量 | 4.5 | 5 | 4.5 | 低冲突下三者均优异,CRDB 无中心瓶颈略胜 |
| 容错与恢复 | 4 | 5 | 4.5 | CRDB 全对等架构无单点;TiDB 的 PD 是潜在风险 |
| 跨地域分布 | 3.5 | 4.5 | 4.5 | CRDB/YDB 去中心化时钟更适合全球部署 |
| 生态成熟度 | 5 | 4 | 3.5 | TiDB MySQL 兼容生态最成熟,中文社区活跃 |
事务系统选型决策矩阵
以下决策流程图可帮助根据业务需求快速缩小选择范围:
flowchart TD
START["开始选型"] --> Q1{"是否需要<br/>跨地域部署?"}
Q1 -- "是" --> Q2{"竞争程度?"}
Q1 -- "否(单 DC)" --> Q3{"现有技术栈?"}
Q2 -- "高竞争<br/>(热点数据多)" --> R1["YugabyteDB<br/>Hybrid Time 避免不确定窗口<br/>地理分区减少跨域事务"]
Q2 -- "低竞争" --> Q4{"延迟要求?"}
Q4 -- "P99 < 50ms" --> R2["CockroachDB<br/>无中心瓶颈 + Follower Read"]
Q4 -- "可容忍较高延迟" --> R3["三者均可<br/>根据生态偏好选择"]
Q3 -- "MySQL 生态" --> Q5{"需要 HTAP?"}
Q3 -- "PostgreSQL 生态" --> Q6{"需要 Serializable?"}
Q3 -- "Cassandra 迁移" --> R4["YugabyteDB<br/>YCQL API 直接兼容"]
Q5 -- "是" --> R5["TiDB + TiFlash<br/>OLTP/OLAP 一体化"]
Q5 -- "否" --> R6["TiDB<br/>MySQL 兼容平滑迁移"]
Q6 -- "是" --> R7["CockroachDB<br/>默认 Serializable 隔离"]
Q6 -- "否" --> R8["CockroachDB 或 YugabyteDB<br/>均提供 PG 兼容"]
该决策矩阵从三个核心维度进行分流:部署拓扑(单 DC vs 跨地域)、竞争程度(高 vs 低)、以及技术栈亲和性(MySQL/PostgreSQL/Cassandra)。实际选型时还需结合团队运维能力、社区成熟度和长期演进方向综合判断。没有”最好”的系统,只有最适合特定场景的系统。
基于场景的推荐
选择 TiDB 的场景:
- 现有应用大量使用 MySQL,希望平滑迁移而不改变应用代码
- 团队对 MySQL 生态非常熟悉,希望复用运维经验和工具
- 需要 HTAP 能力,既有 OLTP 也有 OLAP 查询(通过 TiFlash)
- 可以接受中心化的 TSO 服务,或者主要在单数据中心内运行
- 需要成熟的中文社区和本地化支持(TiDB 的中国社区非常活跃)
选择 CockroachDB 的场景:
- 需要最强的一致性保证(Serializable 隔离级别)
- 希望完全去中心化的架构,避免任何单点
- 现有应用使用 PostgreSQL,希望利用其丰富的 SQL 特性
- 跨数据中心部署,但主要在相对较近的地理位置(如同洲不同城市)
- 希望使用云原生架构,方便在不同云平台间迁移
选择 YugabyteDB 的场景:
- 需要同时支持关系型和宽列数据模型
- 从 Cassandra 迁移但需要事务支持
- 对时钟同步有信心,能够保持严格的 NTP 配置
- 需要灵活的地理分区能力,将数据绑定到特定区域
- 希望在多云环境下部署,利用不同云厂商的优势
各系统的甜蜜点与短板
TiDB 的甜蜜点:
- MySQL 生态兼容性最强
- HTAP 能力通过 TiFlash 得到增强
- 中文文档和社区支持丰富
- 工具链成熟,迁移和运维工具完善
TiDB 的短板:
- TSO 是潜在的性能瓶颈和单点(虽然有高可用保障)
- 跨数据中心事务的 TSO 延迟较高
- 悲观事务模式下的锁管理开销
- 热点问题在某些极端场景下仍然存在
CockroachDB 的甜蜜点:
- 完全对等的无中心架构,真正的云原生设计
- Serializable 隔离级别提供最强一致性
- 无需中心化时间戳服务,避免单点瓶颈
- 企业级特性丰富(多租户、审计、加密等)
CockroachDB 的短板:
- 不确定性窗口在跨数据中心场景下带来性能开销
- Serializable 隔离级别在高冲突场景下重试率高
- 相比 MySQL 生态,PostgreSQL 的商业应用相对较少
- 某些高级 PostgreSQL 特性尚未支持
YugabyteDB 的甜蜜点:
- 双 API 支持提供最大灵活性
- Hybrid Time 机制在理论上更高效
- 地理分区能力强,支持复杂的多区域部署
- 活跃的开发和快速的功能迭代
YugabyteDB 的短板:
- 对时钟同步的依赖较强,运维要求高
- 双 API 增加了学习和维护复杂度
- 社区相对较小,文档和最佳实践仍在积累
- YSQL 和 YCQL 的一致性模型差异需要注意
成本考虑
除了技术因素,成本也是选型的重要考虑。开源版本的使用是免费的,但需要自己运维,包括部署、监控、升级、故障处理等。商业版本和托管服务提供更多企业级特性和专业支持,但需要付费。
TiDB 提供企业版和 TiDB Cloud 托管服务。CockroachDB 有免费的 Core 版本、企业版和 CockroachDB Cloud。YugabyteDB 提供社区版、企业版和 Yugabyte Cloud。在评估总拥有成本(TCO)时,需要考虑软件许可费、云资源费用、人力成本、培训成本等。
一般来说,如果有成熟的运维团队和自建基础设施,使用开源版本成本较低。如果希望快速上线、减少运维负担,托管服务是更好的选择。对于关键业务,企业版的技术支持和 SLA 保证可能是值得的投资。
九、总结与展望
第六部分回顾
本文作为第六部分「分布式事务」的最后一篇,对 TiDB、CockroachDB 和 YugabyteDB 三个代表性的分布式数据库系统进行了全面对比。这三个系统都受 Google Spanner 的启发,但在架构设计、事务模型、时间戳机制等方面做出了不同的选择和权衡。
回顾整个第六部分,我们从分布式事务的基础理论出发,讨论了 ACID 特性在分布式环境下的挑战,深入分析了两阶段提交(2PC)、三阶段提交(3PC)等经典协议,探讨了乐观并发控制和悲观并发控制的优劣。我们研究了分布式快照隔离机制,理解了 MVCC 如何在保证一致性的同时提供高性能。最终,通过本文对三个实际系统的对比,我们看到了理论如何在工程中落地,以及不同的设计选择如何影响系统的性能和适用场景。
分布式事务是分布式系统中最复杂的问题之一。它要求在网络分区、节点故障、时钟偏移等各种异常情况下,仍然保证数据的一致性和事务的原子性。TiDB、CockroachDB 和 YugabyteDB 都通过精巧的设计和工程实现,在很大程度上解决了这个问题,为构建全球化、高可用的应用提供了坚实的数据基础。
技术演进趋势
分布式数据库领域仍在快速演进。几个值得关注的趋势包括:
多模型支持:单一的关系型模型可能无法满足所有需求。越来越多的系统开始支持多种数据模型,如文档、图、时序等。YugabyteDB 的双 API 支持是这个方向的探索。
Cloud-Native 架构:随着云计算的普及,数据库架构也在向云原生方向演进。存算分离、弹性伸缩、多租户隔离等成为标配。三个系统都提供了托管服务,简化云上部署。
HTAP 融合:OLTP 和 OLAP 的界限正在模糊。TiDB 的 TiFlash 是这方面的代表,通过行存和列存的混合,在同一个系统中支持事务处理和分析查询。
Serverless 数据库:按使用量付费、自动扩缩容、无需运维的 Serverless 数据库是未来的方向。CockroachDB Serverless 和 Yugabyte Serverless 都是这方面的尝试。
硬件加速:随着新型硬件的出现,如 RDMA 网络、持久化内存、DPU(数据处理单元),数据库架构也在相应调整。未来可能出现基于新型硬件的分布式数据库。
下一部分预告
第七部分「分布式存储系统剖析」将从不同的角度探讨分布式系统的存储问题。我们将从分布式日志系统开始,深入分析 Kafka 和 Pulsar 的架构设计和应用场景。
分布式日志是许多分布式系统的基础组件。Kafka 作为最流行的消息队列和流处理平台,已经成为事实上的标准。Pulsar 作为后起之秀,提供了多租户、地理复制、分层存储等创新特性。通过对比这两个系统,我们将理解分布式日志的核心挑战和不同的解决方案。
除了日志系统,第七部分还将涵盖对象存储、块存储、文件系统等不同类型的分布式存储,分析它们的架构特点、一致性模型、性能优化等。敬请期待!
参考文献
- Corbett, J. C., et al. (2012). Spanner: Google’s Globally-Distributed Database. OSDI.
- Daniel, A., et al. (2021). TiDB: A Raft-based HTAP Database. VLDB.
- Taft, R., et al. (2020). CockroachDB: The Resilient Geo-Distributed SQL Database. SIGMOD.
- Tyagi, K., et al. (2020). Building a Reliable SQL Layer on Distributed Key-Value Stores. IEEE Data Engineering Bulletin.
- Kulkarni, S. S., et al. (2013). Logical Physical Clocks and Consistent Snapshots in Globally Distributed Databases. Technical Report.
- PingCAP. (2023). TiDB Documentation. https://docs.pingcap.com/
- Cockroach Labs. (2023). CockroachDB Documentation. https://www.cockroachlabs.com/docs/
- Yugabyte. (2023). YugabyteDB Documentation. https://docs.yugabyte.com/
- Pavlo, A., Aslett, M. (2016). What’s Really New with NewSQL? SIGMOD Record.
- Bernstein, P. A., Hadzilacos, V., Goodman, N. (1987). Concurrency Control and Recovery in Database Systems. Addison-Wesley.
上一篇:分布式快照隔离 下一篇:分布式日志:Kafka 与 Pulsar
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【分布式系统实战】分布式事务不是你以为的那个 2PC
「用 2PC 就行了」——说这话的人大概没在生产环境里被 Coordinator 挂掉后全员阻塞的锁堵过三小时。2PC 的真实失败模式、Percolator 的精妙设计、Saga 与 TCC 的工程取舍,分布式事务远比教科书复杂。
【系统架构设计百科】数据库扩展:分库分表的工程实践与替代方案
当单表数据量突破千万行、查询延迟从毫秒级劣化到秒级时,分库分表往往是团队面临的第一个选项。本文从分片时机判断、三种分片策略的工程实现、跨分片查询的六种解法讲起,再拆解 Vitess、TiDB、CockroachDB 三套工业级方案的架构差异,回答一个核心问题:NewSQL 能否让我们彻底告别分库分表?
【分布式系统百科】混合逻辑时钟与 TrueTime:在物理和逻辑之间找到平衡
物理时钟对不齐,逻辑时钟丢物理信息,向量时钟太重。HLC 用物理时间 + 逻辑计数器找到了平衡。但 Google 选了另一条路:用原子钟和 GPS 把物理误差压到几毫秒。这篇文章从 HLC 的算法正确性证明、CockroachDB 源码实现、TrueTime 工程架构,一直讲到 AWS Clockbound 的开源方案——在物理和逻辑之间,每种选择都是一笔工程账。
【系统架构设计百科】Google 基础设施:Borg、Spanner 与全球化架构
Google 在 2003 年发表 GFS 论文时,整个行业还在用单机数据库处理 Web 请求。此后二十年间,Google 内部基础设施经历了多次代际演进,从 GFS 到 Colossus,从 MapReduce 到 Flume,从 Borg 到 Kubernetes,从 Bigtable 到 Spanner。这些系统…