想象你是一家正打算全国扩张的餐饮公司老板。巷口那家“独灶小馆”(单机数据库)已经装不下客流:一口灶、一位大厨,再多客人也只能排队,大厨一病,整店歇业。你听说了两种扩大规模的思路:CockroachDB 像“不垮食堂”——每家分店的店员都经过全能培训,共用一本“电子总台账”,任何一家倒下,其他分店立刻接管生意;YugabyteDB 像“伶鲸餐厅”——前厅服务生全部按著名餐饮学院(PostgreSQL)的标准培养,后厨则是统一备料的中央仓库,前厅只管点单,后厨只管出菜。选哪家加盟?要看你的客群讲什么“方言”(SQL 兼容)、要开几家店(多区域部署)、以及你最怕什么(丢数据还是迁移麻烦)。这篇文章就从这几张“试吃评分表”入手,带你看懂两家云原生分布式数据库的架构、兼容性与高可用策略,最终做出自己的选型决策。
对 AI 从业者而言,你的训练数据流水线、在线推理特征库迟早会面对“单点扛不住、故障丢数据”的瓶颈。读懂这两款代表作的架构权衡,就能在选型会上问出关键问题,为 AI 应用挑一个既高可用又可扩展的数据底座。
目录
可视化演示
对比CockroachDB对等架构与YugabyteDB分层架构、展示Range/Tablet分片与Raft复制机制、以及多区域全球部署策略,切换模式查看不同维度对比。
本节配有交互动效(进入视口后自动加载,约 3KB)。
架构对比:对等vs分层 CRDB对等单体:每节点兼具SQL与存储 YB分层架构:TServer存储与Master管理分离 不同架构影响扩展性与运维复杂度 CRDB: Peer-to-Peer | YB: Tiered 架构选择决定扩展路径与运维模式
架构演进:从独灶小馆到连锁集团
想象你家巷口有家“独灶小馆”:就一口灶、一位大厨、一个收银台。生意一好,排队两小时——性能到顶了;大厨一感冒,全店歇业——单点故障。这就是传统单机数据库的日常:CPU、内存、磁盘就是那口灶的“火力上限”,想扩容只能换更大的灶(纵向扩展),可灶台再大也有物理极限。
为了让更多客人进门,餐饮业先想到“厨师抄菜谱”:把菜谱复制给几个徒弟,客人多了可以去徒弟那桌吃同样的菜(主从复制、读写分离),但写菜谱仍只能师父来,徒弟只能应付读。后来又想到“分桌”(分库分表):把菜单按菜系切给不同厨师,可切得不好就有人忙死有人闲死,而且跨桌拼菜(跨库 JOIN)几乎做不了。
云原生分布式数据库走的是“连锁集团”路线:把数据自动切成许多小份(分片),散布在很多普通服务器(节点)上;哪台机器负载高,数据就自动搬走(自动均衡);哪台机器坏掉,副本自动顶上(故障自愈)。它不依赖一台“超级大厨”,而是用一群普通厨师组成永不歇业的团队。这也是它与“分库分表中间件”的本质区别:分片、复制、事务都是引擎内置的,对 SQL 透明。
所以连锁集团的目标不是把某一家店开得更大,而是让每个档口都足够快、足够稳,还能随时补位。理解了这条“短板公式”,你就明白分布式数据库真正追求的不是单机更快,而是让最慢的节点也永不掉链子。
- 认识 $N$(节点总数)$N$ 表示参与一份数据服务的节点数量,比如 3 副本集群中至少有 3 台机器同时开工。
- 理解 $t_k$(单个节点耗时)$t_k$ 是第 $k$ 个节点处理自己那份数据花费的时间。节点负载不同,$t_k$ 也各不相同,有的快有的慢。
- 取最大值 $\max$$\max_{k=1}^{N}$ 表示从全部 $N$ 个节点中选出耗时最大的那个——它就是整个系统此刻的瓶颈。
CockroachDB架构:全能的“不垮食堂”
Cockroach 这个名字就是“蟑螂”,寓意怎么都打不死。它的每家分店(节点)都是全能店员:点单、备料、掌勺样样在行。最关键的是,所有分店共用一本“电子总台账”——每种原料都按“编号 + 状态”记录(Key-Value 存储),任何店员查同一个编号,得到的记录都一致。
CockroachDB 用 Go 语言写成,所有数据——不管是表、索引还是分区——最终都落在一个统一的、按键排序的分布式 Key-Value 存储里。它以约 64MB 为单位把数据切成许多 Range,每个 Range 默认保存 3 份副本,副本之间用 Raft 共识协议同步:写入必须得到多数副本确认才提交。读取由每个 Range 的“租约持有者”(Leaseholder)负责,它相当于分店的值班店长。SQL 层则是“翻译官”:把 SELECT、JOIN 翻译成对 KV 的读写操作,再根据 Key 范围路由到正确的 Range。
全能店员 + 总台账 + 投票制,构成了“不垮食堂”的生存哲学:任何分店突然消失,其余分店一合计(选举新 Leader)就能继续营业,账目一分不少。正因如此,CockroachDB 在跨机房灾难场景下以“不丢数据”著称。
- 认识 $N$(副本总数)$N$ 指一个分片的数据被复制到了几个节点,默认是 3 副本,即 $N=3$。
- 计算半数 $\lfloor N/2 \rfloor$$\lfloor \cdot \rfloor$ 是向下取整,$3/2=1.5$ 取整后为 1,表示“不到一半”。
- 加一得到法定人数把半数加 1,得到严格超过一半的投票门槛,这是 Raft 判定写入成功的底线。
YugabyteDB架构:分工明确的“伶鲸餐厅”
“伶鲸餐厅”的聪明之处在于把前厅和后厨彻底分开:前厅服务生全部按一家著名餐饮学院(PostgreSQL)的教材培训,客人用熟悉的术语点单;后厨则有一套统一的“文档食谱”(DocDB),食材按文档式档案归档。前厅不懂后厨的仓库细节,后厨也不关心客人的口音。
YugabyteDB 用 C++ 编写,是典型的双层架构。上层是查询引擎:YSQL 直接基于 PostgreSQL 源码构建,提供 PG 的连线协议与大部分语法;另有 YCQL 提供 Cassandra 风格的宽表 API。下层是 DocDB 存储引擎:它在 RocksDB 之上扩展出文档模型,把一行数据按列组织成子文档。每个表按主键范围切成 tablet,每个 tablet 是一个独立的 Raft 小组,默认 3 副本。查询层负责 SQL 解析、优化与执行计划,存储层负责持久化、复制与分布式事务,两者通过 RPC 协作。
前厅专业(PG 语义原汁原味),后厨高效(文档存储善于压缩与扫描),各司其职——这正是 YugabyteDB“更懂 SQL”的结构根源:它不需要把每个 SQL 都翻译成 KV,而是让 PG 的成熟执行器直接跑在自己头上。
- 解析耗时 $T_{\text{解析}}$前厅服务生把客人的口语点单写成标准订单——数据库把 SQL 文本解析成内部语法树。
- 优化耗时 $T_{\text{优化}}$服务生判断是先上凉菜还是先上热菜——优化器决定走索引还是全表扫描,生成执行计划。
- 执行耗时 $T_{\text{执行}}$后厨真正把菜端出来——执行器按计划读写 DocDB,聚合、排序、返回结果。
SQL兼容:用顾客熟悉的方言点菜
客人来自天南海北:有的讲“川话”(MySQL 习惯),有的讲“粤语”(PostgreSQL 习惯)。“不垮食堂”选择在总台装一个“粤语翻译器”——它自己按 PG 的协议和语法接待,但内核是自研的;“伶鲸餐厅”则直接雇了一批 PG 学院毕业的服务生——内核就是 PG 本尊。
CockroachDB 的 SQL 层是自研的,它实现了 PostgreSQL 的连线协议(wire protocol)和大部分常用语法,用 Go 从零重写,兼容策略是“常用功能优先”,边缘特性(部分窗口函数、类型转换细节)取决于具体版本。YugabyteDB 的 YSQL 则把 PostgreSQL 源码“搬进”自己的查询层,继承了 PG 的解析器、优化器和执行器,因此 psql、pg_dump、JDBC/psycopg 驱动和常用扩展的迁移成本更低。但无论选哪家,从 MySQL 迁过来都要改写方言:自增主键改成 SERIAL/IDENTITY,反引号改成双引号,ON DUPLICATE KEY 改成 ON CONFLICT。
顾客点菜越顺畅,翻台率越高。选型前拿现有 SQL 跑一遍“点菜测试”,比看宣传册上印着“兼容 PostgreSQL”五个字有用得多——毕竟服务生会说粤语,不代表他会背粤语诗词。
- 分子 $S_{\text{支持}}$(支持的特性数)你的业务 SQL 里,目标数据库能正确执行的语法项数量,比如 UPSERT、JSONB、窗口函数。
- 分母 $S_{\text{目标}}$(目标方言特性总数)完整 PostgreSQL 方言包含的全部语法项,这是一个“全量菜谱”。
- 相除得到比例比值越接近 1,迁移越平滑;越小,意味着要改写的 SQL 越多、风险越高。
多区域部署:跨城连锁的就近供货
连锁要开到全国,顾客最烦“菜从外地送”。有两种玩法:加盟店各自为政(多集群异步复制,各城市数据不完全同步);直营中央调度(一个全球大集群,副本按城市就近摆放,负责拍板的“店长”(Leaseholder/Leader)被派到离客人最近的分店)。但“就近”有物理极限——光速也救不了几千公里的距离。
CockroachDB 把部署策略做成了可配置项:区域表(regional table)让副本固定在特定区域,全局表(global table)牺牲写延迟换取各区域读都快;还有存活目标(survivability goals),控制整个区域故障还是单个可用区故障时服务不中断。它的“就近读”靠把 Leaseholder 放到读数区域实现,并支持 follower reads——用可容忍的陈旧读换更低的延迟。YugabyteDB 类似:通过优先可用区(preferred zones)控制 tablet leader 的位置,并提供 xCluster 异步复制用于跨云多集群容灾。强一致写必须凑齐多数派,跨区域时每一笔写都绕不开物理距离。
跨城生意的本质是选址:把“拍板的人”(Leader/Leaseholder)放到客人身边,多数派才能最快凑齐;把副本放得太远,再快的服务器也救不了网络延迟。
- $d$(两地距离)客户端所在城市与数据所在城市之间的直线距离,比如北京到上海约 1200 公里。
- $c$(信号速度)光在光纤中的传播速度约每秒 20 万公里,不是真空中的 30 万,因为光纤折射会减速。
- 乘以 2(往返)请求要过去、确认要回来,一来一回就是两倍距离,所以是 $2d$。
选型决策:老板的加盟评分表
老板要加盟,得先列权重:口味正宗(SQL 兼容)占 40%,抗揍(一致性)占 30%,出餐快(延迟)占 20%,加盟费与培训(运维生态)占 10%。两家都试吃打分,加权求和就是最终答案。没有“哪家更好”,只有“哪家更适合你的客群”。
关键差异盘点。事务模型:CockroachDB 默认可串行化隔离(serializable),用混合逻辑时钟为全局事务排序,跨区域提交后往往还要多等一个时间戳推进的往返,因此跨区写更慢;YugabyteDB 默认快照隔离(snapshot isolation),语义贴近 PostgreSQL 的常用模式,跨区写没有额外的全局时钟等待,但也提供可串行化选项。一致性:两者都是 Raft 强一致多副本复制,没有“谁更一致”的本质差别,差别在于默认隔离级别带来的跨区写成本和 PG 语义匹配度。生态:YSQL 内核就是 PG,扩展、迁移工具链更宽;CockroachDB 运维简单,单二进制部署,托管云服务成熟,PostGIS、CDC 等能力也有完整方案。
把“别人说好”翻译成“我的场景打分高”,答案自然浮现:追求极端强一致的全局事务与高可用,优先看 CockroachDB;追求 PG 生态平滑迁移、默认事务语义贴近传统业务,优先看 YugabyteDB。评分表一列,剩下的就是执行。
- $x_i$(单项得分)对某项指标的打分,比如 SQL 兼容度打 8 分,运维省心度打 6 分。
- $w_i$(指标权重)这个指标对你业务的重要性,所有权重加起来等于 1,比如兼容 40%、一致性 30%。
- 求和 $\sum$逐项相乘后累加,得出一家数据库对你的综合适配分,分数高者胜出。
AI 应用场景
金融支付系统的两地三中心改造
阶段:在线数据供给(账务流水、特征存储)
解决的问题:传统 MySQL 主从复制在主数据中心故障时会丢失最后一批未同步的账务记录(RPO 为分钟级),且无法水平扩展。分布式数据库用 Raft 多数派提交,让故障切换时不再丢数据。
具体案例:某支付公司把账务核心从 MySQL 主从迁移到 CockroachDB 的三区域集群,Raft 保证跨机房多数派确认后才提交,单分片吞吐提升约 4 倍,RPO 从分钟级降到 0,支付链路在机房级故障下自动切换。
电商大促的弹性扩容与多活
阶段:在线交易与推荐特征实时写入
解决的问题:手工分库分表扩容要停服搬数据,大促流量波峰难以预测;而原生分布式数据库加节点即扩容,数据自动重新均衡,无需改应用代码。
具体案例:某跨境电商采用 YugabyteDB 承载订单与购物车,大促前横向扩充节点池,数据自动均衡;同时把 AI 推荐所需的用户点击流实时特征写入同一集群,在线推理直接读最新数据。
从自建 PostgreSQL 平滑迁移到云原生
阶段:应用数据库基础设施
解决的问题:单机 PostgreSQL 读多写少、存储遇到瓶颈,而自建分库分表改造复杂、风险高。YugabyteDB 因内核即 PG,支持 pg_dump 导出导入,SQL 几乎零改造完成水平扩展。
具体案例:某 AI 公司的用户行为分析服务原本跑在单机 PostgreSQL 上,日活增长后查询延迟飙升;迁移到 YugabyteDB 后,YSQL 直接复用现有驱动与 ORM,查询自动路由到各 tablet,存储与并发能力随节点数线性增长。
Python 演示
# -*- coding: utf-8 -*-"""mini_raft_compare.py: 模拟 Raft 多数派与分片热点, 辅助理解分布式选型"""import random def quorum(n): # Raft 法定多数: 超过一半才算数 return n // 2 + 1 def write_availability(replicas, fail_rate, trials=20000): # 随机故障下, 写入能拿到多数确认的概率 ok = 0 for _ in range(trials): alive = sum( 1 for _ in range(replicas) if random.random() > fail_rate ) if alive >= quorum(replicas): ok += 1 return ok / trials def shard_tail_latency(keys, shards): # 把 key 哈希到分片, 返回最热分片的负载占比 buckets = [0] * shards for k in keys: buckets[k % shards] += 1 total = len(keys) return max(buckets) / total def choose(weights, scores): # 加权评分: 输出各方案的加权总分 return { name: sum(w * s for w, s in zip(weights, sc)) for name, sc in scores.items() } def main(): random.seed(42) print("== Raft 写入可用性模拟 ==") for r in (3, 5): for f in (0.1, 0.3): print(f"replicas={r}, fail_rate={f}: " f"avail={write_availability(r, f):.4f}") print("== 分片热点模拟 (简单取模哈希) ==") keys = [random.randint(1, 20) for _ in range(10000)] for shards in (10, 50): hot = shard_tail_latency(keys, shards) print(f"shards={shards}, 最热分片负载占比={hot:.3f}") print("== 数据库选型加权评分 ==") weights = (0.4, 0.3, 0.2, 0.1) # 一致性, 生态, 性能, 成本 scores = { "CockroachDB": (9, 7, 8, 6), "YugabyteDB": (8, 9, 7, 7), } print(choose(weights, scores)) if __name__ == "__main__": main()
return n // 2 + 1计算 Raft 法定多数,3 副本时返回 2,5 副本时返回 3。alive >= quorum(replicas)存活副本数是否达到多数派,决定这次写入能不能提交。random.random() > fail_rate用均匀随机数模拟一台机器是否故障,fail_rate 越高越容易挂。buckets[k % shards] += 1模拟“取模哈希”路由:把 key 对分片数取余,映射到某个分片。max(buckets) / total最热分片承载的流量占比,占比越高说明倾斜越严重、短板越明显。sum(w * s for w, s in zip(weights, sc))加权求和:把一致性、生态、性能、成本四项得分分别乘权重后累加。random.seed(42)固定随机种子,让每次运行结果一致,便于复现实验结论。
常见误区
误区所谓云原生数据库,不就是把分库分表中间件内置到数据库里了吗?既然有了它,MyCat、ShardingSphere 这些中间件是不是该被淘汰了?
正解分库分表只是加在单机数据库外面的“路由层”,把一张表切成多份后,跨库 JOIN、全局事务、分布式一致性都被阉割了,还需要人工指定分片键。原生分布式数据库则让存储引擎从一开始就按“分片 + 共识”设计,分区对 SQL 完全透明,跨分片事务和自动再均衡是内在能力。就像把菜谱撕成十份分给十个厨师,和一本会自动重印的电子菜谱,是两种完全不同的东西。
为何常见:因为 MySQL 生态的分库分表中间件太普及,人们习惯用旧的思维框架去套新事物,以为分布式数据库只是中间件的“官方版”。
误区数据复制了三份,随便连哪台读都行,而且读到的一定是刚刚写入的最新值,否则还算什么强一致?
正解强一致读必须走 Raft 共识路径,从 Range 的 Leaseholder(或 Raft Leader)读;直接读普通 Follower 副本,可能拿到的是几毫秒甚至更早的陈旧数据,除非显式开启 follower reads 且应用能容忍短暂滞后。道理很简单:只有店长才知道最新菜价,普通店员可能还在看昨天打印的菜单。
为何常见:把“数据被复制了”等同于“所有副本线性一致”,忽略了读路径也要经过共识协议这一层。
误区YugabyteDB 的内核就是 PostgreSQL,所以现有 PG 应用可以零改动迁移;CockroachDB 也说兼容 PG,那肯定也差不多,随便迁。
正解YSQL 虽然基于 PG 源码,但分布式化会裁剪或改造一部分单机特性——部分函数、扩展、触发器行为、锁语义、序列并发行为都可能与原生 PG 不同,必须逐项验证。CockroachDB 是自研 SQL 层仿照 PG 协议,兼容以常用功能为主。迁移前一定要拿真实业务 SQL 和负载做兼容性测试。就像一个人会说粤语,不代表他懂所有粤语俚语和古诗词。
为何常见:厂商宣传“PG-compatible“,用户自动脑补成”100% 相同“,而忽略了”兼容”是一个需要量化测量的比例。
误区部署一个全球大集群,数据副本遍布各大洲,那么任何地点的用户读写都应该很快,因为数据哪儿都有。
正解强一致写必须由多数派副本确认,如果副本跨洲,每一笔写都至少包含一个洲际网络往返;读也受 Leaseholder 位置约束,不能随便挑最近的副本。想低延迟只有两条路:把数据和“拍板的人”放到用户附近,或者接受异步复制带来的数据滞后。中央厨房可以全球配送,但“就近提货”也得等货先从远方运来。
为何常见:直觉上“多副本 = 到处都是数据 = 到处都快”,忽略了共识协议多数派确认带来的物理延迟下限。
面试题
Q1. 分布式数据库相比单机数据库的核心优势是什么?
- A.自动水平扩展并提升可用性← 正确答案
- B.单条 SQL 查询速度一定更快
- C.可以完全不创建任何索引
- D.不需要考虑网络分区问题
答案:A。分布式数据库把数据切成许多分片分散到多台节点,负载高时加节点即可扩容,节点故障由副本自动接管,这是它相对单机的核心优势。B 错误:查询速度取决于执行计划与网络开销,不一定更快;C 错误:任何数据库都需要合理索引;D 错误:恰恰相反,分布式系统必须认真处理网络分区。
Q2. 在 Raft 共识下,3 副本集群最多可同时故障几台仍能正常写入?
- A.最多 0 台
- B.最多 1 台← 正确答案
- C.最多 2 台
- D.最多 3 台
答案:B。Raft 的法定人数是 ⌊3/2⌋+1=2,即写入只要得到 2 个副本确认就能提交,因此允许 1 台副本宕机;如果 2 台同时故障,存活副本不足 2,无法形成多数派,写入会被阻塞。这就像三人委员会投票,至少两人同意才能通过。
Q3. YugabyteDB 的 YSQL 查询引擎主要继承自哪个数据库?
- A.MySQL
- B.Oracle
- C.PostgreSQL← 正确答案
- D.MongoDB
答案:C。YSQL 直接基于 PostgreSQL 源码构建,继承了 PG 的解析器、优化器和执行器,所以它的 SQL 语义与生态工具最贴近原生 PG。MySQL 是另一套方言体系,Oracle 是闭源商业库,MongoDB 是文档数据库,都与 YSQL 的出身无关。
Q4. CockroachDB 底层使用哪种统一模型来存储所有数据?
- A.文档模型
- B.图模型
- C.列式存储模型
- D.排序键值对模型← 正确答案
答案:D。CockroachDB 的所有表、索引最终都被编码为“排序的 Key-Value”存入统一的 KV 存储,表的一行只是连续 Key 区间中的一小段。文档模型是 YugabyteDB DocDB 的特色,图模型是图数据库,列式存储是 OLAP 分析引擎的取向。
Q5. 关于 CockroachDB 的写入路径,下列说法正确的是?
- A.写单个副本即可直接返回
- B.必须多数副本确认才提交← 正确答案
- C.必须全部副本确认才返回
- D.写入只落到本地不复制
答案:B。CockroachDB 每个 Range 副本之间用 Raft 共识同步,写入只需多数派(3 副本时为 2 个)确认即可提交。A 错误:单副本确认无法形成多数派;C 错误:要求全部副本确认会大幅降低可用性,没有必要;D 错误:不复制就失去了高可用意义。
Q6. CockroachDB 默认提供的事务隔离级别是?
- A.读未提交
- B.读已提交
- C.快照隔离
- D.可串行化← 正确答案
答案:D。CockroachDB 默认使用可串行化(serializable)隔离,这是最强的隔离级别,配合混合逻辑时钟实现全局一致的快照。YugabyteDB 默认才是快照隔离(更贴近 PG 常用语义)。读未提交在主流分布式数据库中几乎不会作为默认值。
Q7. 多区域集群中,把哪个角色放到离用户最近的区域能有效降低读延迟?
- A.全部的 Follower 副本
- B.分片的租约持有者← 正确答案
- C.冷备的历史数据节点
- D.集群的元数据注册表
答案:B。读请求由 Range 的 Leaseholder(租约持有者)负责,它相当于“值班店长”,把它放到客户端附近,读延迟就低。Follower 副本多但可能陈旧;冷备节点和元数据服务都不参与常规读路径,放得再近也没用。
Q8. 相对手工分库分表,云原生分布式数据库的优势包括哪些?
- A.跨分片事务原生支持← 正确答案
- B.自动均衡与故障自愈← 正确答案
- C.无需手工指定分片键← 正确答案
- D.完全不需要任何人工运维
答案:ABC。分片、复制、事务都是引擎内置能力,跨分片事务透明、数据自动再均衡、副本自动切换,都是相对中间件方案的实质性优势。但 D 过于绝对:任何数据库都需要监控、升级、容量规划等运维工作,不存在“完全不需要运维”的系统。
Q9. 对两家数据库 SQL 兼容性的正确理解包括哪些?
- A.CockroachDB 自研 PG 协议实现← 正确答案
- B.YSQL 来源于 PostgreSQL 内核← 正确答案
- C.兼容等于可零改动迁移
- D.兼容度决定迁移成本← 正确答案
答案:ABD。CockroachDB 用 Go 自研 SQL 层并实现 PG 连线协议,YSQL 则直接基于 PG 源码,两者路线不同。兼容度是一个比例而非二值,业务 SQL 中不兼容的部分越多,改写成本越高。C 错误:兼容不等于 100%,分布式化会裁剪某些单机特性。
Q10. 一个 9 副本的 Raft 小组,至少需要几个副本存活才能正常写入?
- A.3 个
- B.5 个← 正确答案
- C.7 个
- D.9 个
答案:B。法定多数 = ⌊9/2⌋+1 = 5,所以至少 5 个副本存活才能凑齐多数派完成写入,同时最多容忍 4 台故障。这里最常见的错误是直接用 9÷2 得到“4 或 5”不够严谨——必须向下取整后再加 1,保证多数严格超过半数。