为什么需要分库分表
分库分表问题往往要从两条线开始说起
垂直方向 和 水平方向
垂直方向
垂直方向主要针对的是业务
分表
假设一个简单的电商系统,使用单库,目前只存在几张表
- 用户表
- 订单表
- 商品表
- 物流表
此时,一个数据库包含所有的业务表。用户的读、写请求操作的都是同一个数据库
随着业务的发展,表中的字段会越来越多,开始变得不好维护,一个表包含几十个字段
比如说需要给用户表增加一些非必要信息字段,但是用户表的数据量有点大,直接改会有风险
这个时候就可以采用分表的策略,将用户表拆分,分为用户基本信息 和 用户扩展信息

用户基本信息表
:存放用户最主要的信息,比如用户名、密码、手机号、小程序openId
、邮箱等核心数据 (存放查询频次非常高的数据)用户拓展表
:存放用户次要信息,比如地址、单位、个性签名等 (这样就不用每次查询用户信息时都要把所有信息查出来了,同时节省了 RPC 的负担)
通过分表把核心数据和非核心数据分开,让表的结构更清晰、职责更加单一、更加便于维护
像订单表和订单详情表也是一个非常经典的例子
分库
业务在 N 次迭代后,往往会陷入一个困境,功能非常完善,但是系统关系错综复杂,牵一发而动全身,需要赶紧进行一次内部技术迭代,不然后续会带来很多隐藏问题!
这个时候就需要按照业务功能划分不同领域,把相同领域的表放在同一个数据库

按照领域拆分后,每个域只用关注自己相关的表,职责更加单一
对于代码来说,也可以根据领域拆分出不同的服务
分库分表
有时候业务上只分库、只分表还是不够的
比如在财务系统的场景上,需要按照月份、年份汇总用户的资金
还可以按照区域进行分库,比如华中、华东、华南等等
水平方向
如果说垂直方向更多的是针对业务,那么水平方向更多的是针对数据
也是在面试中说的更多的"分库分表"
单库
还是刚才的单库场景
- 用户表
- 订单表
- 商品表
- 物流表
一个 master
数据库,包含所有的业务表
用户的读写请求操作的都是同一个数据库,适用于并发量很低的场景
主从读写分离
业务发展必然伴随着用户数量的增长
但是一般来说,用户的请求中,读请求
往往占据了大部分,写请求
占比极少
数据库的连接是有限的,它是非常宝贵的资源
但是不管是读请求,还是写请求也好,它都至少占用一个数据库连接
那如果写数据需要的连接,被读请求占据完了咋办?不就写不了数据了?
所以就出现了主从读写分离架构
,将读库和写库分开

如上所示,是最普通的 一主一从架构
(一个 master
,一个 slave
)
所有的写数据请求,都指向主库
一旦主库写完数据之后,立马异步同步给从库,此时所有的读数据请求,就能获取最新的数据了(网络条件好的情况下几乎忽略不计)
相较于单库的方案,主从结构更能保证系统的稳定性
如果主库跪了,可以将从库升级为主库
那么问题来了,如果用户量过大,master
挂了,salve
升级成 master
后还是扛不住怎么办?

这就需要 一主多从方案
了
如果 master
挂了,可以从从库里选择一个成为新的 master
,那么另一个从库就变更成新 master
的 slave
了
分库
还是刚才的场景,如果请求量真的很大, master
根本扛不住怎么办 (升级配置哈哈!)
在不升级机器的情况下,可以选择建立多个库
每个库的结构是一模一样的,只有存储的数据不一样
分表
根据经验,单表的数据量应该尽量控制在 1000 万以内,这时的性能是最佳的(根据机器配置上下浮动)
当单表的数据超过这个值时,性能会变得很差,比如说索引的检索、建立
那我们就可以分表,控制每张表的数据量和索引大小
比如一张数据量很大的用户表
我们将其拆分为
- 用户表 0
- 用户表 1
- 用户表 2
- ...
可以通过用户的唯一键去做hash
,确定用户在的那张表,随后进行新增、插入、更新操作
分库分表
将上述两者结合起来,就会得到一个 分库分表
方案
适用于用户并发量很大、而且需要存储的数据量也很多的场景

当用户请求过来时,先根据用户 唯一键
路由到其中的一个用户库,然后在定位到某张表
路由的算法有很多
根据 id 取模
指定区间 id
一致性 hash 算法
总结
垂直方向的分库分表更多的是从业务角度出发,为了减少系统的复杂度,将数据区分开
水平方向的分库分表更多的是为了能让数据在读写中更加丝滑,让数据库更好的发挥性能
分库
:解决数据库连接资源不足以及磁盘 IO 性能瓶颈的问题分表
:为了解决单表数据量太大,索引维护困境分库分表
:同时解决以上问题
根据结论我们在实践中就可以根据具体需要来选择方案
用户并发量很大,但是数据量不大
:需要分库,不需要分表并发量不大,但是数据量很多
:需要分表,不需要分库