← 返回分布式系统
🗄️ 分布式存储 · 面试高频

数据分片与分区

当单库单表撑不住时,要把数据水平拆到多台机器。怎么拆、按什么拆、拆完怎么再平衡,决定了系统的扩展天花板。

🧩 一、什么是分片(Sharding / Partition)

把一张大表按某种规则切成多份,每份叫一个分片(shard / partition),分布到不同节点。每个节点只负责一部分数据,整体突破单机容量与性能上限。

💡
垂直拆分 vs 水平拆分:垂直拆分是按"列/业务"分库(用户库、订单库);水平拆分(即分片)是按"行"把同一张表的数据分散到多机。面试里说的"分库分表"通常指水平分片。
分片的核心目标:① 突破单机存储上限;② 突破单机算力上限(查询/写入并行);③ 故障隔离(一个分片挂不影响全局)。

🗺️ 二、四种分片策略

范围分片 A–M N–Z a–m 哈希分片 hash%3=0 =1 =2 列表/枚举 华北 华南 西部
策略规则优点缺点适用
范围分片按 key 区间切(如 user_id 0–1kw)范围查询快、易扩展易热点(最新区间最忙)时序/日志、按时间
哈希分片hash(key) % N分布均匀、无热点范围查询需扫多分片通用 KV、用户数据
列表/枚举按枚举值定向(地区/租户)业务语义清晰易不均、需人工规划多租户、地域隔离
地理分片按地理位置就近降低延迟跨区查询复杂全球化部署
🔗
与一致性哈希的关系:哈希分片的"节点增减"痛点,正是一致性哈希要解决的。生产上常用"固定槽位(如 Redis 16384 slot)"替代裸取模。

🔑 三、分片键(Shard Key)怎么选

分片键选错,再好的策略也救不回来。它决定数据分布、查询路由和扩展能力。

高基数(取值多)
基数太低(如"性别"只有 2 个值)会导致分片极少、无法打散。优先选 user_id、order_id 这类高基数字段。
查询高频携带
大部分查询都应带上分片键,否则要"广播"到所有分片再聚合,丧失分片意义。
避免单调递增
用自增 ID 做范围分片会产生"永远写最后一单片"的热点;可用雪花 ID(见分布式ID)或哈希打散。
尽量不变
分片键一旦写入不宜变更,否则要跨分片迁移整行数据。

🔥 四、热点与数据倾斜

即使选了哈希,也可能因"某 key 被疯狂访问"(如爆款商品、大 V 用户)造成单分片热点。

⚠️
常见解法:① 热点 key 加随机后缀(写时分散、读时聚合);② 本地缓存 + 限流;③ 对超热 key 单独复制多副本做读负载均衡;④ 提前做数据预判与预分片。

⚖️ 五、再平衡(Rebalancing)

集群扩缩容、节点上下线时,要把分片重新分布到新拓扑上,这个过程叫再平衡。目标是:迁移量最小、不停服、不丢数据。

再平衡三原则
① 尽量均匀:各节点承载相近分片数;② 最小化迁移:借助一致性哈希/槽位,只动必要分片;③ 自动化且可回滚:多数系统(Kafka/Cassandra)由控制器自动调度,迁移按"先复制再切换"保证安全。

🎯 六、面试高频追问

分库分表后,跨分片查询/事务怎么办?
聚合查询靠中间件(如 ShardingSphere)并行查各分片再汇总;跨分片事务用分布式事务(TCC/Saga/消息最终一致)兜底,尽量避免。
分片数和节点数一定要相等吗?
不一定。常见做法是"分片数 > 节点数",一个节点承载多个分片,扩节点时只需把部分分片搬过去,调度更灵活(Kafka 的 partition 即如此)。
分片键和唯一 ID 的关系?
全局唯一且最好带分片信息的 ID 能简化路由。例如把分片号编入 ID 高位,或通过 ID 反查分片,避免额外查路由表。

延伸阅读:一致性哈希 · 数据复制 · 分布式ID生成