分库分表概念
互联网系统需要处理大量用户的请求。比如微信日活用户破10亿,海量的用户每天产生海量的数量;美团外卖,每天都是几千万的订单,那这些系统的用户表、订单表、交易流水表等是如何处理呢? 数据量只增不减,历史数据又必须要留存,非常容易成为性能的瓶颈,而要解决这样的数据库瓶颈问题,“读写分离”和缓存往往都不合适,目前比较普遍的方案就是使用NoSQL/NewSQL或者采用分库分表。
使用分库分表时,主要有垂直拆分和水平拆分两种拆分模式,都属于物理空间的拆分。
分库分表方案:只分库、只分表、分库又分表。
垂直拆分:由于表数量多导致的单个库大。将表拆分到多个库中。
水平拆分:由于表记录多导致的单个库大。将表记录拆分到多个表中。、
拆分方式
垂直拆分
垂直拆分又称为纵向拆分,垂直拆分是将表按库进行分离,或者修改表结构按照访问的差异将某些列拆分出去。应用时有垂直分库和垂直分表两种方式,一般谈到的垂直拆分主要指的是垂直分库。
垂直分表就是将一张表中不常用的字段拆分到另一张表中,从而保证第一张表中的字段较少,避免出现数据库跨页存储的问题,从而提升查询效率。
解决:一个表中字段过多,还有有些字段经常使用,有些字段不经常使用,或者还有text等字段信 息。可以考虑使用垂直分表方案。
按列进行垂直拆分,即把一条记录分开多个地方保存,每个子表的行数相同。把主键和一些列放到一个表,然后把主键和另外的列放到另一个表中。
垂直拆分优点
- 拆分后业务清晰,拆分规则明确;
- 易于数据的维护和扩展;
- 可以使得行数据变小,一个数据块 (Block) 就能存放更多的数据,在查询时就会减少 I/O 次数;
- 可以达到最大化利用 Cache 的目的,具体在垂直拆分的时候可以将不常变的字段放一起,将 经常改变的放一起;
-
垂直拆分缺点
主键出现冗余,需要管理冗余列;
- 会引起表连接 JOIN 操作,可以通过在业务服务器上进行 join 来减少数据库压力,提高了系统的复杂度;
- 依然存在单表数据量过大的问题;
-
水平拆分
水平拆分又称为横向拆分。 相对于垂直拆分,它不再将数据根据业务逻辑分类,而是通过某个字 段(或某几个字段),根据某种规则将数据分散至多个库或表中,每个表仅包含数据的一部分,如下图所示:

水平分表是将一张含有很多记录数的表水平切分,不同的记录可以分开保存,拆分成几张结构相同 的表。如果一张表中的记录数过多,那么会对数据库的读写性能产生较大的影响,虽然此时仍然能 够正确地读写,但读写的速度已经到了业务无法忍受的地步,此时就需要使用水平分表来解决这个问题。水平拆分优点:
拆分规则设计好,join 操作基本可以数据库做;
- 不存在单库大数据,高并发的性能瓶颈;
- 切分的表的结构相同,应用层改造较少,只需要增加路由规则即可;
-
水平拆分缺点:
拆分规则难以抽象;
- 跨库Join性能较差;
- 分片事务的一致性难以解决;
-
水平拆分对比垂直拆分
水平拆分:解决表中记录过多问题。
垂直拆分:解决表过多或者是表字段过多问题。 水平拆分重点考虑拆分规则:例如范围、时间或Hash算法等。
分库分表实战
背景
刚开始我们的系统只用了单机数据库
- 随着用户的不断增多,考虑到系统的高可用和越来越多的用户请求,我们开始使用数据库主从架构
当用户量级和业务进一步提升后,写请求越来越多,这时我们开始使用了分库分表
问题
用户请求量太大
- 单服务器TPS、内存、IO都是有上限的,需要将请求打散分布到多个服务器
- 单库数据量太大
- 单个数据库处理能力有限;
- 单库所在服务器的磁盘空间有限;
- 单库上的操作IO有瓶颈
单表数据量太大
垂直拆分
- 垂直分库
微服务架构时,业务切割得足够独立,数据也会按照业务切分,保证业务数据隔离,大大提升了数据库的吞吐能力
- 垂直分表
表中字段太多且包含大字段的时候,在查询时对数据库的IO、内存会受到影响,同时更新数 据时,产生的binlog文件会很大,MySQL在主从同步时也会有延迟的风险
- 水平拆分
- 水平分表
针对数据量巨大的单张表(比如订单表),按照规则把一张表的数据切分到多张表里面去。 但是这些表还是在同一个库中,所以库级别的数据库操作还是有IO瓶颈。
- 水平分库
将单张表的数据切分到多个服务器上去,每个服务器具有相应的库与表,只是表中数据集合不同。 水平分库分表能够有效的缓解单机和单库的性能瓶颈和压力,突破IO、连接数、硬件 资源等的瓶颈
- 水平分库规则
- 不跨库、不跨表,保证同一类的数据都在同一个服务器上面。
- 数据在切分之前,需要考虑如何高效的进行数据获取,如果每次查询都要跨越多个节点,就需要谨 慎使用。
- 水平分表规则
- RANGE
- 时间:按照年、月、日去切分。例如order_2020、order_202005、order_20200501
- 地域:按照省或市去切分。例如order_beijing、order_shanghai、order_chengdu
- 大小:从0到1000000一个表。例如1000001-2000000放一个表,每100万放一个表
- HASH
- 用户ID取模
- RANGE
不同的业务使用的切分规则是不一样,就上面提到的切分规则,
举例如下:
站内信
- 用户维度:用户只能看到发送给自己的消息,其他用户是不可见的,这种情况下是按照 用户ID hash分库,在用户查看历史记录翻页查询时,所有的查询请求都在同一个库内
用户表
- 范围法:以用户ID为划分依据,将数据水平切分到两个数据库实例,如:1到1000W在 一张表,1000W到2000W在一张表,这种情况会出现单表的负载较高- 按照用户ID HASH尽量保证用户数据均衡分到数据库中
如果在登录场景下,用户输入手机号和验证码进行登录,这种情况下,登录时是 不是需要扫描所有分库的信息? 最终方案:用户信息采用ID做切分处理,同时存储用户ID和手机号的映射的关系 表(新增一个关系表),关系表采用手机号进行切分。可以通过关系表根据手机 号查询到对应的ID,再定位用户信息。
