Distributed System 分布式系统 Sharding 数据切分
定义
数据切分(Data Partioning)是将大的数据库切分为多个小数据库
数据达到一定量后,水平扩容往往比垂直扩容更便宜
切分方法
水平切分(Horizontal Partitioning) / 范围切分(Range Based Sharding)
- 根据数据范围进行切分,例如 ZIPCode 小于 1000 的一个表,大于 1000 的另外一个表
问题
- 如果切分的范围选择不小心,就会出现分布不均衡
垂直切分(Vertical Partitioning)
- 根据数据的特征进行切分,例如用户的头像信息在一个数据库,用户的好友列表在另一个数据库,图片在第三个数据库
问题
- 如果应用数据增长,可能需要将一个特征的数据库重新切分,例如一台数据库服务器不可能处理 10B 的图片数据
地址簿切分(Directory Based Partitioning)
- 一种松耦合(Loosely Coupled)的方式是创建一个查找服务(LookUp Service),要找到数据切分的时候,可以通过查找服务,找到对应的服务器
- 这种方法可以在添加新的服务器时,不会影响应用
切分标准(Criteria)
- Key 或 基于 Hash 切分
例如有 100 台服务器,那么 Hash 函数可以是 ID % 100
不过如果增加一台服务器,会导致数据重分布(可以用一致性哈希解决) - 列表切分(List Partitioning)
每个分区被分配一个 Key 列表,新纪录通过判断哪个分区包含了它的 Key 来插入
例如,北欧区包含了北欧的所有国家(Key列表),对应国家的用户记录会插入北欧区 - 轮询切分(Round-Robin Partitioning)
所有分区形成一个环,然后顺时针取下一个,用于插入新纪录 - 组合切分(Composite Partitioning)
组合多种切分方式
常见问题
大部分问题都是因为多个表或者同表多行不在一台设备上
Joins 操作和反范式化(Denormalization)
多表 Join 对于数据分布在不同服务器上会很慢
反范式化(Denormalization)
把数据在不同的地方多放几份,以加快数据检索速度
- 常见做法
- 存一些派生数据:把需要频繁重复计算的结果存起来,例如在一对多关系中,把“多”的数量作为“一”的属性存储起来
- 预先连接(pre-joined)生成汇总表:把需要频繁join的表提前join好
- 采用硬编码值:把依赖表中的常量值(或者不经常变化的值)直接硬编码到当前表中,从而避免join操作
- 把详情信息纳入主表中:对于数据量不大的详情表,可以把全部/部分详情信息塞到主表中,以避免join操作
- 代价
- 会出现数据一致性问题
引用完整性(Referential Integrity)
大多数 RDBMS 在多台数据库服务器上不支持跨数据库的外键(Foreign Keys)约束
- 这个只能由应用自己来保证,需要跑一些定期的 SQL 来清理一些已经被删除的空引用
重均衡(Rebalancing)
- 很多原因导致数据分布不均衡,需要重新均衡, 例如一个 ZipCode 下面的很多地点,另一个却很少
- 如果直接做拆分均衡,那么必然会停机(可以使用基于地址簿切分(Directory Based Partitioning)来解决)