分库分表后出现热点分片和数据倾斜怎么办?
简化版
热点分片是请求集中,数据倾斜是数据量集中。解决思路包括重新评估分片键、引入散列因子、热点数据单独拆分、逻辑分片迁移、读写分离、缓存保护、限流降级和按时间/业务做冷热隔离。
详细版
常见原因:
- 分片键基数低,如按地区、状态、类型分片;
- 大客户或超级用户数据过多;
- 时间 Range 导致新数据集中写最新分片;
- 热门商品、热门活动导致请求集中;
- 分片数量或映射关系规划不合理。
治理手段:
- 数据倾斜:迁移大分片、拆超级租户、增加逻辑分片;
- 读热点:缓存、多级缓存、本地缓存、读副本;
- 写热点:加随机后缀、分桶写入、异步削峰、限流;
- 时间热点:时间分片内再 Hash;
- 运维治理:监控每个分片 QPS、RT、容量、慢查询和错误率。
面试时要区分读热点、写热点、容量倾斜,因为它们的解决方案不同。
完整版教学
一、热点和倾斜不是同一件事
数据倾斜指某些分片数据特别多。比如 64 个分片中,大部分只有 1000 万行,某个分片有 2 亿行。它会导致该分片索引更大、备份更慢、DDL 更危险。
热点分片指某些分片请求特别多。它的数据量未必最大,但 QPS、CPU、锁竞争或 IO 明显高于其他分片。比如某个热门商品秒杀,所有库存更新都打到同一行或同一分片,这就是热点。
两者可能同时出现,也可能单独出现。治理前要先看监控:是容量高,还是 QPS 高,还是写锁冲突高,还是慢查询高。诊断错了方向,优化会很尴尬。
二、分片键低基数最容易造成倾斜
如果按性别、状态、城市等级、订单状态分片,分片数量天然有限,而且分布不均。例如订单状态里“已完成”可能占绝大多数,“待支付”只占一小部分。按状态分片会让已完成分片巨大无比。
分片键应该基数高、分布均匀。user_id、order_id 通常比地区、状态更适合做 Hash 分片。但即便使用高基数字段,也要注意超级用户、大商家、大租户。一个头部商家可能贡献普通商家的上万倍订单量,按 seller_id 分片时就会成为大分片。
三、超级租户和大客户要单独治理
多租户系统常遇到“长尾租户很多,头部租户巨大”的情况。如果所有租户都按 tenant_id Hash,某个超级租户仍然只能落在一个分片,无法被打散。
常见做法是识别超级租户,把它们单独分库,或者对超级租户内部再按二级键拆分。例如普通租户按 tenant_id 分片,大租户按 tenant_id + user_id 或 tenant_id + order_id 再拆。路由层通过租户配置判断走普通规则还是专属规则。
这种设计会让路由更复杂,但比让一个分片被大客户拖死要可靠。
四、写热点要用分桶和削峰思路
写热点最典型的是计数、库存、热门活动报名。所有请求都更新同一行,即使分库分表也没用,因为热点在业务键上。
一种办法是分桶写入。比如商品浏览数不更新一行,而是拆成 100 个桶:
counter_key = product_id + random(0, 99)
写入随机落到不同桶,读取时汇总 100 个桶。这样牺牲一点读取成本,换取写入并发能力。库存场景也可以做库存分段,但要小心超卖,需要预扣、校验和回收机制。
削峰也很重要。秒杀类请求可以先进入队列,异步串行或分批处理,前端展示排队状态。不要让所有写请求直接冲击数据库。
五、读热点要用缓存和副本,但要防止缓存击穿
读热点通常可以通过缓存、多级缓存、本地缓存、CDN、只读副本解决。但热点 Key 如果失效,所有请求会瞬间打到数据库,造成击穿。因此热点数据要配合互斥重建、逻辑过期、后台刷新、热点探测和限流。
如果某个分片整体读压力高,可以迁移逻辑分片到新实例,或者增加只读副本承接查询。这里要求路由层能观察每个分片的负载,并支持按逻辑分片迁移。
六、热点治理要先定位是读、写还是容量问题
热点分片的治理不能一上来就扩容。读热点、写热点、容量倾斜的表现和解法完全不同。读热点通常表现为 QPS 高、缓存命中率下降、数据库读 IO 高,可以用多级缓存、只读副本、热点 Key 本地缓存、请求合并解决。写热点表现为行锁冲突、更新等待、事务延迟高,要用分桶、队列削峰、异步聚合或业务限流。容量倾斜表现为某些分片数据远大于其他分片,要做逻辑分片迁移、大客户拆分或重新规划分片键。
定位时要看分片维度的监控:每个分片的 QPS、TPS、P99、慢查询、连接数、锁等待、磁盘使用、Buffer Pool 命中率、主从延迟。没有分片级监控,就只能凭感觉猜热点,处理效率会很低。
热点还要看时间维度。某些热点是长期大客户导致,适合独立拆分;某些是活动期间短时爆发,适合限流、队列和缓存;某些是新数据写入集中,适合 Range 内 Hash 或预分桶。
七、热点拆分要考虑读合并和一致性
分桶是常见写热点方案,但它把一次写分散成多处写,也会让读变复杂。例如计数器拆成 100 个桶后,写入很快,读取总数要汇总 100 个桶。对于实时性要求不高的计数,可以异步汇总到缓存;对库存这类强约束数据,不能简单随机分桶,否则可能超卖。
超级租户拆分也要小心路由复杂度。普通租户按 tenant_id 路由,大租户按 tenant_id + user_id 二级拆分,这意味着路由层要支持特殊规则,迁移、备份、监控也要识别特殊租户。否则解决了一个热点,又制造了长期维护黑洞。
面试里讲热点治理时,最好给出“先监控定位,再按类型处理,最后用迁移和预案固化”的闭环。热点不是一次性修完的问题,业务增长、活动营销、大客户接入都会不断改变流量分布,所以分库分表系统必须具备持续再平衡能力。
八、常见误区与追问
这道题要紧扣「分片热点与数据倾斜」本身回答,不能把它混成泛泛的分库分表套话。面试官通常不是只听定义,而是看你能不能把适用场景、关键流程、失败边界和工程取舍串起来,尤其要说明拆分边界、路由规则、扩容迁移、跨库查询和一致性兜底。
| 回答层次 | 要讲清的内容 | 容易漏掉的边界 |
|---|---|---|
| 核心结论 | 热点是访问集中,倾斜是数据或请求分布不均,核心是识别热点键并通过拆桶、迁移、缓存和限流打散压力 | 不要停在名词解释 |
| 流程机制 | 采集分片 QPS 和容量 -> 识别热点 key 或大租户 -> 读热点加缓存 -> 写热点拆桶聚合 -> 迁移倾斜分片 -> 持续监控回归 | 要说清触发点、状态变化、确认点和失败兜底 |
| 工程取舍 | 100 万请求里 60 万都落到同一个 user_id 分片,即使总 QPS 没超,单分片也会先被打爆 | 分库分表能扩展容量和吞吐,但会带来路由、事务、Join、唯一约束、扩容和运维复杂度 |
分片热点与数据倾斜 面试拆解:
1. 采集分片 QPS 和容量
2. 识别热点 key 或大租户
3. 读热点加缓存
4. 写热点拆桶聚合
5. 迁移倾斜分片
6. 持续监控回归
记忆钩子:先给结论,再拆流程,再讲数字例子和失败边界;回答「分片热点与数据倾斜」时要围绕题目问法收束,不要把相邻概念堆成一段没有重点的名词清单。
- 误区:分片数量越多越不会热点。 如果路由键本身集中,再多分片也可能让热点落在少数分片上。
- 误区:数据均匀就一定请求均匀。 少量热门用户、商品或商户可能贡献大部分请求。
- 误区:热点都能靠缓存解决。 写热点、计数器和强一致库存还需要拆桶、队列化或限流。
- 追问:怎么发现倾斜? 看单分片 QPS、慢查询、存储量、CPU、锁等待和 Top key。
- 追问:大客户数据怎么拆? 按租户内二级维度继续拆分,或为大租户单独分片。
- 追问:写热点怎么处理? 拆成多个桶写入,异步聚合,并控制一致性要求。
九、加强记忆
热点治理先分类:数据多是倾斜,请求多是热点;读多用缓存和副本,写多用分桶、队列和限流;大客户要单独拆,时间热点要 Range 内再 Hash。分库分表不是一次性动作,后续必须靠监控、迁移和热点治理持续维护平衡。