
在数据库性能遇到瓶颈时分库分表是绕不开的话题。很多同学一听到“分库分表”就头皮发麻觉得名词一大堆、中间件原理神秘莫测其实核心就那么几件事。这篇博文想跟你好好聊聊分库分表相关的名词以及中间件背后的运行原理。我接触过的项目里从单库到分库分表的演进踩过不少坑所以这篇不只是概念堆砌更多是实际操作里摸出来的经验。无论你现在是刚接触这个方向还是已经在排查分库分表问题这篇内容都能给你一些有参考价值的思路。话不多说先直接拆解分库分表里的核心名词。别被“分库分表”这个词吓住它本质就是一种数据拆分策略目的是让单库单表扛不住的压力分散到多个库、多张表上。但拆分不是拍脑袋里面涉及的名词和原理是有严格逻辑的理解了这些再看中间件源码或者配置文档会顺很多。1. 分库分表核心名词拆解分库分表相关的名词看起来多其实都能归纳到数据拆分、路由访问、数据一致性这几个族群里。这里先把最常见的、面试和工作里都会高频遇到的名词讲透并且说清楚它们之间是什么关系。1.1 分库与分表的区别和联系分库和分表是两个维度的事情很多人一开始会混淆。分库就是把原本集中在一个数据库里的数据按照某种规则分散到多个数据库实例上。分表则是把同一张表里的数据按照规则拆到多张物理表里这几张表可以在同一个库也可以跨库。它们面对的问题不一样。分库主要解决的是连接数、I/O吞吐、CPU压力这些数据库实例级别的瓶颈。比如说单库的连接数到了上限或者写入并发把单库的磁盘I/O打满了这时候分库就有了意义。分表主要解决的是单表数据量过大带来的索引深度、扫描行数、锁竞争等问题。一张表几千万行甚至上亿行之后即使有索引B树的层数也会增加查询性能明显下滑分表能把单表的数据量降下来。实际项目里通常是先分表后分库或者两者并行。举个例子订单表在单库单表状态下到了几千万行先按订单ID哈希分表拆出16张表单表数据量降到了几百万行性能问题缓解了。但随着业务继续增长单库的总写入量又上去了这时再把16张表分别放到4个库上每个库4张表这就是分库分表结合。理解这个组合逻辑后面配置中间件时才能明白为什么分片规则要同时考虑库和表。1.2 水平拆分与垂直拆分的适用场景水平拆分和垂直拆分是两种截然不同的思路。水平拆分是把同一张表的数据行按某种规则分到不同的物理表或库里每一份的结构完全一样只是数据子集不同。垂直拆分是把一张表的不同列拆到不同的表里每一份拥有不同的字段通过主键关联。水平拆分最典型的场景就是用户表、订单表这种持续增长的业务表。拆分后单表数据量下降索引和维护成本也跟着下降。垂直拆分常用于一张表和关联表字段过多的情况比如把经常变动的字段和固定字段分开或者把大字段如文本内容、二进制内容单独拆出去。垂直拆分在微服务架构里还有一种表现就是按业务域拆库把用户库、订单库、支付库分开这已经超出单表拆分进入服务化拆分范畴了。实操里有一个很普遍的问题拿不准什么时候该水平拆分、什么时候该垂直拆分。我的经验是优先看数据量的增长曲线和单表行数峰值。单表行数没到千万级别或者还有索引优化空间就先别急着拆分先考虑冷热分离、归档旧数据。一旦单表数据量到了靠优化索引也救不回来的程度水平拆分就是主要手段。垂直拆分更多用在表结构不合理、字段冗余严重的场景或者是服务化改造时顺势做的拆分很少单独为了性能去做垂直拆分。1.3 分片键与路由规则的核心作用分片键也叫分库分表字段是决定一行数据到底该去哪张表、哪个库的依据。选择分片键是整个分库分表设计里最关键的一步选错了后面改起来很难受。分片键必须选择查询条件里高频出现的字段同时它的基数要足够大分布要足够均匀。比如订单表用订单ID作为分片键是因为几乎所有查询都带订单ID或者买家ID但如果你用订单状态作为分片键状态值就那几种数据分布会严重倾斜某些表数据爆炸某些表数据几乎为空。路由规则是根据分片键计算目标库表编号的算法。最常见的路由算法是哈希取模和范围分片。哈希取模就是拿分片键的值做哈希然后对分片总数取模得到库表编号。范围分片则是按照某个字段的区间来分比如按时间按月分表或者按用户ID区间分段。哈希取模的优点在于数据分布均匀缺点是不利于范围查询范围分片的好处是适合按时间归档和范围扫描但可能造成数据热点比如某个月的数据量突然巨大。这里要特别注意路由规则一旦上线扩展分片数时会遇到数据迁移问题。哈希取模在增加分片数量后原有的取模结果会全部变化意味着几乎所有数据都得重新分布。这是很多项目改分库分表时最头疼的一环。所以现在有些中间件支持一致性哈希算法虽然迁移成本低一些但实现复杂度也上去了。设计路由规则时要把未来的数据增长和分片扩展提前考虑进去。1.4 分布式ID与全局唯一约束的挑战分库分表之后单表自增主键彻底没法用了因为每张表各自自增会产生重复ID。分布式ID的核心要求是全局唯一并且尽量保证趋势递增方便索引存储。常见的方案有UUID、号段模式、雪花算法。UUID虽然简单但作为主键时随机性强索引页分裂严重数据插入性能很差所以实际业务表很少直接拿UUID做物理主键最多做逻辑主键。号段模式是每次从数据库申请一批ID号段应用侧自己分配性能不错但引入了额外的数据库依赖。雪花算法是当前最流行的方案由一个时间戳、机器ID、序列号组合成一个64位长整型ID保证在单机内并发递增、跨机器不重复。分布式ID设计里有一个容易被忽略的细节ID长度对存储的影响。在分库分表环境下订单ID往往是核心查询条件也是索引的构成部分。如果用雪花算法生成的19位长整数单表数据量大的时候索引体积会比之前自增ID大不少。所以设计时权衡ID位长和业务范围很重要。另外全局唯一约束不仅仅针对主键还有业务上的唯一键比如订单号。分库后跨库的唯一性校验不能靠数据库唯一索引必须借助全局ID方案或者引入额外的去重存储。2. 中间件原理总体架构名词理顺了再来看中间件。分库分表中间件说白了就是在你的业务代码和数据库之间加了一个代理层它负责拦截SQL、解析语句、计算路由、改写SQL、执行查询、聚合结果。理解这个原理能帮你更好地排查线上问题也能让你对中间件的配置项不至于一头雾水。2.1 中间件的两类实现模型代理层与SDK层分库分表中间件在业界有两种主流实现方式一种是独立部署的代理层另一种是嵌入到应用里的SDK层。代理层中间件是独立运行的比如典型的数据库代理服务。业务应用连接它就像连接一个普通数据库一样代理层再根据你的分片规则把请求路由到后端的真实数据库节点。这种模型的优势在于应用侧几乎不需要改动驱动层面就能兼容数据库迁移、版本升级都可以集中管理。缺点是每次SQL都要经过代理层转发多一次网络跳转性能有损耗另外代理层自己会成为高可用和性能瓶颈点需要单独运维。SDK层中间件则是以jar包的形式嵌入在业务应用里应用直接通过这个SDK访问多个真实数据库节点。这种方式没有额外网络开销性能更好配置也更灵活但应用和中间件耦合度变高更新SDK时所有服务都要跟着发布。实际项目里如果团队不太想引入额外的代理部署又希望性能尽量高SDK层方案用得很普遍。这里插一句我自己的体验没有绝对的好坏全看你的运维能力和团队规模。小团队、数据库节点不多SDK层上手快开箱即用大团队、数据库节点很多且需要统一治理代理层集中管理更省心。很多中间件产品也在往混合方向发展但原理上绕不开这两类。2.2 核心模块SQL解析、路由计算、结果合并中间件的处理链路非常清晰一条SQL进来大致经历四个阶段SQL解析、路由计算、SQL改写、结果合并。SQL解析阶段中间件会把应用传来的SQL语句解析成抽象语法树。它并不像数据库那样做完整执行计划优化而是主要提取几个关键信息要操作的表名、查询条件里是否包含分片键、操作类型是查询还是写入、是否需要排序或聚合。解析的准确性和容错性直接影响后续路由是否正确。有些SQL写法太复杂中间件解析不了就会导致路由失败或只能走全库路由。路由计算阶段拿到分片键的值后按照你配置的分片算法计算出目标库表编号。这里要注意不是所有SQL都带分片键。比如一条不带分片键的查询语句中间件只能进行全库路由把SQL广播到所有分片上去执行然后再合并结果。全库路由的代价很高所以设计表结构和查询条件时要尽量保证核心查询都携带分片键。SQL改写阶段根据路由计算结果把逻辑表名替换成物理表名同时调整SQL里的某些结构。比如你查的是订单表路由到第3号库的订单表_03中间件就会把SQL里的表名从订单表改成订单表_03再把SQL发到对应的库执行。对于带有排序、分页、聚合的SQL改写会更复杂因为它需要对多个分片的结果进行二次处理。结果合并阶段把各个分片返回的数据集汇合起来进行排序、分页、聚合计算等操作。这个阶段特别考验中间件的实现质量因为如果处理不当聚合结果就会出错。比如统计总金额各个分片返回金额中间件要统一累加跨分片去重统计也要在合并层完成。合并结果还需要考虑内存占用数据量大时容易把中间件所在进程的堆内存撑爆所以很多中间件对分页查询做了限制或者特殊优化。2.3 私有协议与全局表、广播表概念分库分表中间件还有一种场景要专门处理某些表数据量不大但每个分片上的业务逻辑都要用到而且数据更新频繁不适合拆分。这种表在中间件里通常称为全局表或者广播表。它的做法是把这张表的相同数据复制到每个分片库中写操作时中间件自动向所有分片同步写读操作则直接在各分片本地读取。广播表很典型的就是配置表、字典表比如订单状态字典、国家地区表。如果分库分表后这些表只放在某一个库其他分片的SQL就无法本地关联必须跨库查询性能很差。广播表机制就是为了解决这个问题设计的。实际操作时要注意广播表的更新策略因为每次更新都要同步到所有分片写放大效应很明显。如果频繁更新建议考虑是否真的适合广播表或者换用缓存方案。中间件在处理SQL时还会识别出一些特殊的内部语法或者注释标记比如通过注释强制指定某个分片、强制走主库或者从库。这些功能在实际业务里很实用尤其是某些数据还没同步完为了保证强一致性的读写场景需要临时把流量路由到主库。理解这些属于中间件功能的延伸但核心原理依旧是建立在解析和路由的基础之上。2.4 分布式事务在分库分表中间件中的实现思路分库分表之后一个业务操作可能涉及多个库的多张表原本数据库本地事务的ACID能力就没法覆盖了。中间件里的分布式事务最终没有银弹都是基于CAP理论做取舍。常见的实现有XA强一致方案、TCC补偿方案、BASE最终一致方案等。XA方案看起来美好能保证强一致但性能和可用性方面的代价太大在分库分表这种高并发场景下很少直接用。TCC方案是把业务操作拆成Try、Confirm、Cancel三个阶段业务侵入性很强对开发来说要求很高。实际项目里最常见的还是最终一致性的方案比如基于可靠消息或者本地消息表来保证业务状态最终一致。以订单支付和扣库存为例订单库和库存库分布在不同的分片。你无法在同一个数据库事务里完成就只能先扣库存然后发消息异步通知订单状态变更。中间件本身不会帮你解决分布式事务的全部问题它更多的是给你提供某种事务补偿机制或者对分布式事务中间件的集成。所以设计分库分表方案时要尽早识别核心链路里哪些操作必须跨库尽早改成可补偿的异步模型而不是在后期硬撑着做分布式事务。3. 核心流程与实操要点原理说了一堆落到实操上很多细节才是要命的地方。这一部分会带你走一遍从规划分片规则、选择分片数量到配置中间件、上线迁移的完整流程。每一步都结合我在项目中真实观察到的坑尽量做到能直接照做。3.1 分片键与分片数量的规划步骤先确定分片键再确定分片数量。很多项目是把顺序搞反了先拍脑袋定了数量再来选分片键导致后面路由不均衡或者扩展困难。分片键选择的实操步骤是这样的把所有核心查询列出来找出哪些字段是高频等值查询条件记录下来。然后评估这些字段的基数和分布用一个实际的存量数据去跑一下统计看各个值之间的数据量差异。如果某个键分布极其不均匀比如大部分数据集中在少数几个值上那就得换键或者采用复合分片键。分片数量的选择要考虑两个维度当前数据量和未来增长速度。举例来说当前订单表有2000万行数据期望单表数据量控制在500万行以内那么至少需要4张表。再考虑未来两年订单量可能翻到8000万那就需要16张表。分片数量尽量设置成2的幂次方或者对后续扩展友好的数量这样在增加分片时可以通过一致性哈希或者特定算法减少数据迁移。有一个实践细节分片数量不宜过多。每个分片都会占用连接数、文件句柄和内存分片太多反而会降低整体性能。有一个项目把订单分成了64张表可是每天新增数据量并不多结果大部分表很小查询时中间件还要维护大量连接明显浪费。分片数量要匹配数据增长的速度而不是越大越好。3.2 中间件的配置要点与实际配置示例以常见的SDK层中间件为例配置的核心是数据源配置和分片规则配置。数据源配置里你要把真实库的地址、账号、密码都配好并给每个库起一个逻辑名称。分片规则配置里要定义逻辑表和物理表之间的映射关系以及分片键和分片算法。一个典型的配置过程大概是这样的先配置两个真实库节点一个名为ds0一个名为ds1。再配置逻辑表订单表它实际分布在ds0的订单表_0到订单表_3以及ds1的订单表_4到订单表_7。分片键是订单ID采用哈希取模算法取模结果是目标表编号和库编号。配置分片算法时要明确告诉中间件取模的基数是多少以及如何从取模结果推导出库名和表名。配置里最容易被忽略的是默认数据源和不需要分片的表。很多时候业务里不仅有逻辑表还有广播表、全局表甚至一些不需要分片的普通表。中间件要支持对这些表的路由到固定库否则一张没配置分片规则的表被业务SQL访问时中间件会直接报错。实际配置时建议一开始就把不需要分片的表统一指向一个默认数据源避免线上突然冒出一条因为漏配规则而失败的SQL。另外在配置SQL方言时不同中间件对数据库特有函数的支持不一样。比如MySQL的某些JSON函数、自定义存储过程中间件解析和改写时不一定能完整支持。上线前要把核心SQL清单过一遍逐个验证在中间件模式下能否正常执行和返回正确结果。3.3 数据迁移与上线切换的常见策略分库分表改造最刺激的阶段就是数据迁移和上线切换。老库老表里的数据要搬到新分片里去还要保证迁移过程中不丢数据不停业务这非常考验方案设计。常用的迁移策略是双写方案。业务应用在改造期间同时写入旧的单库单表和新的分库分表老数据通过离线工具进行批量迁移。迁移完成后对新旧数据进行一致性校验校验通过后再切换读流量最后停掉旧表写入。双写期间的业务逻辑处理要格外小心因为同一笔写操作要保证在两个系统里都成功如果一边成功一边失败就会产生数据不一致。还有一种策略是停机迁移。在业务低峰期或者允许短暂停服的前提下把所有服务停止然后进行全量数据迁移迁移完成后切换应用配置再启动服务。这种方式简单直接但只适合业务容忍停服窗口的场景。做电商、交易系统的同学一般不会接受这种方案所以双写迁移是常态。迁移过程中一个常见坑是全量迁移的批次大小和速度控制。一次性把所有数据都灌入新分片容易造成新库写入锁冲突、主从延迟飙升。我的做法是按主键ID范围分段拉取每段几千行先小规模试跑观察新库的写入延迟和主从状态再逐步加快并发。迁移脚本里还要加入失败重试和断点续传机制否则跑到一半断了要从头再来那会很煎熬。3.4 读写分离与分库分表的组合使用分库分表之后通常还会结合读写分离来进一步提升性能。原理不复杂主库承担写操作从库承担读操作通过主从复制保持数据同步。在分库分表中间件层面往往既支持分片路由也支持读写路由即把同一分片内的读请求分发到该分片对应的从库上。组合使用时的配置问题在于中间件需要知道每个分片的主库、从库对应关系。比如订单表落到ds0ds0对应一个主库和两个从库当SQL是查询时中间件可以轮询或者按权重分配到从库上。这类配置通常在数据源定义里声明每个节点的主从角色。实际操作中有一个很重要的地方主从复制延迟问题。分库分表环境同样存在主从延迟甚至因为数据分片后单库压力依然不小延迟可能更明显。如果刚写完主库立即从从库去读很有可能会读到旧数据。所以中间件通常提供了强制走主库的配置比如在SQL注释里加特定标识或者根据事务状态自动识别。在一致性要求高的场景务必要把这类SQL的读写路由逻辑写明白。我见过一个案例因为没注意主从延迟订单支付成功后页面跳转订单状态显示还是未支付排查到最后就是读写分离配置把状态查询路由到了从库而从库复制延迟了几百毫秒。后来针对订单状态查询直接强制路由到主库问题立刻消失。4. 常见问题与排查技巧实录分库分表中间件上线之后最大的挑战已经不是容量了而是杂七杂八的问题。这里整理几个我在实际项目中高频遇到并且重点排查过的问题这些内容可能比原理部分更有参考价值。4.1 分片键缺失导致的全库路由风暴最常见的性能问题之一就是应用代码里写了一堆不带分片键的查询。比如用户想根据买家昵称去查订单但订单表的分片键是订单ID查询条件里没有订单ID中间件只能把SQL广播到每一个分片去执行。如果分片数量多这条SQL瞬间变成几十次单库查询数据库连接数和负载直接飙高。排查这类问题第一步要看中间件的慢SQL日志和路由日志确认哪些SQL走了全库路由。第二步去业务代码里找到对应的查询方法分析是否真的无法带上分片键。如果业务确实需要按非分片键查询那就得引入额外的索引表或者搜索引擎比如根据买家ID和订单ID建立映射关系先查到订单ID再按分片键查。千万不要指望中间件能对这种查询做多聪明的优化。我自己的经验是在系统设计阶段就要明确限制不带分片键的查询。比如提供DAO层封装时要求所有订单查询方法必须传入订单ID或强制走某个搜索引擎否则在测试环境直接报错。用制度约束比靠中间件拦截要靠谱得多。4.2 数据倾斜问题的识别与处理即使分片键选得不错数据依然可能出现倾斜。比如订单表按用户ID哈希分片如果某些大客户产生的订单量远高于普通用户那么这些用户的订单还是会集中到某一张分片表里形成热点。识别数据倾斜可以在中间件的监控面板里看各分片的QPS和存储量。如果某几个分片的数据量和请求量明显高于其他分片基本可以判定存在倾斜。处理方式一是换分片键二是改用一致性哈希让热点数据能分散到多个分片节点上三是针对特殊的大客户做定制路由比如单独把大客户的订单分到独立分片。一致性哈希也不是万能药它虽然能减少扩展时的数据迁移但热点问题依然可能存在。为了彻底解决热点有的系统会在分片键上再叠加一个随机因子把同一位大客户的订单分散到多张子表但这样会带来管理复杂度和跨表查询。具体取舍还是要看业务场景能不能接受为少数大客户付出额外的架构成本。4.3 分布式查询结果不一致与聚合错误排查分库分表后同一个查询可能会涉及多个分片如果中间件在合并结果时出现bug或者多分片的数据本身就不一致查询结果就跟预期对不上。这种现象比全库路由风暴更隐蔽不容易被发现而且一旦发现往往已经影响到了线上数据报表。比如说要对订单表做分页查询每页20条按创建时间排序。中间件从每个分片各取20条然后在协调节点合并重新排序后再截取前20条。如果某些分片的查询数据已经过期或者排序字段的精度不一致合并出来的结果就可能缺行或者重复。排查这类问题先把中间件的SQL改写日志打开确认每条子SQL去哪个分片执行的再逐个分片手工执行子SQL对比返回数据。另一个容易踩的坑是count查询的汇总。各个分片的count结果加起来能够得到总数但如果数据迁移过程中有重复数据或者有脏数据汇总出来的count就会偏大。所以做完一轮数据迁移后要立刻做数据一致性校验比如抽样比对几个分片的数据总和别等到线上报表突然异常了才回头查。4.4 中间件事务与连接管理的避坑要点中间件在分库分表之后连接管理成了性能瓶颈的高发区。每个分片数据库都需要保持长连接中间件自身会有连接池来复用。如果连接池设置过小高并发时会频繁等待获取连接设置过大又可能压垮后端数据库。我一般建议根据分片数量和预估QPS来倒推连接池大小例如每分片最大连接数设为20到50之间先压测观察再逐步调整。事务问题上分库分表中间件对跨库事务的支持有限。如果一条事务里同时操作了多个分片的数据中间件往往会对每个分片分别开启本地事务但这些本地事务并不会有统一的回滚机制。所以一旦某个分片执行失败其他分片已经提交的数据就成了脏数据。这里要记住分库分表设计的第一原则就是尽量让一个事务只操作一个分片不要在事务里跨界查询或跨界更新。如果非得保证跨库事务就得引入分布式事务中间件但正如前面讲到的复杂度会大幅上升。我的建议是在设计业务逻辑时就尽量以分片键为维度组织事务比如把同一个用户的订单操作都路由到同一个分片这样至少能保证单用户维度内的事务一致性。这个方法虽然不能解决所有问题但能规避掉大多数跨库事务的坑。4.5 中间件版本升级与本地测试模拟分库分表中间件一直在迭代版本升级是躲不开的。升级最怕的不是功能变化而是SQL解析规则和路由算法出现细微调整导致线上SQL的改写结果发生变化。我自己就遇到过升级一个小版本后原先能正常执行的子查询突然解析失败业务侧直接报错。所以升级前一定要准备一套和生产一致的分库分表测试环境把线上真实的SQL调用日志回放一遍。回放过程中重点关注两点第一所有SQL是否还能正确路由到目标分片第二聚合和分页结果是否和旧版本一致。如果没有条件做全量回放至少要把核心业务接口的压测脚本跑一遍确认返回结果符合预期。本地测试模拟也是一个值得投入的方向。用测试容器或者嵌入式中间件把分库分表规则贴在本地数据库环境上然后在开发阶段就让研发人员把SQL直接跑在中间件模式下。很多SQL问题在开发阶段就能暴露出来比到了线上再排查要省太多事。调试中间件时一定要学会看它打印的底层SQL日志那才是真正能定位问题的地方。5. 经验总结与后续扩展的一些思考分库分表这个技术方向设计时多花一分心思上线后就能少操十分心。我见过太多项目前期为了快速上线分片键随便选路由规则图省事结果后面每次大促或者性能压测都要经历一次痛苦的重构。其实分库分表的底层逻辑并不复杂只要抓住数据分布均匀、路由可控、查询尽量带分片键、事务尽量单分片这几个核心原则方向基本不会跑偏。5.1 分库分表和非分库分表方案怎么选需要冷静看待一点分库分表不是银弹很多场景其实不需要走到这一步。数据量还在可控范围单表的查询性能下降主要因为慢查询或者索引失效这时候优先做索引优化、SQL改写和缓存。数据量涨了但读多写少先考虑读写分离可能就顶住压力了。只有当你把读写分离、缓存、归档都用了单库的写入或者存储依然成为瓶颈才值得引入分库分表。从操作成本看分库分表会显著增加代码开发、运维、排查问题的复杂度。如果一个团队只有几个人没有专职DBA也没有成熟的监控体系贸然上分库分表风险会很大。我更建议先用PostgreSQL或者高配置的MySQL实例做垂直拆分或者归档等业务量确实到了必须水平扩展的阶段再引入中间件不迟。5.2 从分库分表到分布式数据库的演进分库分表中间件解决了很多问题但中间件本身还是独立于数据库之外的一层。随着数据量继续膨胀你可能会发现中间件的存在感越来越强但它的能力边界也越来越明显。比如跨分片复杂查询能力弱、分布式事务支持不完美、运维成本居高不下。这时候可以考虑迁移到天生具备分布式能力的原生数据库。原生分布式数据库把分片、路由、数据一致性都下沉到了数据库内核里应用开发时可以更像使用普通数据库。当然这种迁移也要评估兼容性和团队熟练度。我的经验是分库分表中间件适合解决当下的容量和性能问题但如果你预估未来数据规模会再上一个数量级不妨从架构层面思考转向分布式数据库的可能性。5.3 写给新人:学习中间件源码的正确路线很多新人问我怎么才能彻底吃透分库分表中间件。我的建议是先别看太多源码细节而是顺着一条主线去读SQL进来解析器做了什么路由怎么计算SQL如何改写结果怎么合并。把这五个环节串起来你就把握住了中间件的主干。然后再去看具体的数据结构设计比如分片规则如何表达、SQL执行计划如何缓存、连接池如何获取和释放。遇到看不懂的地方不要硬啃去翻中间件自带的底层日志和测试用例。测试用例是很好的学习素材几乎覆盖了各种SQL路由和结果合并的边界情况。把测试用例跑起来打断点看内部数据的流转比盯着文档理解得深刻得多。我自己当年也是通过这种方式把中间件的路由解析和聚合逻辑啃下来的。分库分表这套东西确实是数据库领域里比较高阶的玩法但它并不是什么玄学。掌握了名词体系和中间件原理之后你会发现它本质上就是一类有章可循的架构设计。按这套思路去实践去踩坑去复盘慢慢就能积累出自己的方法论。希望这篇内容能帮你少走一些弯路特别是在分片键选择和数据迁移阶段多想几层后面的日子会好过很多。