一 分库分表场景
- 单库数据量太大:单库所在服务器磁盘空间受限、IO 瓶颈等
- 单表数据量太大:增删改查速度慢、索引膨胀等等
遇到这些问题之后,就需要考虑去做分库分表了
二 分库分表的策略
垂直切分
垂直切分可以同时作用于库和表,即垂直分库和垂直分表。垂直分库就是根据业务的特性,将关联程度不同的表放到不同的库中。它的思想与微服务的思想是类似
例如:对于一个电商系统来说,库中可能会有用户表、商品表、订单表、反馈表等,我们就可以将这些表分到三个库中
- 垂直切分的优点
- 消除库中存在的业务表耦合,使数据表之间的关系更加的清晰
- 将数据库的连接资源、单机硬件资源隔离开,更利于业务的扩展
- 垂直切分的缺点
- 表与表之间很难做到完整的 JOIN,只能通过多次查询的方式聚合数据
- 查询多个表会将单表事务升级为分布式事务,实现难度大大增加
- 仍然可能会存在单表数据量过大的问题
水平切分
经典的水平拆分规则:
- 按照时间区间或者自增 id 来切分:这比较好理解,就是数据分段存储,例如100万行数据一个表,或者一个季度的数据切分为一个表。这样做的优点是简单、单表数据量可控;但是缺点也很明显,非常容易造成热点数据(最近的数据访问的频率最高)
- 哈希取模切分:这个规则是计算某一列或几列的哈希值,再去取模散列到对应的表中。通常,我们会选择 user_id 做哈希取模。这种方式的优点是数据分片比较均匀,不易出现热点问题;缺点是扩容成本高(可以考虑一致性哈希)
三 分库分表引发的问题
全局主键问题
分库分表之后,一张表会跨越多张表,甚至是多个库,此时,数据库的自增 id 将会变得没有意义。因此,我们必须需要单独设计全局主键,以避免主键重复,引起业务系统的 KEY 冲突问题
常见的做法:
- UUID:它被称为通用唯一识别码,由一组32位数的16进制数字所构成,目的是让分布式系统中的所有元素都能有唯一的识别信息。它可以本地生成,性能很高;但是,由于它很长,会占用大量的存储空间
- 全局的自增id表:单独创建一张表,只有一个自增主键,而这个主键则用于分库分表的全局主键。这种做法需要依赖于其他表,且存在单点问题,当这张自增表出现故障,导致系统不可用
- 分布式全局唯一 ID 生成算法:这种算法有很多,例如:Twitter 的 snowflake、美团的 Leaf 等等
关联查询(JOIN)问题
- 字段冗余设计:这是一种反范式的设计,也是空间换时间的典例,它是将需要多次用到的数据分布到多张表中,避免了 JOIN 查询
- 数据组装:也就是多次查询,将多次查询的数据组装在一起构成整体数据
- 拆分查询:注意,这里所说的查询指的是前端发起的查询请求,即前端把复杂查询(多表)拆分成多次简单查询(单表)
网友评论