最近与同行进行技术交流时,经常被问到分库分表与分布式数据库应该如何选择。网上也有不少讨论中间件+传统关系数据库(分库分表)与 NewSQL 分布式数据库的文章,但其中一些观点与判断在我看来有些偏激。脱离具体环境去评价方案的好坏,其实有失公允。
本文旨在通过对两种模式关键特性的实现原理进行对比,尽可能客观、中立地阐明它们各自的真实优缺点以及适用场景。
NewSQL数据库先进在哪儿?
首先,关于“中间件+关系数据库分库分表”算不算 NewSQL 分布式数据库的问题,可以参考国外的一篇论文(pavlo-newsql-sigmodrec)。如果根据文中的分类,Spanner、TiDB、OceanBase 算是第一种新架构型,而 Sharding-Sphere、Mycat、DRDS 等中间件方案则属于第二种。
基于中间件(包括 SDK 和 Proxy 两种形式)与传统关系数据库的分库分表模式,算不算分布式架构?我认为是的,因为其存储确实实现了分布式,也能进行横向扩展。
但是否是“伪”分布式数据库呢?从架构先进性来看,这种说法也有一定道理。“伪”主要体现在中间件层与底层 DB 存在重复的 SQL 解析与执行计划生成工作,以及存储引擎仍基于 B+Tree 等,这在分布式数据库架构中实际上是冗余且低效的。为了避免陷入真伪分布式数据库的口水战,本文后续提到的 NewSQL 数据库特指这种新架构的 NewSQL 数据库。
那么,NewSQL 数据库相比中间件+分库分表先进在哪儿?我们可以通过一张简单的架构对比图来理解:

图1:传统数据库(分库分表)与 NewSQL 数据库架构核心差异对比
- 存储引擎设计:传统数据库面向磁盘设计,基于内存的存储管理及并发控制,不如 NewSQL 数据库那般高效。
- SQL处理冗余:中间件模式下,SQL解析、执行计划优化等在中间件与数据库中重复工作,效率较低。
- 分布式事务:NewSQL 数据库的分布式事务相比于XA进行了优化,性能更高。
- 高可用机制:新架构 NewSQL 数据库存储设计即为基于 Paxos(或 Raft)协议的多副本,相比于传统数据库的主从模式(半同步转异步后也存在丢数问题),实现了真正的高可用与高可靠(RTO < 30s,RPO = 0)。
- 分片透明性:NewSQL 数据库天生支持数据分片,数据的迁移、扩容都是自动化的,大大减轻了DBA的工作量,同时对应用透明,无需在 SQL 中指定分库分表键。
这些点也常是 NewSQL 数据库产品宣传的重点。但看起来如此美好的功能,是否真的如宣传一样呢?接下来,我将针对以上几点分别阐述我的理解。
分布式事务
这是一把双刃剑。
CAP限制
回想一下更早出现的 NoSQL 数据库为何大多不支持分布式事务(最新版 MongoDB 等已开始支持),是因为缺乏理论与实践支撑吗?并非如此。根本原因在于 CAP 定理依然是悬在分布式数据库头上的“紧箍咒”,在保证强一致性(C)的同时,必然会牺牲可用性(A)或分区容忍性(P)。那么,大部分 NoSQL 为何不提供分布式事务呢?
那么,NewSQL 数据库突破 CAP 定理的限制了吗?并没有。NewSQL 数据库的鼻祖 Google Spanner(目前绝大部分分布式数据库都参照其架构设计)提供了一致性和大于5个9的可用性,宣称是一个“实际上是CA”的系统。其真正含义是系统处于 CA 状态的概率非常高,由于网络分区导致的服务停用的概率非常小。究其原因,在于其打造的私有全球网络保证了不会出现网络中断引发的分区,此外还有其高效的运维团队。这也是 Cloud Spanner 的核心卖点。详细可见 CAP 提出者 Eric Brewer 撰写的《Spanner, TrueTime 和CAP理论》。
完备性
两阶段提交协议(2PC)是否严格支持 ACID?各种异常场景是否都能覆盖?实际上,2PC 在 commit 阶段发生异常时,与最大努力一阶段提交类似,也可能出现部分数据可见的问题。严格来说,在一段时间内并不能保证原子性(A)和一致性(C)(待故障恢复后,通过 recovery 机制可以保证最终的一致性和原子性)。
完备的分布式事务支持并非易事,需要能够应对网络以及各类硬件(网卡、磁盘、CPU、内存、电源等)异常,并通过严格的测试。之前与某友商交流,他们甚至表示目前已知的 NewSQL 数据库在分布式事务的支持上都是不完整的,他们都有案例可以“跑挂”这些系统。圈内人士如此笃定,也说明了分布式事务的支持完整度其实是参差不齐的。
然而,分布式事务又是这些 NewSQL 数据库非常重要的底层机制,跨资源的 DML、DDL 等都依赖其实现。如果这一块的性能或完备性打折扣,上层跨分片 SQL 执行的正确性会受到很大影响。
性能
传统关系数据库也支持分布式事务 XA,但为何在高并发场景下很少使用呢?因为 XA 基于的两阶段提交协议存在网络开销大、阻塞时间长、容易死锁等问题,这导致其实际上很少大规模用于基于传统关系数据库的 OLTP 系统中。
NewSQL 数据库的分布式事务实现也多基于两阶段提交协议,例如 Google 的 Percolator 分布式事务模型,它采用原子钟+MVCC+快照隔离(SI)。这种方式通过 TSO(Timestamp Oracle)保证了全局一致性,通过 MVCC 避免了锁,同时通过 primary lock 和 secondary lock 将一部分提交转为异步,相比 XA 确实提高了性能。
SI 是乐观锁,在热点数据场景下,可能会导致大量的提交失败。另外,SI 的隔离级别与 RR(可重复读)并非完全相同,它不会有幻读,但会出现写倾斜。
但无论如何优化,相比于 1PC,2PC 多出来的全局事务 ID 获取、网络交互、prepare 日志持久化等操作,仍会带来显著的性能损失,尤其是在跨节点数量较多时。例如,在银行场景下进行批量扣款,一个文件可能涉及上万个账户,这种场景无论怎么做,吞吐量都很难达到很高。
Spanner 给出的分布式事务测试数据

图2:Spanner 论文中展示的不同参与者数量下的分布式事务延迟数据(平均值与99百分位数)
虽然 NewSQL 分布式数据库产品都宣传完备支持分布式事务,但这并不意味着应用可以完全不用关心数据拆分。这些数据库的最佳实践中仍然会建议,应尽可能让应用的大部分场景避免使用分布式事务。
既然强一致事务付出的性能代价如此之大,我们不妨反思一下,是否真的在所有场景下都需要这种强一致的分布式事务?尤其是在微服务架构普及后,很多业务数据已不太可能集中在一个统一的数据库中。
尝试将一致性要求弱化,便引出了柔性事务的概念。它放弃 ACID,转而追求 BASE(基本可用、软状态、最终一致),例如 Saga、TCC、可靠消息最终一致性等模型。对于大规模高并发的 OLTP 场景,我个人更建议使用柔性事务而非强一致的分布式事务。
高可用与异地多活
主从模式并非最优的高可用方案,即便是半同步复制,在极端情况下(半同步转为异步)也存在丢数风险。目前业界公认更好的方案是基于 Paxos 分布式一致性协议或其变种(如 Raft)。Google Spanner、TiDB、CockroachDB、OceanBase 都采用了这种方式。基于 Paxos 协议的多副本存储,遵循“过半写”原则,支持自动选主,解决了数据的高可靠性问题,缩短了故障切换时间,提高了可用性,特别是减少了运维工作量。这种方案技术已很成熟,是 NewSQL 数据库的底层标配。
当然,这种方式也可以用于改造传统关系数据库。阿里、微信等团队也有将 MySQL 存储引擎改造以支持 Paxos 多副本的实践。MySQL 官方也推出了 MySQL Group Replication。预计在不远的将来,主从模式可能会成为历史。
分布式一致性算法本身并不复杂,但在工程实践中,需要考虑大量异常情况并进行诸多优化。实现一个生产级可靠、成熟的一致性协议并不容易。例如,实际使用时必须将其转化为 Multi-Paxos 或 Multi-Raft,并通过批处理、异步化等方式减少网络与磁盘 I/O 开销。
需要注意的是,很多 NewSQL 数据库厂商宣传基于 Paxos 或 Raft 协议可以实现【异地多活】,这实际上是有前提的,即异地之间的网络延迟不能太高。 以银行的“两地三中心”为例,异地之间往往相隔数千公里,网络延迟可能达到数十毫秒。如果要求多活,就需要异地副本也参与数据库日志的“过半确认”,如此高的延迟几乎没有 OLTP 系统能够接受。
在数据库层面实现异地多活是一个美好的愿景,但由物理距离导致的延迟,目前并没有完美的解决方案。
之前与蚂蚁团队交流,他们的异地多活方案是在应用层通过消息队列(MQ)同步双写交易信息。异地数据中心将交易信息保存在分布式缓存中。一旦发生异地切换,数据库同步中间件会告知应用数据延迟时间,应用则从缓存中读取交易信息,并将这段时间内涉及的业务对象(如用户、账户)进行“黑名单”管理,待数据同步追上后再将其从黑名单中剔除。由于双写的不是所有数据库操作日志而只是关键交易信息,数据延迟只影响一段时间内的部分数据,这是目前我认为比较靠谱的异地多活实现思路之一。
此外,有些系统进行了单元化改造,这在 Paxos 选主时也需要结合考虑,这也是目前很多 NewSQL 数据库所欠缺的功能。
横向扩展与分片机制
Paxos 算法解决了高可用、高可靠问题,但并未解决横向扩展(Scale Out)的问题,因此分片是必须支持的能力。NewSQL 数据库天生内置分片机制,并且会根据每个分片的数据负载(如磁盘使用率、写入速度等)自动识别热点,然后进行分片的分裂、数据迁移与合并。这些过程对应用是无感知的,极大地减轻了 DBA 的运维工作量。以 TiDB 为例,它将数据切分为 Region,当 Region 大小达到 64MB 时,数据会自动进行迁移。
而在分库分表模式下,应用需要在设计之初就明确各表的拆分键、拆分方式(范围、取模、一致性哈希或自定义路由表)、路由规则、拆分库表数量以及扩容方式等。相比 NewSQL 数据库,这种模式给应用带来了很大的侵入性和复杂度,对大多数系统而言是一大挑战。
分库分表模式也能做到在线扩容,基本思路是通过异步复制追加数据,然后设置库表为只读以完成路由切换,最后放开写操作。当然,这需要中间件与数据库端配合才能完成。
这里存在一个问题:NewSQL 数据库统一的内置分片策略(例如 TiDB 基于主键 Range)可能并非最高效的,因为它可能与领域模型中的业务划分要素不一致。这导致的后果是,很多业务交易会产生跨分片的分布式事务。
举个例子,银行核心业务系统通常以客户为维度,也就是说客户表、该客户的账户表、流水表在绝大部分场景下是一起写入的。但如果按照各表主键进行 Range 分片,这个交易很可能无法在一个分片上完成,这在高频 OLTP 系统中会带来显著的性能问题。
分布式SQL支持
对于常见的单分片 SQL,两者都能很好地支持。NewSQL 数据库由于定位是通用数据库,因此支持的 SQL 语法会更完整,包括跨分片的 Join、聚合等复杂查询。
中间件模式则更多地面向应用需求设计,不过大部分也支持带拆分键的 SQL、全库表遍历、单库 Join、聚合、排序、分页等。但对于跨库的 Join 以及聚合,支持能力通常不足。
NewSQL 数据库一般并不支持存储过程、视图、外键等功能。而中间件模式底层是传统关系数据库,这些功能如果仅涉及单库,是比较容易得到支持的。
NewSQL 数据库往往选择兼容 MySQL 或 PostgreSQL 协议,因此 SQL 支持局限于这两种。而中间件(尤其是驱动模式)通常只需做简单的 SQL 解析、计算路由和 SQL 重写,因此可以支持更多种类的数据库 SQL。
SQL 支持的差异主要在于分布式 SQL 执行计划生成器。由于 NewSQL 数据库拥有底层数据的分布统计信息,因此可以做基于成本的优化(CBO),生成的执行计划效率更高。而中间件模式下缺乏这些信息,通常只能基于规则进行优化(RBO)。这也是为什么中间件模式一般不支持跨库 Join,因为即使实现了,效率也往往不高,还不如交给应用层处理。
由此可见,中间件+分库分表模式的架构风格体现出的是一种妥协与平衡,它是面向应用的设计;而 NewSQL 数据库则要求更高、“大包大揽”,它是一个通用的底层技术软件,因此后者的复杂度和技术门槛也高得多。
存储引擎
传统关系数据库的存储引擎设计是面向磁盘的,大多基于 B+ 树。B+ 树通过降低树的高度来减少随机读,进而减少磁盘寻道次数,提高读性能。但大量的随机写会导致树的分裂,从而带来随机写,导致写性能下降。
NewSQL 数据库的底层存储引擎则多采用 LSM 树(Log-Structured Merge Tree)。相比 B+ 树,LSM 树将对磁盘的随机写变为顺序写,大大提高了写性能。不过,LSM 树的读操作由于可能需要合并多个数据文件,性能通常比 B+ 树差。一般而言,LSM 树更适合写多读少的场景。
当然,这只是单纯从数据结构角度进行的对比。在实际数据库实现中,还会通过 SSD、缓存、布隆过滤器等方式来优化读写性能,因此读性能基本不会下降太多。NewSQL 数据库由于存在多副本、分布式事务等开销,其单条 SQL 的响应时间相比单机关系数据库并不占优。但由于集群具备弹性扩展能力,整体 QPS 的提升还是非常明显的。这也是 NewSQL 数据库厂商常说的:分布式数据库更看重的是吞吐量,而不是单次 SQL 的响应时间。
成熟度与生态
分布式数据库是一种新型的通用底层软件,准确衡量与评价需要一个多维度的测试模型,应包括发展现状、使用情况、社区生态、监控运维、周边工具、功能满足度、DBA 人才储备、SQL 兼容性、性能测试、高可用测试、在线扩容能力、分布式事务能力、隔离级别、在线 DDL 等多个方面。
虽然 NewSQL 数据库经过了一段时间的发展与检验,但其应用多集中在互联网行业以及传统企业的非核心交易系统中,目前仍处于快速迭代、通过大规模使用不断优化完善的阶段。
相比之下,传统关系数据库已经过数十年的发展,通过了完整而严苛的市场评测,在成熟度、功能完备性、性能、周边生态、风险把控以及相关人才积累等多方面都具有明显优势,同时对已有系统的兼容性也更好。
对于互联网公司而言,数据量的增长压力以及追求新技术的基因,会使其更倾向于尝试 NewSQL 数据库。毕竟,不用再考虑库表拆分、应用改造、扩容、事务一致性等问题,怎么看都是一个非常吸引人的方案。
而对于银行这类风险意识较高的传统行业来说,NewSQL 数据库可能在未来一段时间内仍处于探索和审慎试点的阶段。基于中间件+分库分表的模式架构相对简单,技术门槛更低。虽然没有 NewSQL 数据库功能全面,但在大部分场景下,最核心的需求就是拆分后 SQL 的正确路由,而中间件模式应对这一点绰绰有余。可以说,在大多数 OLTP 场景下,它是够用的。
限于篇幅,其他特性如在线 DDL、数据迁移、运维工具等,本文不再展开对比。
总结
如果看完以上内容,您仍然难以抉择,那么可以结合以下几个问题,思考一下 NewSQL 数据库所解决的痛点是否是你真正的痛点:
- 强一致事务是否必须在数据库层解决?
- 数据的增长速度是否不可预估?
- 扩容的频率是否已超出了自身运维能力?
- 相比响应时间,是否更看重吞吐量?
- 是否必须做到对应用完全透明?
- 是否有熟悉 NewSQL 数据库的 DBA 团队?
如果以上问题有 2 到 3 个的答案是肯定的,那么你可以考虑采用 NewSQL 数据库了。虽然前期可能需要一定的学习成本,但它是数据库技术发展的方向,未来的收益也可能更高。尤其是对于互联网行业,随着数据量的持续爆发式增长,分库分表带来的痛苦会与日俱增。当然,选择 NewSQL 数据库也意味着你需要做好承担一定技术风险的准备。
如果仍未做出决定,不妨再想想下面这几个问题:
- 最终一致性是否可以满足实际业务场景?
- 未来几年的数据总量是否可以进行预估?
- 扩容、DDL 等操作是否有系统维护窗口期?
- 对响应时间是否比吞吐量更敏感?
- 是否需要兼容已有的关系数据库系统?
- 是否已有传统数据库 DBA 人才的积累?
- 是否可以容忍分库分表对应用带来的侵入性?
如果这些问题多数答案是肯定的,那么继续使用分库分表或许仍是更合适的选择。在软件领域,很少有完美的解决方案,NewSQL 数据库也并非数据分布式架构的“银弹”。相比之下,分库分表是一个代价更低、风险更小的方案。它最大限度地复用了传统关系数据库的成熟生态,通过中间件也能满足分库分表后的大多数功能需求,并且具备更强的定制化能力。
在当前 NewSQL 数据库尚未完全成熟的阶段,分库分表可以说是一个“上限低但下限高”的方案。尤其对于传统行业的核心系统,如果仍然希望将数据库作为一个稳定的黑盒产品来使用,踏踏实实地用好分库分表,往往被认为是一个更稳妥、更实际的选择。