0%

分库分表

分库分表

为了解决单库单表数据量太大,导致的数据库压力过大,所以需要进行分库分表

分库分表有两种方式,分为垂直拆分和水平拆分

垂直拆分

垂直分表和垂直分库

  • 垂直分表 把一张大表中的字段拆分为两张表
  • 垂直分库 由于垂直分表之后,两个表还是存储在同一个数据库中,而如果数据库中表过多,数据库的压力过大,所以按照业务来对数据库进行拆分

带来的问题

  • 单机的ACID被打破,要么放弃原本的单机事务,修改实现,要么引入分布式事务
  • join操作很不方便,不能很方便地利用数据库自身的join了,需要应用或者其他方式来解决
  • 靠外键去进行约束的场景会受到影响

垂直拆分的规则简单,尤其适合各业务之间的耦合度较低且业务清晰的系统

水平拆分

水平分表和水平分库

  • 水平分表
  • 水平分库 如果对于同一业务中的表,依然是数据量特别大,可以对数据库进行水平拆分,其中的结构完全相同

带来的问题

  • 单机的ACID同样可能被打破
  • Join操作同样可能被影响
  • 靠外键去进行约束的场景会被影响
  • 依赖单库的自增序列生成唯一ID会受影响
  • 针对单个逻辑意义上的表的查询要跨库

几种典型的分片规则为:

  • 根据日期来分片
  • 根据某个特定的字段,如用户id来进行取模分片

问题解决

单机ACID问题

单机事务问题可以使用分布式事务 https://zhhll.icu/2022/分布式/分布式问题/2.分布式事务/,或者最终一致性 https://zhhll.icu/2022/分布式/分布式问题/3.数据一致性/ 来解决

自增序列问题

之前在单机时我们经常使用mysql的autoIncrement来生成id,但是在进行分库分表后,这种方式不能满足我们的要求了,根据id的特性:唯一性和连续性,我们来寻找解决方案

  • 唯一性,如果只考虑唯一性的话,那么可以参考UUID来生成,但是连续性不好
  • 连续性,考虑到整体全局的连续性的话,我们只能采用独立的系统来解决这个问题

将所有的id生成交给一个单独的系统去处理,所有的机器都是用id生成服务来生成,这个方式有几点不足

  • 性能问题,每次都远程取id会有性能损耗,改进方案是每次取一段,剩下的缓存在本地,这样就不需要每次都去远程获取了,但是这样如果机器宕机了,可能会有部分id的浪费
  • id生成服务的稳定性,这里使用了一个新的服务,无疑又增加了一个宕机的风险点
  • 存储问题

join问题

由于数据已经分布到多个数据库中了,join操作可能会出现跨库的情况,这个如何操作呢?这里说几个思路

  • 将需要进行数据库join的操作分为多次数据库操作
  • 数据冗余,对一些常用的信息进行冗余,将原本需要join的操作变成单表查询
  • 借助elasticsearch来做宽表解决跨库

欢迎关注我的其它发布渠道