连载中 13/16

分片基因:把路由信息写进 ID

2026-06-11 · 4644 阅读 · 0 评论 · 0 赞

订单号查不到订单的尴尬

老王的订单业务量起来了,DBA 动手分库分表:16 个库、每库 16 张表,共 256 张,按 user_id 取模路由。拆完顺一阵子,直到客服接入工单:用户报了个订单号,系统拿着号去查——查哪个库?订单号是雪花 ID,里面只有时间和机器信息,没有 user_id,路由信息是空的。要么全库广播问一遍,要么先查路由表。两条路都有代价,这一篇讲第三条路。

二次路由的三条路

广播查询:拿着订单号把 16 个库全问一遍。简单粗暴,浪费巨大——每次单点查询变成 256 张表的全网扫,高峰期直接打爆所有库。只配当兜底,不配当日常。

路由表/索引表:单独建一张 order_no 到 user_id 的映射表,先查映射再路由。查询翻倍,映射表本身也是大表,还要维护一致性(订单创建失败要回滚映射)。能做,但每条链路都多个绊子。

基因法:发号的时候就把路由信息埋进 ID——让 ID 自己会认路。

基因法的位设计

原理一句话:把 user_id 的路由哈希值截取低位几位(比如 8 位),作为「基因」嵌进订单 ID 的固定位置。订单落库时,既可以用 user_id 路由,也可以直接用订单 ID 的基因位路由——因为基因就是 user_id 路由值的拷贝,两种路由结果必然一致:

user_id 路由基因:hash(user_id) 低 8 位 = 0b10110100
订单 ID 位分配(示例):
[ 1 符号 ][ 40 时间戳 ][ 8 workerID ][ 8 基因位 ][ 7 序列 ]
订单号查库:订单ID 基因位 0b10110100 直接取模路由
用户查单:user_id 基因 0b10110100 取模路由
两条路落进同一张表,天然一致

客服拿订单号查单,中间件(ShardingSphere 之类)配一个自定义分片算法,解析 ID 的基因位直接定位库表——一次路由,零额外查询。用户查自己的单,走 user_id 路由,还是同一张表。商家查自己的所有订单(跨用户的场景),才需要ES 或异构索引兜底——基因法解决的是「已知 ID 或已知用户」的精准查,不是复杂维度的搜索。

发号侧怎么嵌

雪花模式:取号接口加一个参数(业务方传入基因值),发号器把序列位砍掉几位腾出基因位。号段模式更简单:各业务取号段时把基因拼在低位,或者干脆每个基因一个 biz_tag——基因值有限的场景(如分 256 张表,基因就是 0-255),直接给每个基因一个独立号段,号段天然带基因,连位运算都省了。

关键纪律只有一条:嵌入基因必须与 user_id 的路由哈希同源——同样的哈希函数、同样的位数、同样的取模规则。发号服务和分片中间件分属两个团队时,这条规则最容易断,一断就是数据路由分裂的大事故。

明码标价的代价

基因法不是免费的:

分片规则焊死在 ID 里:日后扩容(256 表变 1024 表)或换路由算法,存量 ID 里的基因还是老规则的产物,新老 ID 路由并存,迁移方案要特殊设计。这是最大的隐性债,选基因法等于签了一份长期合约。

位数挤占:64 位总量恒定,基因位每加一位,序列位就少一位,单机单毫秒吞吐折半。基因要几事先算清,别拍脑袋。

业务耦合:这个 ID 挪去别的业务用,基因位就是无意义的包袱——带基因的 ID 适合「专用」,不适合「通用」。

方案额外查询额外存储主要风险
广播查询N 倍放大无高峰打爆全库
路由映射表多一次一张大映射表双写一致性
基因法零无规则焊死、位数挤占

小结

基因法一句话:在 ID 里预埋路由基因,换来零成本的二次定位;同源纪律是生命线,规则焊死是长期债。分库分表场景值得上,通用发号场景别乱上。老王的订单号从此自带门牌号,客服查单一秒定位。但新的问题悬在头顶:发号服务自己挂了怎么办?全公司都依赖它,它可是单点中的单点——下一篇讲高可用与降级。

☕
503

10 年全栈工程师 · 503咖啡馆主理人

#分布式ID#分片基因#分库分表#路由#ShardingSphere

评论 (0)

热门推荐

连载中 11/22

主从搭建实操:从零配出一主两从

光讲原理不过瘾?手把手搭一主两从:my.cnf 六个参数、复制账号、GTID、CHANGE REPLICATION SOURCE TO、SHOW REPLICA STATUS 验收,附翻车排查清单。

#MySQL#主从复制#GTID#主从搭建#高可用
2026-05-07 · 10101 阅读 · 0 评论 · 0 赞
连载中 16/22

连接池:HikariCP 参数与连接风暴

连接池不是越大越好:8 核机器配 1000 连接反而更慢的数学原理,HikariCP 四个必调参数,maxLifetime 与 wait_timeout 的隐形陷阱。

#MySQL#连接池#HikariCP#maxLifetime#连接风暴
2026-05-10 · 9872 阅读 · 0 评论 · 0 赞
连载中 4/16

缓存穿透:恶意 ID 打穿 MySQL 的四道防线

请求的数据在缓存和数据库里都不存在时,缓存形同虚设。聊聊参数校验、空值缓存、布隆过滤器、限流熔断四道防线的原理与组合打法。

#Redis#缓存穿透#布隆过滤器#高可用
2026-05-16 · 9293 阅读 · 21 评论 · 287 赞