本篇我打算简单整理一下关于 MySQL 分库分表的基础知识
- 分库:将单个数据库拆分成多个数据库的过程
- 分表:将单张表拆分为多张表的过程
总得来说分库分表的原因主要有以下几种:提高性能,增加并发量,增加安全性
提高性能是说单张表数据量太大时,数据库查询效率变低,通过拆分数据的方式提高查询性能
增加并发量是说单个 MySQL 实例最多支持 2000 左右的并发量,一般超过 1000 数据库就已经很危险了,所以可以通过拆分多几个 MySQL 实例,通过分流的方式减少单个实例上的压力,防止高并发流量直接将数据库打挂
增加安全性是说,即使某个数据库挂了,还有部分数据库可以正常工作,假如存在 4 个 MySQL 实例,某一个实例挂掉后,起码可以保证还有 3 个实例可以正常服务
那么是不是说可以无限分库分表来提高性能呢?当然不是,从本质来说这是一种通过牺牲资源来提升性能、提高可用性的方案,这里需要权衡具体使用哪种方案处理起来更优一些
从分库分表字面意义来说,分库分表主要有以下几种情况:
- 只分库不分表:主要解决 MySQL 并发访问量太大的问题
- 只分表不分库:主要解决单表数据量过大,数据库操作性能较差的问题
- 既分库也分表:上面两种方案都加起来的结果
宏观角度看,分库分表主要包含以下两种实现方式:
水平切分:想象 Excel 表格,第一行定义不同列,所谓水平拆分就是将数据按照某种规则放到不同的库表中,这里包含两种情况:
- 相同表结构,表名不同,放到同一个 MySQL 实例中:主要解决单表数据量过大问题
- 相同表结构,表名相同,放到不同 MySQL 实例中:既可以解决单表数据过大,又可以解决流量大的问题
垂直切分:简单来说就是将某一张表中所有字段拆分为几组,分别放到不同表中,这里同样包含两种情况:
- 不同表结构,表名不同,放到同一个 MySQL 实例中:主要解决单表数据量过大问题
- 不同表结构,表名不同,放到不同 MySQL 实例中:既可以解决单表数据过大,又可以解决分流问题
垂直拆分很好实现,根据业务维度将大表拆成多个小表。但水平拆分比较复杂,此时你需要定义具体的分配规则,哪类数据放在库 A,哪类数据放在库 B,一般情况下包含两种分法:
- 按时间范围来分:实现简单但功能较差,此时同一时间段的数据只会打到某一个数据库,无法解决分流问题
- 一致性 Hash 算法:效率高,但需要考虑扩容后的数据迁移问题,此时迁移数据会很麻烦
上面只是简单提到了一致性 Hash 二次扩容可能带来的问题,实际上分库分表还可能带来以下问题:
- 唯一主键和唯一索引的冲突检测
- 分片规则的设定
- 分布式事务是否支持
目前市面上常见的数据库分库分表中间件有:Sharding-jdbc、MyCat