数据分片

分片(Sharding)把一份逻辑数据集分布到多台机器,目的是扩展容量或分担负载。它不只是路由公式,还会改变事务、查询、迁移和运维的边界。

分片键通过路由映射到不同分片

分区、分片与复制的区别

单实例表分区(Partitioning)把表拆成较小的管理单元,可以帮助分区裁剪、归档和维护,但不一定增加机器。分片通常把子集放到不同机器。复制(Replication)给同一份数据增加副本,主要服务于容错或特定读取扩展。

三者可以同时存在:每个分片有副本,每个数据库内部也可以分区。不能因为增加了读副本,就认为单个写入主节点的热点已经被解决。

判断是否值得承担分布式复杂度

观察限制来自存储、IO、CPU、写日志、锁竞争,还是单个热点。查询和索引调整、连接池、批处理、纵向扩容、缓存或读副本可能已经足够。

只有当目标负载、增长、恢复时间或地域约束确实超出单机方案时,再引入分片。某个固定 GB 或 QPS 数值不是适用于所有数据库的分片门槛。容量之外,备份、恢复和迁移时间也可能是约束。

先选键,再选分布规则

分片键(Shard Key)决定数据的归属单元。好的键既能分散数据量与访问量,也能让常用操作落在少数分片。键的基数(Cardinality)很高不代表流量均匀;某个实验仍可能独占大部分写入。

规则优点代价
范围(Range)范围查询和相邻数据管理直观。单调增长的时间或编号可能把新写入集中到末端。
哈希(Hash)通常更容易分散大量不同键。失去范围局部性,扩容方式需要额外设计。
目录(Directory)显式映射可以迁移大租户并调整放置。路由元数据需要高可用、缓存和版本管理。

AWS 的分区键设计说明强调活动量分布,而不只是记录数量。

热点需要改变负载单位

如果 experiment_id=42 贡献了一半写流量,对这个编号再做均匀哈希也只会得到一个结果。可把日志分成 (experiment_id, time_bucket, subshard),让一个大实验拥有多个可独立路由的写入单元。

代价是查询一个实验时需要读取多个分片并合并。子分片数量、时间桶边界和路由元数据应能被查询端发现;盲目加随机后缀却没有读取计划,会让写入变快、读取失控。

跨分片读取与事务

跨分片查询需要扇出(Fan-out)和结果聚合。全局最近 20 条可以让各分片返回局部候选再归并,但深分页、过滤和某个分片超时会使语义更复杂。二级索引可以另建访问路径,却需要讨论更新延迟与一致性。

跨分片事务可能使用分布式提交协议;也可以重新安排数据归属,使关键不变量留在一个事务边界内。Saga 等补偿流程适合可撤销的业务步骤,但不等价于单个原子事务。全局唯一编号也不自动保证全局业务唯一性。

在线扩容是一段迁移协议

一种迁移思路是:准备目标分片 → 搬迁存量快照 → 追赶增量变化 → 校验 → 切换路由版本 → 保留回滚窗口 → 清理旧副本。不同数据库会采用不同协议,但每一步都要明确读写由谁负责。

直接复制数据后立刻改路由,可能漏掉复制期间的新写入。没有协调规则的双写也可能只写成功一侧。迁移期间需要处理重复、乱序、墓碑(Tombstone)与旧路由请求,并通过写入版本或路由代次防止旧节点继续承诺写入。

托管分片仍然需要数据建模

数据库可以替你实现物理拆分和再平衡,但不能替你选择正确的访问单元。热点键、跨分区事务和二级索引仍然可能决定成本与性能。也不能假定所有托管数据库都使用相同的哈希环算法;应以产品文档描述其放置和路由机制。

关联与来源

数据模型 · 一致性哈希 · CAP · 容量估算

学习入口:Hello Interview · Sharding(已登录核对书面章节)。迁移步骤与训练日志例子是独立的工程推导。