Database
数据库分库分表策略

数据库分库分表策略

垂直切分

垂直分表是基于数据库中的"列"进行,某个表字段较多,可以新建一张扩展表,将不经常用或字段长度较大的字段拆分出去到扩展表中。

优点:

  • 解决业务系统层面的耦合,业务清晰
  • 与微服务的治理类似,也能对不同业务的数据进行分级管理、维护、监控、扩展等
  • 高并发场景下,垂直切分一定程度的提升IO、数据库连接数、单机硬件资源的瓶颈

缺点:

  • 部分表无法join,只能通过接口聚合方式解决,提升了开发的复杂度
  • 分布式事务处理复杂
  • 依然存在单表数据量过大的问题

水平切分

当一个应用难以再细粒度的垂直切分,或切分后数据量行数巨大,存在单库读写、存储性能瓶颈,这时候就需要进行水平切分了。

根据数值范围

按照时间或者 ID 区间来切分。按日期将不同月甚至是日的数据分散到不同的库中;将userId为19999的记录分到第一个库,1000020000的分到第二个库,以此类推。

image-20200901113743788

优点:

  • 单表大小可控
  • 天然便于水平扩展,后期如果想对整个分片集群扩容时,只需要添加节点即可,无需对其他分片的数据进行迁移
  • 使用分片字段进行范围查找时,连续分片可快速定位分片进行快速查询,有效避免跨分片查询的问题

缺点:

  • 热点数据成为性能瓶颈。连续分片可能存在数据热点,例如按时间字段分片,有些分片存储最近时间段内的数据,可能会被频繁的读写,而有些分片存储的历史数据,则很少被查询

根据数值取模

采用 Hash 方式取模切分。

按照 Hash 取模分片

优点:

  • 数据分片相对比较均匀,不容易出现热点和并发访问的瓶颈

缺点:

  • 后期分片集群扩容时,需要迁移旧的数据
  • 容易面临跨分片查询的复杂问题

基因分库法

上面的 按照数值取模 的方式只适合于按照一个 Key 的维度来分表,在实际使用中有时候会有一定的局限性,比如业务需要按照两个维度来查询。在电商系统中,对于订单 (Order) 和 购买用户 (Buyer),需要同时支持按照两个维度来查询

  • 用户维度,以用户 ID 作为查询条件,查询用户的所有订单
  • 订单维度,以订单 ID 为查询条件,查询订单详情

以任何维度来作为分表的 Sharding Key 都不合适,因此就有了基因分库法

image-20200901140552712

假设我们将用户的订单拆分成 16 个库(数量必须为 2 的 N 次幂,这里将十进制整数的取模运算转换为了二进制取模),则用户 ID 二进制的后四位为分库基因,在订单 ID 末端加入该分库基因,这样无论是按照用户 ID 取模还是订单 ID 取模,结果都会落到同一个库上。

主键生成策略

UUID

UUID标准形式包含32个16进制数字,分为5段,形式为8-4-4-4-12的36个字符。UUID是主键是最简单的方案,本地生成,性能高,没有网络耗时。但缺点也很明显,由于UUID非常长,会占用大量的存储空间;另外,作为主键建立索引和基于索引进行查询时都会存在性能问题,在InnoDB下,UUID的无序性会引起数据位置频繁变动,导致分页。

结合数据库维护主键ID表

在数据库中建立 Sequence 表。

字段类型说明
idunsigned bigint(20) auto_increment自增主键
stubchar(1) UNIQUE标识是哪个表,唯一索引

需要获取全局唯一 ID 时,执行下面的 SQL

REPLACE INTO sequence (stub) VALUES ('a');
SELECT LAST_INSERT_ID();

方案简单,但是存在单点问题,强依赖DB,当DB异常时,整个系统都不可用。配置主从可以增加可用性,但当主库挂了,主从切换时,数据一致性在特殊情况下难以保证。另外性能瓶颈限制在单台MySQL的读写性能。

Twitter 的 Snowflake 分布式自增 ID 算法

Twitter的snowflake算法解决了分布式系统生成全局ID的需求,生成64位的Long型数字,组成部分:

image-20200901120032235

  • 第一位未使用
  • 接下来41位是毫秒级时间,41位的长度可以表示69年的时间
  • 5位datacenterId,5位workerId。10位的长度最多支持部署1024个节点
  • 最后12位是毫秒内的计数,12位的计数顺序号支持每个节点每毫秒产生4096个ID序列

优点:

  • 毫秒数在高位,生成的ID整体上按时间趋势递增
  • 不依赖第三方系统,稳定性和效率较高,理论上QPS约为409.6w/s(1000*2^12),并且整个分布式系统内不会产生ID碰撞;
  • 可根据自身业务灵活分配bit位

缺点:

  • 强依赖机器时钟,如果时钟回拨,则可能导致生成ID重复。

参考文献: