想象你住的小镇有一家老字号药房。老板记性极佳,货架整整齐齐,方圆五里的人都来抓药——这就是传统关系型数据库(SQL):功能完备、可靠,但只能服务一条街的人。后来,网络上突然涌来千万客流,游医们在街边支起小摊,各管各的草药,谁也不知道对方给病人开过什么——这是 NoSQL:灵活、能摊大饼,却丢了统一规范和病历记录(事务)。NewSQL 要做的,是开一家全国连锁药房:既有老药房的规范服务(SQL 兼容、ACID 事务),又能开几千家分店应对天量客流(水平扩展),还保证每个分店对同一张处方的理解完全一致(强一致)。本篇要认识的三大“连锁品牌”——CockroachDB、TiDB、YugabyteDB,恰好代表了三种截然不同的扩张路径。我们将从店内的仓库管理(存储引擎)、处方如何走流程(事务模型)、以及各地对账方式(一致性保证)三层剖析三者的异同,最终帮你为业务挑选最合适的那家连锁。

岗位关联

学好 NewSQL,是云原生时代架构师与 AI 工程师的必修课。它决定了你在设计 AI 数据底座、高并发推荐系统或金融风控平台时,能否做出兼顾性能与可靠性的技术选型。

目录
  1. 可视化演示
  2. 背景与定义
  3. CockroachDB:总店强中心
  4. TiDB:分店自治海报栏
  5. YugabyteDB:先写行程单
  6. 存储引擎对比:仓库怎么摆货
  7. 事务模型对比:需要几个科室盖章
  8. 一致性保证:各地对账的严苛程度
  9. 选型与最佳实践:按店址选品牌
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

展示CockroachDB、TiDB与YugabyteDB三大NewSQL流派:存储引擎、事务模型与一致性保证对比,通过交互理解SQL兼容与水平扩展选型。

本节配有交互动效(进入视口后自动加载,约 3KB)。

存储引擎:三大流派 SQL兼容与扩展 水平扩展能力 En 按业务场景选型

背景与定义

小镇上那家老药房(单机 SQL 数据库)经营了几十年,口碑极好。可随着小镇变成千万人口的都市,药房门口排起长队,老板就算三头六臂也忙不过来。这时有人说:为什么不把药房搬到更多街区去呢?于是出现了没有统一规范的“游医摊”(NoSQL)——它们确实铺得快,可病人在这家看的病、在另一家开的药,完全没有记录关联。NewSQL 的使命,就是造出一家“规范又连锁”的大型药房网络。

连锁药房如何既保持老药房的服务标准(SQL 兼容),又拥有覆盖全国的能力(水平扩展)?答案是“开分店”:把数据切成若干分片,每个分片放在不同的分店(节点)里,同时给每份数据准备几个副本。分店越多,能接待的客流越大;副本越多,单店出问题也不影响整体营业。CockroachDB、TiDB、YugabyteDB 就是三种不同的“连锁管理方案”,它们都将数据分区与复制作为地基,差异体现在对分店的管理方式上。

展开来看,三者有一个共同的数学逻辑:系统的容量与数据被切成的分片数成正比,容错能力则与副本数成正比。于是有了如下关系。

由此可知,NewSQL 并非某种单一技术,而是一套“既要也要”的系统工程。接下来,我们逐一走进三家连锁药房,看它们各自的经营哲学。

系统容量=分片数×单分片容量;可用性∝副本数\text{系统容量} = \text{分片数} \times \text{单分片容量}; \quad \text{可用性} \propto \text{副本数}
分片数越多、处理能力越大;副本数越多、越不怕节点故障。但分片与副本都会引入新的协调开销,所以分布式数据库的设计始终在“扩展性”与“一致性”之间找平衡。
  1. 分片数与容量的关系$\text{系统容量} = \text{分片数} \times \text{单分片容量}$ 表示把数据横向切分到更多分店,整体接待能力线性增长。
  2. 副本与可用性$\text{可用性} \propto \text{副本数}$ 说明每份数据多存几份,即使某个分店起火(节点宕机),其他分店还能继续营业。
  3. 平衡点$n$ 个分片带来 $n$ 倍的并发,但也让跨分片的处方(跨节点事务)需要更多沟通成本,这就是后面要讲的事务与一致性问题。

CockroachDB:总店强中心

CockroachDB 的连锁模式,像是有一个极有权威的总店:所有分店都严格对齐总店的时钟。你在上海分店上午 10 点开的处方,北京分店 10 点零 1 秒查询时,必定能看到。这种“全局时钟”由混合逻辑时钟(HLC)实现,它把物理时间与逻辑事件序号结合,让所有节点对“谁先谁后”达成一致。

有了统一的时间观,CockroachDB 用 Raft 共识算法管理每个数据分片的副本组。每个分片的数据存 3~5 份,副本之间通过多数派投票决定谁来当“领头店长”(Leader)。写请求只发给 Leader,Leader 将日志复制给多数派 Follower 后才算成功。这种机制保证了即使少数分店失联,系统依然能正常营业。

跨分片的事务则依靠两阶段提交(2PC)协调,配合全局时钟实现可串行化隔离。这让 CockroachDB 成为强一致爱好者的首选——但代价是跨区域延迟较高。它的核心公式在于多数派决策:

CockroachDB 就像纪律严明的连锁总店:每个分店都在同一时间标准下工作,重大决策必须多数店长点头。这种“强中心”风格,换来的是让金融监管都放心的数据一致性。

Q=⌊n2⌋+1Q = \lfloor \dfrac{n}{2} \rfloor + 1
在一个有 $n$ 个节点的副本组中,至少 $Q = \lfloor n/2 \rfloor + 1$ 个节点确认,才能提交一条写入。例如 3 节点组需要 2 人点头,5 节点组需要 3 人点头。
  1. 节点总数 $n$$\lfloor n/2 \rfloor$ 表示取 $n$ 的一半并向下取整,例如 $n=3$ 时 $\lfloor 1.5 \rfloor = 1$。
  2. 加一形成多数$+1$ 让 $Q$ 严格超过一半,避免出现两个半数派别互相否决的“脑裂”僵局。
  3. 法定人数 $Q$$Q$ 是提交事务所需的最小确认数,只要获得 $Q$ 个副本确认,写入就安全落盘。

TiDB:分店自治海报栏

TiDB 的连锁哲学截然不同:分店各自记账,但总部会定期贴出“海报栏”(全局快照),让大家看到某个时刻的完整账本。TiDB 将体系分为三层:最上层是无状态的 TiDB Server(相当于接待前台),中间是存储层 TiKV(一个分布式的 Key-Value 仓库),最底下是 PD 调度模块(负责分片管理与负载均衡)。前台与仓库分离,意味着前台可以随意增减,轻松应对突发客流。

TiKV 底层的存储引擎是 RocksDB,它采用 LSM-Tree 结构,写入像往快递仓库扔包裹一样快。每个数据分片(Region)默认保存 3 份副本,并用 Raft 协议同步。TiDB 的招牌技术是多版本并发控制(MVCC):每行数据保留多个历史版本,每个版本打上“写入时间戳”。读请求拿到一个全局快照时间戳后,只需找到对应时间点的版本即可,读写互不阻塞。

MVCC 的核心是版本可见性判断。当一个事务的读时间戳为 $T_{read}$ 时,只有满足以下条件的版本才可见。

TiDB 的 MVCC 就像药房的海报栏:顾客看的是贴出来的历史公告,店员在后面改账本也互不打扰。这种设计让 TiDB 在读写混合场景下表现出色,同时高度兼容 MySQL 协议,让无数 MySQL 团队零改造迁移。

可见(vi)⇔Tread≥Twrite(vi)  ∧  未标记删除(vi)\text{可见}(v_i) \Leftrightarrow T_{read} \ge T_{write}(v_i) \;\wedge\; \text{未标记删除}(v_i)
读请求只看到写时间戳早于自己读时间戳、且未被删除标记的版本。这条规则让读者看到的是“某个瞬间的安静快照”,而不是正在变动的实时数据。
  1. 读时间戳与写时间戳比较$T_{read} \ge T_{write}(v_i)$ 表示只有在自己开始读之前就已提交的版本才有资格被看到。
  2. 未删除条件$\text{未标记删除}(v_i)$ 排除那些已被逻辑删除(打了墓碑标记)的版本。
  3. 与(∧)运算$A \wedge B$ 要求两个条件同时成立,MVCC 才认为该版本可见。

YugabyteDB:先写行程单

YugabyteDB 的经营方式更有趣:每个分店在办事之前,先在小黑板上写一份“行程单”——我接下来要做什么——然后按单执行。这个“行程单”其实就是预写日志(WAL)。YugabyteDB 的查询层直接复用 PostgreSQL 的代码,所以它几乎 100% 兼容 PostgreSQL 的语法、类型和扩展生态。存储层叫 DocDB,是一个基于 RocksDB 的分布式文档存储系统,数据模型是“表+行+列”的嵌套结构。

事务被明确分成两层:如果操作只涉及单个分片内的数据,就在本地用 PostgreSQL 风格的事务解决,开销极小;如果操作跨多个分片,才升级为分布式事务(常用两阶段提交)。这种分层的好处非常直观:大多数业务请求只访问少量行,本地事务就够了,不必每次都付出昂贵的跨节点协调成本。

用公式表达本地事务与分布式事务的代价差异:

YugabyteDB 的策略很务实:大多数处方只需一个柜台搞定,少数需要多科室会诊的才大动干戈。这让它成为深度使用 PostgreSQL 的团队最顺手的分布式升级路径。

Tdistributed≈Tlocal×2+TnetworkT_{\text{distributed}} \approx T_{\text{local}} \times 2 + T_{\text{network}}
分布式事务至少需要两次远程通信(准备 + 提交),而本地事务只需要一次本地处理。设计者把高频简单操作留在本地,把低频复杂操作交给分布式协调,从而兼顾性能与正确性。
  1. 本地事务 $T_{\text{local}}$单分片内执行的事务,只需在一家分店内部完成,没有网络往返。
  2. 两倍关系 $\times 2$跨分片事务至少经历“准备阶段”与“提交阶段”两次往返,因此时间约为本地事务的两倍。
  3. 网络开销 $T_{\text{network}}$分店之间的消息传递延迟,在跨地域场景下可能远超本地计算本身。

存储引擎对比:仓库怎么摆货

现在走进三家药房的仓库。仓库的货物摆放方式,直接决定了药房抓药(读)和进货(写)的速度。传统老药房(如 MySQL 的 InnoDB)用的是 B+Tree:货架永远按药品编号排得整整齐齐,找药极快,但每次进货都要重新腾挪位置,写多时效率下降。三家中最特殊的是 TiDB 和 CockroachDB,它们的存储层都建立在 RocksDB(LSM-Tree)之上,而 YugabyteDB 的 DocDB 也用了 RocksDB。

LSM-Tree 的哲学是“先堆后理”:新货物先扔进内存的“待整理区”(MemTable),攒够一批再批量刷到磁盘上的“货架”(SSTable)。写入永远是好玩的追加操作,所以写性能极高;但读取要依次查看内存、各级磁盘文件,数据越久越深,读起来相对费劲。这就引出了一个关键指标——读写放大。

写放大(Write Amplification)衡量实际写入磁盘的数据量是逻辑写入量的多少倍:

选型时看清读写比很重要:日志型、IoT 型业务写多读少,LSM 系(TiDB、CockroachDB)如鱼得水;报表型、复杂查询业务读多写少,也许传统 B+Tree 或带强缓存的方案更合适。

WA=D实际写入磁盘D逻辑写入WA = \dfrac{D_{\text{实际写入磁盘}}}{D_{\text{逻辑写入}}}
逻辑上的 1MB 写入,由于要经历多次 Compaction(合并文件),实际可能写入了几 MB 到几十 MB。写放大越高,磁盘寿命损耗越大,但对写入延迟反而更友好。
  1. 逻辑写入 $D_{\text{逻辑写入}}$应用层期望保存的数据量,比如 1MB 的订单记录。
  2. 实际写入 $D_{\text{实际写入磁盘}}$LSM-Tree 后台合并(Compaction)导致同一份数据被反复改写落盘的累计量。
  3. 比值 $WA$$WA$ 越大说明磁盘磨损越严重;读取放大则相反,表示一次逻辑读需要扫描的数据量倍数。

事务模型对比:需要几个科室盖章

一张处方若同时涉及心内科和呼吸科,两个科室都得盖章确认,缺一不可。分布式数据库的事务模型也是这个道理:如果一次操作的数据恰好都在同一个分片内,那只需一个“科室”(节点)盖章,这就是单分片事务;如果数据散落在多个分片,就需要所有相关节点同时确认,这就是分布式事务。

CockroachDB 对跨分片事务采用两阶段提交(2PC)加重试机制,配合全局时钟实现严格的可串行化;TiDB 采用乐观锁思路,先假定事务不会冲突,提交时若检测到版本冲突则让事务重试;YugabyteDB 则偏向悲观锁,在事务开始时加锁,冲突少但等待可能增多。三种风格没有绝对优劣,要看业务冲突的比例。

两阶段提交的提交条件可以形式化为:

跨科室盖章总是比单科室麻烦,但这是保证连锁药房“处方不乱”的必要代价。并发高、单事务涉及行少的业务,应尽量避免频繁触发分布式事务——这也是选型时的优化要点。

∀pi∈P:prepare(pi)=OK⇒commit\forall p_i \in P: \text{prepare}(p_i) = \text{OK} \Rightarrow \text{commit}
只有事务涉及的所有参与者 $p_i$ 都回复“准备就绪”,协调者才能发出全局提交指令。只要有一个节点准备失败,整个事务就回滚。
  1. 参与集合 $P$$P$ 是本次事务涉及的所有数据分片节点集合。
  2. 准备阶段 $\text{prepare}(p_i)$协调者询问每个节点“能否锁定相关数据并准备好提交”,节点回答 OK 或 Abort。
  3. 全称量词 $\forall$$\forall p_i \in P$ 要求集合中每个节点都满足条件,一个都不能少,体现分布式事务的原子性本质。

一致性保证:各地对账的严苛程度

连锁药房最怕什么?同一张处方在广州是 100 元,在上海查变成 120 元。一致性保证就是规定各分店在什么时间点对账、对账后看到什么。CockroachDB 提供线性一致性:任何读操作都像在“绝对公平的队列”里排队,一旦某条写请求完成确认,之后所有读请求必然读到它——哪怕这些读发生在另一个城市。

TiDB 默认提供快照隔离:每个事务基于一个固定的历史快照运行,比如午时 12:00 整的账本。大家在午时看的是同一份数据,但午时之后新开的处方不会被这个快照看到。YugabyteDB 提供 PostgreSQL 级别的隔离强度,默认是读已提交(Read Committed),可选串行化——即所有事务像排队买单一样,效果上等价于串行执行。

线性一致性的数学刻画是对操作顺序的约束:

选择哪档一致性,取决于业务能否容忍“短暂读旧”。金融转账必须线性一致;而商品库存、内容社区用快照隔离也足够,没必要为极致一致付出高延迟的代价。

∀w,r:w→sor⇒TS(w)≤TS(r)  ∧  r 能观察到 w 的效果\forall w, r: w \xrightarrow{\text{so}} r \Rightarrow TS(w) \le TS(r) \;\wedge\; r \text{ 能观察到 } w \text{ 的效果}
若写操作 $w$ 在全局顺序上先于读操作 $r$,则 $r$ 的时间戳必定不小于 $w$、且能看到 $w$ 写入的数据。离线不一致、最终一致这类模糊状态在线性一致性下被彻底禁止。
  1. 全局顺序 $\xrightarrow{\text{so}}$so 表示“顺序发生”(session order),即所有操作在全局时间轴上有一个确定的前后关系。
  2. 时间戳约束 $TS(w) \le TS(r)$读操作的时间戳不能早于其之前发生的写操作的时间戳。
  3. 可观察效果$r$ 能观察到 $w$ 的效果,意味着读到了 $w$ 提交的新值,而非旧快照。

选型与最佳实践:按店址选品牌

介绍完三家连锁的脾气,终于到了做决定的时刻。选型就像为一座新城挑选药房品牌,关键看地段和客流:如果业务是金融交易、订单支付,强一致是底线,CockroachDB 的线性一致性最为稳妥;如果团队已有 MySQL 背景、业务要平滑扩容,TiDB 的 MySQL 生态能让你少掉头发;如果公司重度使用 PostgreSQL 的 JSON、地理空间等高级特性,YugabyteDB 是最平滑的分布式延伸。

集群规划时要把容量、分片、跨域复制统筹考虑。数据量暴涨前,应预先设计好分片键,避免热点分店被挤爆;跨区域部署时,把副本放在不同可用区甚至不同城市,保证地震火灾都撼动不了核心账本。日常运维则需要搭好监控体系:三大数据库都原生支持 Prometheus 指标暴露与 Grafana 仪表盘,慢查询日志、副本落后时间、Raft 投票活跃度是重点观测项。

从成本角度综合权衡:

选型没有最好的数据库,只有最匹配业务的数据库。把一致性需求、团队技能、读写特征和运维成本放在一张表里打分,答案会自己浮现。

TCO=Cnode×N+Cops+Cdowntime×PfailTCO = C_{\text{node}} \times N + C_{\text{ops}} + C_{\text{downtime}} \times P_{\text{fail}}
总体拥有成本 = 节点采购/租赁费用 + 运维人力 + 停机损失期望值。看起来单价低的方案,如果运维复杂或故障率高($P_{\text{fail}}$ 大),总成本未必占优。
  1. 节点成本 $C_{\text{node}} \times N$$N$ 是集群节点数,$C_{\text{node}}$ 是单节点硬件或云主机成本。
  2. 运维成本 $C_{\text{ops}}$包括 DBA 人力、监控告警、备份恢复体系的搭建与维护。
  3. 停机损失 $C_{\text{downtime}} \times P_{\text{fail}}$每次故障的平均损失乘以故障概率,是隐性但最昂贵的成本项。

AI 应用场景

金融风控实时特征库

阶段:数据采集与特征存储

解决的问题:金融风控模型需要实时读写用户交易流水,并跨多个服务保持账户余额一致。传统 MySQL 扛不住峰值写入,Redis 之类的缓存又难保证强一致。CockroachDB 的线性一致性 + 分布式事务,让 AI 风控平台在读取特征时永远拿到最新账户状态,避免“读到旧余额导致误判”。

具体案例:某支付平台将交易流水写入 CockroachDB 三副本集群,AI 风控系统实时读取特征、计算风险分。某次大促峰值每秒 3 万笔写入,集群平滑扩展至 20 个节点,千亿级风控查询全部返回最新数据。

电商大促AI推荐训练样本库

阶段:训练样本生成与离线特征服务

解决的问题:推荐系统需要把用户点击、下单行为整合成训练样本,样本量随着大促流量陡增。TiDB 的 MySQL 兼容让业务代码零改动接入,其存算分离架构允许在流量高峰快速扩展计算节点,MVCC 保证数据抽取时不会被正在写入的行为日志打断。

具体案例:某电商平台用 TiDB 存储近 90 天用户行为明细,AI 特征工程每半小时从 TiDB 拉取增量数据生成训练集,在线推理服务实时查询用户最新特征,支撑了「双11」期间 1 万个 Pod 的模型推理。

银行业务系统跨区域双活

阶段:交易数据落库与 AI 辅助审核

解决的问题:银行要求核心账务系统跨城市双活部署,且主备切换不能丢失任何交易。YugabyteDB 对 PostgreSQL 的深度兼容,使行内成熟的 Oracle 迁移资产可复用,Raft 复制让双中心自动选主,AI 审核系统读取数据时无需关心当前主中心在哪个城市。

具体案例:某城商行将贷款审批系统迁至 YugabyteDB,部署在两个可用区,Raft 自动维持 5 副本。AI 审批模型并发读取 5 万笔待审订单,异地容灾演练时 RTO 小于 30 秒。

Python 演示

python49 行
import random  class Node:    """模拟 Raft 副本组中的一个节点。"""     def __init__(self, node_id):        self.node_id = node_id        self.log = []     def append_entry(self, entry):        self.log.append(entry)        return True  class RaftGroup:    """简化版 Raft 法定人数日志复制模拟器。"""     def __init__(self, n_nodes, leader_index=0):        self.nodes = [Node(i) for i in range(n_nodes)]        self.leader = self.nodes[leader_index]        self.quorum = n_nodes // 2 + 1     def write(self, value):        entry = {"value": value, "term": len(self.leader.log) + 1}        self.leader.append_entry(entry)        acks = 1  # leader 自己算一票        for node in self.nodes:            if node is self.leader:                continue            if random.random() < 0.9:  # 成功复制概率 90%                node.append_entry(entry)                acks += 1        if acks >= self.quorum:            print(f"提交成功: {value}  (法定人数={self.quorum}, 确认={acks})")            return True        print(f"提交失败: {value}  (法定人数={self.quorum}, 确认={acks})")        return False     def read_leader_log(self):        return [e["value"] for e in self.leader.log]  if __name__ == "__main__":    group = RaftGroup(n_nodes=5, leader_index=0)    for i in range(1, 7):        group.write(f"处方-{i}")    print("Leader 日志:", group.read_leader_log())    print("各节点日志条数:", [len(n.log) for n in group.nodes])
目的:模拟 Raft 共识中“日志通过多数派确认后提交”的过程,直观展示法定人数公式 Q = ⌊n/2⌋ + 1 如何在故障下保护数据一致。
  1. quorum = n_nodes // 2 + 1计算法定人数,5 个节点时需要 3 个确认才能提交。
  2. random.random() < 0.9模拟网络可能丢包,让每份副本的复制并非 100% 成功。
  3. acks >= self.quorum只有确认数达到法定人数,写操作才真正落盘,这是 Raft 安全性的核心。
  4. read_leader_log()读请求由 Leader 处理,确保读到的是已被多数确认的日志。

常见误区

误区很多初学者以为 TiDB 这类 NewSQL 只是把 MySQL 加个中间件做分库分表,区别不大,选哪个都一样。

正解分库分表方案(如 ShardingSphere)只是把请求分发到多个 MySQL 实例,每个实例依然是独立的数据库,跨分片事务与全局一致性非常难做。而 NewSQL 从底层重新设计了存储引擎、分布式事务与一致性协议,是一个“原生分布式”的自治系统,相当于把连锁药房的总部、物流、账本在诞生之初就合为一体,而不是事后加个调度员。

为何常见:因为 TiDB 对外兼容 MySQL 协议,连接方式、SQL 语法看起来一模一样,容易让人误以为它只是“加强版 MySQL”。

误区很多人一听到“线性一致性 + 全局时钟 + Raft 多数派”,就觉得性能一定很差,直接否掉。

正解线性一致性带来的额外延迟主要在跨节点通信上,而同城同区域内的多数派确认通常只有几毫秒。CockroachDB 还支持把高频读取放到本地副本,将读请求就近处理。真正需要担心的是跨地域写放大,而非强一致本身。好比总店规定全国收银台时间一致,这并不会让每个分店的收银变慢,只是需要联网对表而已。

为何常见:大家容易把“一致性强”和“性能差”画等号,忽略了延迟的关键在于网络距离和副本布局。

误区有人认为 TiDB 的快照隔离就是“读到旧数据没关系,反正最终会一致”,把快照隔离当成弱一致。

正解快照隔离依然是强一致的一种,它保证每个事务看到的是一份完整、一致的历史快照——不会出现“读到一半账单”这种撕裂状态。它和最终一致的本质区别是:快照隔离在任何时刻都返回某个确定时间点的正确状态,而最终一致存在中间态的“脏读”窗口。就像午时 12 点整的账本照片,虽然看不到下午的新处方,但照片本身是完整准确的。

为何常见:因为“快照”听起来像是“暂存数据”,让人误以为是不稳定的临时值。

误区有人以为 CockroachDB、TiDB、YugabyteDB 分别用三种截然不同的存储引擎,技术栈互不相关。

正解实际上三者底层都有 RocksDB / LSM-Tree 的身影。TiDB 的 TiKV 直接基于 RocksDB;CockroachDB 的 Pebble 是 RocksDB 思想下的 Go 语言实现;YugabyteDB 的 DocDB 同样建立在 RocksDB 之上。真正的差异不在“用什么引擎”,而在于数据模型、分片策略、事务控制这些上层架构。

为何常见:每家的宣传材料都强调自己的存储“独特”,但底层开源组件的共用被刻意淡化了。

误区学完 NewSQL 后,有人觉得 MySQL、PostgreSQL 该淘汰了,所有新项目都应该上分布式。

正解单机数据库在数据量可控、读多写少的场景下依然极具性价比和运维便利。分布式数据库需要至少 3 个节点起步,复杂度和成本都更高。技术选型要看数据量是否真的到了单机瓶颈、是否需要跨地域容灾、是否无法接受分库分表的复杂性。连锁药房不会开进每一条小巷,街角老药房在很多社区依然是更好的选择。

为何常见:新技术总会带来“非此即彼”的二元思维,但成熟架构往往是多种技术并存的混合格局。

面试题

Q1. NewSQL 相比 NoSQL 的核心差异是什么?

单选题 · easy

  • A.NewSQL 不支持水平扩展
  • B.NewSQL 保留 SQL 与事务能力← 正确答案
  • C.NewSQL 只支持内存存储
  • D.NewSQL 不需要副本容灾

答案:B。NewSQL 兼顾 NoSQL 的扩展能力与传统 SQL 的关系模型和 ACID 事务。A 说反了,NewSQL 的招牌就是水平扩展;C、D 都是典型的 NoSQL 特征而非 NewSQL 特征。

Q2. 下列哪家数据库以全局时钟保证强一致?

单选题 · easy

  • A.CockroachDB← 正确答案
  • B.TiDB
  • C.YugabyteDB
  • D.Cassandra

答案:A。CockroachDB 采用混合逻辑时钟(HLC)为所有操作排序,实现线性一致性。TiDB 依赖 PD 分配时间戳实现快照隔离,YugabyteDB 使用 Raft 但并未以全局时钟为核心,Cassandra 是最终一致。

Q3. TiDB 的存储层 TiKV 基于哪个开源引擎?

单选题 · easy

  • A.InnoDB
  • B.RocksDB← 正确答案
  • C.WiredTiger
  • D.BerkeleyDB

答案:B。TiKV 是一个分布式 Key-Value 存储,单节点层面基于 RocksDB(LSM-Tree 结构)。InnoDB 是 MySQL 的存储引擎,WiredTiger 是 MongoDB 的引擎,BerkeleyDB 则是 Oracle 的老牌嵌入式存储。

Q4. CockroachDB 中 Raft 副本组法定人数的计算方式?

单选题 · mid

  • A.n/2
  • B.n/2 + 1
  • C.⌊n/2⌋ + 1← 正确答案
  • D.n - 1

答案:C。法定人数 $Q = \lfloor n/2 \rfloor + 1$,即超过半数。例如 5 节点组需要 3 节点确认,A 和 B 都可能得到小数,D 的容忍度过低,不具备容错能力。

Q5. YugabyteDB 的查询层兼容哪种数据库协议?

单选题 · mid

  • A.MySQL
  • B.Oracle
  • C.PostgreSQL← 正确答案
  • D.SQL Server

答案:C。YugabyteDB 直接复用 PostgreSQL 的查询层代码,实现高度兼容的 PostgreSQL 协议和 SQL 语义。它虽有"YSQL"命名,但底层是标准的 PostgreSQL 能力,而非 MySQL 或 Oracle。

Q6. 关于 LSM-Tree 存储引擎的特点,下列说法正确的是?

单选题 · mid

  • A.读快写慢,适合报表分析
  • B.写快读慢,适合日志写入← 正确答案
  • C.读写都快,全面超越 B+Tree
  • D.读写在所有场景下都慢

答案:B。LSM-Tree 将随机写转化为顺序追加,写性能极佳,但读取可能需要合并多层数据,读放大明显。日志、IoT 这类写多读少的业务是它的主场。

Q7. 下列哪些技术被 NewSQL 用于保证事务正确性?

多选题 · mid

  • A.两阶段提交(2PC)← 正确答案
  • B.Raft 日志复制← 正确答案
  • C.多版本并发控制(MVCC)← 正确答案
  • D.全局时间戳排序← 正确答案

答案:ABCD。三大流派都综合运用这些手段:CockroachDB 用 2PC 加全局时钟,TiDB 用 MVCC 加 Raft,YugabyteDB 用 2PC 加 Raft。四者都是分布式事务与一致性的基石。

Q8. 关于 TiDB 架构,以下说法正确的有哪些?

多选题 · hard

  • A.计算层与存储层分离部署← 正确答案
  • B.PD 负责分片调度与负载均衡← 正确答案
  • C.兼容 MySQL 的传输协议← 正确答案
  • D.数据以 Region 为单位复制管理← 正确答案

答案:ABCD。TiDB Server 是无状态计算层,TiKV 是存储层,PD 负责时间戳分配与调度,Region 是数据分片基本单位。四者共同构成存算分离、可弹性伸缩的 MySQL 兼容分布式数据库。

Q9. 某支付平台要求读操作必须看到此前所有已确认的转账,应优先选择?

单选题 · hard

  • A.TiDB(快照隔离)
  • B.CockroachDB(线性一致性)← 正确答案
  • C.YugabyteDB(读已提交)
  • D.Cassandra(最终一致性)

答案:B。线性一致性保证写确认后所有后续读都可见,是题干需求的最严格匹配。TiDB 的快照隔离只保证快照内一致,YugabyteDB 默认读已提交,Cassandra 最终一致都达不到该约束。

Q10. 关于三大 NewSQL 流派,以下哪些说法是准确的?

多选题 · hard

  • A.CockroachDB 强调线性一致性← 正确答案
  • B.TiDB 使用乐观锁解决冲突← 正确答案
  • C.YugabyteDB 支持事务分层← 正确答案
  • D.三者存储层均基于 LSM-Tree← 正确答案

答案:ABCD。CockroachDB 以全局时钟实现线性一致;TiDB 的并发控制采用乐观锁与重试;YugabyteDB 区分本地事务与分布式事务;CockroachDB 的 Pebble、TiDB 的 TiKV、YugabyteDB 的 DocDB 底层都是 LSM-Tree 思想实现,四者均正确。