分布式数据库通识:分片策略、事务模型与选型决策的关键概念

我是小马哥,干了十来年 DBA。这些年跟分布式数据库打交道,最大的感受是:概念不难,难的是搞清楚"这个概念在什么场景下才用得上"。这篇文章是我从实际项目里攒下来的经验——不讲虚的,只讲你真正需要知道的东西。咱们从架构聊到分片,从事务聊到选型,每个概念我都会告诉你在实际项目里它意味着什么。


从单机到分布式:架构的事先想清楚

分布式数据库听起来高大上,但它的起点其实就是一个朴素的念头:"一台机器真的扛不住了。"

单机扛不住有三种扛法。CPU 跑满了但数据量不大——加机器、多副本分担查询压力就行,Shared-Disk 架构够用了。数据量太大了单机磁盘装不下——必须分片,Shared-Nothing 架构走起。两者都扛不住——分片 + 多副本 + 分布式事务,全套上。

这三种"扛不住"对应了三种主流架构,咱们一个一个说。

Shared-Nothing 是目前分布式数据库最主流的玩法。每台机器有自己的 CPU、内存、磁盘,谁也不欠谁的,数据按分片策略分散在所有机器上。好处是水平扩展——加机器就加容量,线性增长。代价是有时候你查一条数据,它跨了两个分片,那就得协调两个节点一起干——这就是跨分片查询的开销。不过大多数 OLTP 查询(增删改查单条记录)天然就能落在单个分片上,所以这个代价在实际业务里没那么频繁。

Shared-Disk 是另一种思路:所有机器共享同一份存储(SAN 或者分布式文件系统),每台机器有自己的 CPU 和内存,但数据是同一份。好处是不用分片——数据本来就在那,所有节点都能访问,跨节点查询没有额外开销。坏处是当多台机器同时写同一块数据时,需要通过"缓存融合协议"来回传递数据块的所有权,写冲突多了性能就掉。这种架构适合那种"数据必须强一致、写冲突不多、但可用性要求极高"的场景。

存算分离 是这几年最火的话题。简单说就是把"算"(SQL 解析、查询优化、执行引擎)和"存"(数据持久化、副本管理)拆成两层。计算节点无状态——挂了就挂了,新拉一个直接挂载原来的存储就能干活。存储节点管数据副本和一致性,计算节点专门干活。好处很直接:晚上做批处理就多拉几个计算节点,算完就释放,不用为峰值长期买单。但代价是数据从存储层拉到计算层有网络开销——所以存算分离很依赖高速网络,不是所有场景都适合。


数据怎么切:分片这件事没有回头路

确定了架构,接下来就是最要命的问题:数据怎么分到不同节点上?这个决策一旦做了就很难改——分片键选错了,后面整个系统的查询性能都会被拖累。

哈希分片 是最常见的选择。hash(分片键) % 分片数,数据分布均匀,也不会出现热点——哈希函数会帮你把所有数据均匀地洒在所有分片上。但它有个代价:范围查询不好使。比如你想查"最近 90 天的订单",哈希把不同日期的订单随机散在各个分片上,这个查询就得扫所有分片——本来一个分片就能干的事变成了 N 个分片一起干。

范围分片 恰好相反。按 ID 或时间的值域范围分——分片 1 存 1-100 万,分片 2 存 100-200 万。范围查询非常高效——查 50 万到 150 万的数据,只需要碰两个分片。但代价是数据分布可能不均匀,而且最新写入的数据全部压在最后一个分片上——这就是"写入热点"。我见过不止一个系统,按日期做范围分片,结果每个月月底结算时候,最后一个分片的 CPU 跑满了,前面几个分片闲得发慌。

列表分片 按离散的枚举值分——比如按省份、按业务线。好处是业务语义清晰(华东订单独立一个分片,数据治理方便),坏处是分片之间数据量可能差出几个数量级——广东和西藏的用户量能一样吗?

一致性哈希分片 解决的是扩容时的数据迁移问题。传统哈希取模 hash % 4 加一个节点变成 hash % 5,几乎所有数据都要重新迁移——TB 级数据库的迁移周期是用天来算的。一致性哈希的思路是把所有节点和数据都映射到一个哈希环上,加减节点只影响相邻区域的数据——8 个节点加一个变成 9 个,只有约 1/9 的数据需要动。少了多少工作量,你自己算。

分片键选择 是所有这些决策里最不能犯错的。我总结四条铁律:这条列在 WHERE 条件里最频繁的字段应该当分片键(保证查询只走一个分片)、值域足够分散的字段(避免热点)、同一笔业务涉及的所有数据尽量在一个分片里(避免跨分片事务)、留有余地(以后加节点时不用大规模迁移数据)。选分片键的时候多花一周,后面少还三年技术债。选错了——那就不是改配置的事,是数据全量重分布的事。


数据可靠性:复制这件事比你想象的复杂

分片解决了"数据放哪"的问题,复制解决了"数据别丢"的问题。

主从复制 是最经典的方案——一个分片有一个 Leader 管写、多个 Follower 管读。写操作用户到 Leader,Leader 把变更同步给所有 Follower。读操作可以从任意 Follower 走——这就是读写分离。但 Follower 的数据不是实时的——Leader 写入后要经过"日志生成→网络传输→Follower 应用"三个环节,通常在毫秒到秒级。所以"写完之后立刻查"这种场景,你得把读请求强制路由回 Leader,不然大概率读到旧数据。

同步复制还是异步复制 这个问题在项目评审会上能吵一下午。同步复制:Leader 写完之后必须等至少一个 Follower 确认持久化才能返回成功——RPO 等于 0,任何情况下不丢数据,但多了一次网络来回的延迟。异步复制:Leader 写完就返回,不等人——延迟低,但 Leader 挂了那一瞬间可能有已提交但未同步的数据丢失。半同步是折中方案:Leader 等至少一个 Follower 确认就返回,保住至少一份完整副本。实际项目里,同机房的副本用同步(延迟可控,不超过 2ms),跨机房的用异步(几十毫秒的网络延迟不值得让所有写操作都等)。

主从切换的坑 是我见过最多的生产事故来源。主库宕了,要从一群 Follower 里选一个新 Leader——如果没有共识协议(比如 Raft),就会出现两个 Follower 同时认为自己是 Leader,各写各的——脑裂。脑裂一旦发生,两边的数据都乱了,分区恢复后基本没有干净的合并方案——只能从备份恢复,这意味着数据丢失。新一代的分布式数据库把 Raft 协议做到内核里,从协议层面杜绝了这个坑——任何决策必须多数派同意才生效,不可能出现两个 Leader 同时接受写入。


分布式事务:从 ACID 到"最终一致"的妥协

单机数据库里 BEGIN → 操作 → COMMIT 是铁律——要么全做,要么全不做。数据拆到多个分片上以后,一个业务操作可能同时改了分片 A 和分片 B 的数据——你怎么保证这俩分片同时成功或同时失败?

2PC(两阶段提交) 是最经典的答案。引入一个协调者:第一阶段"准备"——协调者让所有分片把事务操作执行完但不提交,锁住数据等着。第二阶段"提交"——如果所有人都准备好了,协调者发令一起提交;有任何一个人掉链子,全员回滚。2PC 的问题是第一阶段到第二阶段之间如果协调者崩了——所有分片全悬挂,锁不释放,数据被堵着,直到协调者恢复。金融核心系统还是得用它——宁可慢不能错。

TCC(Try-Confirm-Cancel) 把 2PC 的思路搬到了业务层。Try 阶段做预留(冻结库存、预占额度——不真扣),Confirm 阶段确认执行(冻结转正式扣减),Cancel 阶段回滚(释放预留资源)。好处是 Try 阶段不锁数据库——只是业务层面的"标记了一下"——并发能力比 2PC 强很多。代价是你得为每个业务操作写三套代码,而且处理各种异常场景(网络超时了 Try 到底成功了没?Cancel 被重试了两次怎么办?)。

SAGA 是处理长流程的利器。一个下单流程横跨订单、库存、支付、物流四个系统——等 2PC 全部锁着不现实。SAGA 的思路是:拆分成一串独立提交的小事务,每个小事务配一个"反操作"(补偿)。如果中间某一步失败了,按倒序把前面已成功的步骤一个个补偿回去。SAGA 的坑是隔离性——补偿完成之前,其他业务可能读到"做了一半"的中间数据。大多数业务场景下这能接受(订单"处理中"又不是什么大问题),但涉及钱的时候还是得用 TCC 或 2PC。

全局时钟 是所有分布式事务的基础设施。分布式系统里各机器的物理时钟有偏差,判断"谁先谁后"不能靠看表。最朴素的方案是单独搞一个授时服务(TSO),所有事务从它那拿时间戳——简单但那个授时服务是单点,得用高可用部署。更优雅的思路是混合逻辑时钟(HLC)——"物理时间戳 + 逻辑计数器"的组合,不依赖单一授时点但精度取决于 NTP 同步质量。Spanner 走了最极端的路线——用 GPS 加原子钟做硬件授时,把时间不确定度控制在 7 毫秒以内,在这个误差窗口内用"commit wait"来保证外部一致性。说白了就是:花大钱解决时钟问题,换一个全局一致的时间基准。


NewSQL 和 HTAP:分布式数据库的两条进化路线

几年前刚入行那会儿,分布式和 SQL/ACID 基本是互斥的——要么选传统关系型数据库的 ACID 保证,要么选 NoSQL 的水平扩展能力。NewSQL 的出现打破了这条线——它在保持 SQL 兼容和 ACID 事务的前提下,实现了 NoSQL 级别的水平扩展。背后怎么做到的?把数据分片做得更透明(对应用隐藏分片细节)、把分布式事务的协调开销优化到可接受范围(不是消除,是控制在几个百分点内)、用共识协议替代外部协调者做故障切换。

HTAP 是一条并行路线——它解决的不是"扩展"问题,是"实时分析"问题。传统架构里 OLTP(在线交易)和 OLAP(离线分析)是两套系统——白天交易库跑业务,晚上把数据 ETL 到分析库做报表。HTAP 的思路是同一套数据库同时干两件事——行存扛交易,列存扛分析,行存到列存在内部实时同步。为什么这个很重要?因为传统的 T+1 延迟(今天的数据明天才能分析)在实时风控、实时推荐这些场景下是致命的——你发现异常交易的时候钱已经转走了。

行列混合存储 是 HTAP 的底层支撑。行存——一行数据所有列放在一起,读一行一次 I/O 就搞定,但做聚合分析("统计所有用户上个月的消费总额")要扫大量不需要的列,浪费 I/O。列存——同一列的值连续存储,做聚合时只读需要的几列,I/O 省了、压缩率也高(同列数据类型相同,压缩比通常 10:1 以上),但插入一行要分别往各个列文件末尾写数据,写入开销大。所以实际做法是:OLTP 写入走行存 → 后台异步把行存转成列存 → OLAP 查询走列存。HTAP 数据库要解决的核心问题是这个转化过程的延迟和一致性。


选型时候我问自己的六个问题

聊了这么多概念,最后说说选型——这是我每次做技术评估的时候会问自己的六个问题,按优先级排的。

第一,这个系统三年后的数据量大概多大? 单机能扛住这三年就别上分布式——分布式引入的运维复杂度是实实在在的,不是"技术更先进"就一定要用。反过来,如果现在已经有几个 TB、增速还在加快,Shared-Nothing 或者存算分离架构就该认真看了。

第二,读写比例大概多少? 读多写少——主从复制加读写分离性价比最高。写密集——分片架构的写入分散能力比读写分离强得多,因为写操作分布在多个分片的 Leader 上,不像主从复制那样所有写都压在一台机器上。

第三,有没有跨分片的复杂查询? 大多数 OLTP 查询的条件带上分片键就只走一个分片——不用分布式事务。但如果业务里有大量"全局排序""跨租户统计"这类需求——要么选 Shared-Disk(天然支持跨节点查询),要么在应用层做聚合(把分片结果拉回来自己算),要么引入列存副本专扛分析。

第四,对数据一致性的容忍度? 资金相关——RPO 等于 0 是底线,同步复制加 2PC 或 TCC。一般业务——秒级延迟可以接受,异步复制加 SAGA 或本地消息表就够。不要为了一致性焦虑在所有场景都用强一致——成本和性能都会付出不必要的代价。

第五,团队有没有分布式数据库的运维经验? 分布式数据库的故障排查比单机复杂得多——网络分区、脑裂、日志不一致、再平衡卡住……这些问题在单机上不存在。如果团队还没准备好,选一个有成熟工具链和厂商技术支持的方案,比选一个技术指标最强但出了问题只能自己啃源码的方案划算得多。

第六,业务有没有合规和数据本地化要求? 某些行业要求数据必须存储在指定物理位置——这直接决定了你的分片策略(按地域做列表分片)、多租户架构(数据库级隔离还是 Schema 级隔离)和容灾部署(两地三中心还是同城双活)。


金仓数据库 KingbaseES 面向不同业务场景提供集中式和分布式两种架构选择,兼容 Oracle/MySQL 生态,支持基于 Raft 协议的高可用集群和分布式架构的水平扩展能力,在金融、政务、能源等领域有规模化部署案例。


资源推荐


声明:本文技术内容基于公开资料和行业实践整理,小马哥一家之言,仅供参考。具体架构选型需结合实际业务规模、负载特征和技术团队能力进行综合评估。

posted @ 2026-08-06 11:04  DBA小马哥  阅读(35)  评论(0)    收藏  举报