分片键选得不好,数据热点和倾斜几乎是必然结果根源不在数据量,而在于字段的分布特征与分片算法不匹配。
分片键设计不合理为什么会直接制造热点
很多人把数据热点当成高并发问题,把数据倾斜当成存储问题,但实际项目中这两者经常同时出现,而且病因高度重合。
数据热点和倾斜不是一回事,但总是绑在一起
数据热点指少数几个分片承载了远超平均水平的读写请求,数据倾斜指各分片上的行数、字节数或索引大小出现明显不均,前者看流量,后者看容量。
| 现象 | 关注维度 | 常见表现 |
|---|---|---|
| 数据热点 | QPS / TPS | 某个节点CPU持续飙高,其他节点空闲 |
| 数据倾斜 | 行数 / 磁盘占用 | 某个分片存储量是其他分片的数倍 |
热点不一定伴随倾斜,倾斜也不一定立刻产生热点,但分片键选错时,多数情况下两者会互相放大:数据多的分片更容易被查询命中,查询多又进一步拖慢该分片,最后形成单点瓶颈。
哪些字段最容易踩坑
- 单调递增字段:订单ID、自增主键、时间戳,这类字段写入时总是落在同一个分片,因为新数据永远排在后面。
- 低基数字段:状态、类型、性别、是否删除,字段值只有几种或几十种,分片数量一多,很多分片根本分不到数据。
- 业务聚集字段:店铺ID、城市、品类,如果头部商户的订单量占全平台较大比例,按商户分片会让少数几个分片被塞满。
- 有明显节假日效应的字段:按日期分片时,大促当天分片QPS可能是平时的数倍,而其他日期分片很闲。
订单表分片键用什么字段好?这些场景最典型
订单表是分布式数据库里最常被讨论的场景,也是分片键翻车最多的地方,因为订单表同时具备写多、读多、范围查询多、单点查询多等特征。
订单表为什么总是热点重灾区
订单业务天生带有头部集中趋势,少数卖家可能贡献大部分订单,少数买家可能频繁下单,如果直接拿卖家ID做分片键,大卖家的分片很快成为热点;如果拿买家ID做分片键,刷单或批量采购的买家同样会造成倾斜。
一个更隐蔽的问题是:订单主键通常是自增ID,直接用自增ID做分片键,所有新写入都压到最后一个分片,写入热点非常明显,即使后面改用雪花ID,如果没做哈希,时间递增特征仍然会让写入集中在尾部。
一个可验证的排查步骤
实际项目中,可以按下面顺序快速判断订单表分片键是否已经造成倾斜:
- 登录分布式数据库管理台,查看各分片的行数统计,行数相差数倍通常说明倾斜已经存在。
- 查看各分片的QPS曲线,如果某几个分片QPS明显高于均值,说明存在热点。
- 查看慢查询日志,如果大量慢查询集中在特定分片,说明该分片负载过重。
- 用
SELECT COUNT() FROM orders WHERE shard_key = ?对候选字段做分布抽样,观察不同取值的行数差异。
hash分片和range分片哪个更容易热点
这个问题没有绝对答案,取决于字段本身的分布。
- range分片更容易在单调递增字段上产生热点,因为写入永远落在最后一个区间,但它对范围查询友好,相邻数据在物理上更近。
- hash分片能打散单调递增字段,让写入均匀分散,但会破坏范围查询的局部性,导致跨分片查询增多。
所以如果订单表的主要查询模式是单点查询和最近N条查询,hash分片通常更安全,如果业务大量依赖时间段范围扫描,range分片更合适,但需要接受写入热点风险,并通过二级分区或拆分时间粒度来缓解。
分片键怎么选才能避免数据倾斜?从四个维度评估
分片键设计不是拍脑袋选一个字段,而是要把字段放到四个维度里过一遍,这套评估方法对多数分布式表都适用。
高基数不等于均匀
字段基数高只代表不同取值多,不代表分布均匀,比如用户ID基数很高,但少数大客户可能产生大量数据,行业共识认为,判断分片键是否合适,核心指标不是基数本身,而是各取值的数据量方差。
实操方法:对候选字段执行SELECT field, COUNT() FROM table GROUP BY field ORDER BY COUNT() DESC LIMIT 20,观察前20个取值的行数是否已经占全表较大比例,如果前几十个取值就吞掉大部分数据,说明该字段存在头部集中,不适合直接做分片键。
查询模式决定分片键方向
分片键选错还有一个常见原因:只考虑写入均匀,忽略了查询路由。
- 如果90%的查询都带
条件,那么用user_id
user_id做分片键能让大多数查询只落到一个分片,避免全分片扫描。 - 如果查询条件分散在多个字段,单一分片键会导致大量跨分片查询,这时可以考虑复合分片键,或者引入映射表。
复合分片键的实操方法
复合分片键通常由两个字段拼接,例如user_id + order_time,具体设计时需要注意顺序:
- 把查询中最常用的等值字段放在前面。
- 把范围查询字段放在后面。
- 避免把低基数字段放在最前面,否则前面几个固定值会让分片数量受限。
以订单表为例,如果业务主要是买家查询自己的订单,且经常按时间过滤,可以使用buyer_id + create_time作为复合分片键,写入时同一买家的订单会路由到同一分片,时间维度在分片内部保持有序。
监控倾斜率的可操作指标
设计阶段很难100%避免倾斜,上线后必须持续监控,实用的指标包括:
- 分片行数比:最大分片行数除以平均分片行数,多数情况下比值超过3就需要关注。
- 分片QPS比:最大分片QPS除以平均分片QPS,超过2通常意味着热点已经影响性能。
- 分片磁盘使用率差异:如果个别分片磁盘使用率远超其他分片,说明数据倾斜已经开始挤压硬件资源。
- 写入延迟分位数:观察P99延迟是否集中在特定分片的写入操作上。
分片键设计不合理带来的扩容成本与国内分布式数据库地域差异
分片键出错不只是性能问题,还会直接转化成扩容成本和运维复杂度,国内分布式数据库在这方面的表现也有明显地域和产品差异。
为什么分片键不合理会推高扩容成本
扩容时通常需要迁移数据,如果分片键本身存在倾斜,迁移过程会变得非常痛苦:
- 倾斜分片数据量过大,迁移耗时远超其他分片,整个扩容窗口被拖长。
- 热点分片迁移时如果同时承载高QPS,容易触发双倍性能压力。
- 迁移完成后如果分片键不变,倾斜依旧存在,扩了容量却治不了根。
很多团队在扩容时才发现,分片键设计不合理带来的成本比最初节省的设计时间高出数倍,这里说的成本包括机器成本、人力成本以及业务中断风险。
国内分布式数据库分片键设计有哪些地域差异
国内分布式数据库部署经常跨地域,分片键如果选择地域相关字段,例如region、city,会导致数据向北京、上海、深圳等业务集中区域倾斜。
- 如果业务主要分布在华东,按
city做分片键,上海分片数据量可能远超其他城市分片。 - 跨地域部署时,分片键还应考虑地域间的网络延迟,把高频访问的数据分片放在离用户更近的机房,能显著降低响应时间。
- 对于多地域活多活的架构,分片键还需要考虑全局唯一性,避免不同地域写入冲突。
因此国内分布式数据库分片键设计不能只考虑逻辑分布,还要结合机房部署、地域带宽成本和访问延迟一起评估。
分片键是分布式表的物理地基,选错字段,热点和倾斜会随着数据量增长被持续放大,最终拖垮整个集群,反过来,只要在字段基数、分布方差、查询模式和写入模式之间找到平衡点,大多数热点和倾斜问题都可以在设计阶段被提前消除。
Q&A
分片键设计不合理导致数据热点怎么排查?
先看分片行数统计,找出最大分片和平均分片的行数比,再看各分片QPS曲线,找出峰值差异,然后对候选字段做GROUP BY分布统计,观察头部取值的行数占比,最后结合慢查询日志,确认慢请求是否集中在特定分片,这套流程不需要额外工具,用数据库自带的监控和SQL就能完成。
订单表分片键用什么字段好?用买家ID还是卖家ID?
这取决于业务查询主体,如果主要服务买家查询自己的订单,用买家ID做分片键更合适,因为大多数查询能直接路由到单个分片,如果平台主要服务卖家管理订单,卖家ID更合理,但要注意头部卖家可能导致倾斜,可以配合买家ID做复合分片键,或者对卖家ID做哈希后再分片,打散头部集中趋势。
分片键已经倾斜了,能在线修改吗?
可以在线修改,但过程不是简单地改字段,通常需要新建一张按新分片键分布的目标表,然后通过在线迁移工具将数据逐步从旧表同步到新表,切换时短暂停写或使用双写方案,最后将读流量切到新表,整个过程需要保证旧分片数据不会丢,同时不能让热点分片在迁移期间承载过高压力,多数分布式数据库都提供在线分片调整工具,但操作前必须先在测试环境完整演练迁移和回滚流程。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/639385.html





