数据库分库分表
何时分库分表
数据库性能出现问题后,一般按照如下步骤优化:
① 参数优化 ② 缓存、索引 ③ 读写分离 ④ 分库分表 (最终方案)
- 分库
- 服务器磁盘空间不足、内存不足、 CPU 压力过大,导致读写性能瓶颈。
- 网络带宽不足,响应慢,导致客户端连接等待/超时。
- 数据量过大,影响读写性能;MySQL单库数据量在5000万以内性能比较好,超过阈值后性能会随着数据量的增大而变弱。MySQL单表的数据量是500w-1000w之间性能比较好,超过1000w性能也会下降。
- 数据库连接数过多,响应慢,导致客户端连接等待/超时。MySQL数据库默认100个连接,单机最大1500连接。
- 分表
- 单表出现性能瓶颈,通常是因为单表数据量过大,导致读写性能较慢。一般B+树索引高度是2~3层最佳,如果数据量千万级别,可能高度就变4层了,数据读写就会明显变慢。
分库分表方式
可以分为两种垂直切分和水平切分模式
- 垂直切分
垂直分库,按照业务模块进行切分,将不同模块的表切分到不同的数据库中。垂直分库把一个库的压力分摊到多个库,提升了一些数据库性能,但并没有解决由于单表数据量过大导致的性能问题,所以就需要配合后边的分表来解决。
垂直分表,将表中不同的字段切分到同意数据库不同的表中。一般是把业务宽表中比较独立的字段,或者不常用的字段拆分到单独的数据表中,是一种大表拆小表的模式。 - 水平切分
水平分库是把同一个表按一定规则拆分到不同的数据库中,每个库可以位于不同的服务器上,以此实现水平扩展。
水平分表是在同一个数据库中将一张大表按照一定的切分规则,按照行切分成不同的表。
水平分表(策略)
主流的切分策略有:Range 范围、hash切分、range+hash取模混合、映射表
- Range 范围
是指按某个字段的数据区间来进行切分。比如,表按照 id 的数据范围切分成多张表,每 1000万条数据存放一张表,切分后的表可以放到同一个数据库,也可以放到不同的数据库。
优点: 有利于扩容,后续扩容不需要数据迁移。
缺点: 存在写偏移,会有热点问题。比如,按照时间来划分时,最近的数据会聚集在一张表中,所以读写流量全部集中在最新的表。 - hash切分
通过对分表键 key 进行一定的运算(通常有取余、取模运算),通过运算结果来决定路由的库和表。
优点: 数据分片比较均匀,大大降低热点问题。
缺点: 后期扩容可能需要迁移数据。 - range+hash取模混合
拆分库的时候,可以先用range范围方案,再用hash取模的策略把同一range库中的表进行切分。 - 映射表
将分表键和数据库的映射关系记录在一个单独的表(表的形式可以是数据库表、文件或者配置中心)。
优点: 可以灵活设置路由规则。
缺点: 映射表可能也会随着业务量的增大,同样需要分库分表。
分库分表后的问题
- 分布式ID问题
分库分表后,需要维护全局唯一的ID,常用的算法有:UUID、数据库自增生成全局ID、利用Redis的incr命令生成主键、雪花算法。 - 分布式事务问题
分库分表之后可能就需要引入分布式事务的问题,解决方案有两种:- 业务划分的时候规避分布式事务;
- 使用专业的的分布式框架,比如阿里开源的 Seata;
- 跨库关联问题
- 将有E-R关系的表存储到一个库中。
- 对于数据量少的表建成全局表,分布到各个库中
- 对于必须跨库join的,最多支持跨两张表的跨库join。跨节点Join的问题:解决这一问题可以分两次查询实现
- 分页问题
分页问题,解决方案有三种:- 选择合适的分表字段,规避绝大部分高频查询场景出现跨库;
- 使用专业的分布式框架,比如开源框架:ElasticSearch;
- 业务代码中分别查询,然后组装数据;
- 排序问题
跨节点的count,order by,group by以及聚合函数等问题:可以分别在各个节点上得到结果后在应用程序端进行合并。 - 增加调试和维护难度
分库分表中间件
分库分表工具主要有 2种模式:客户端模式 和 代理模式。客户端模式是指在客户端实现直连数据库,客户端通常是通过一些封装好的 jar来实现,常见的开源中间件有:Apache的Sharding-JDBC、淘宝的TDDL、美图的Zebra。代理模式是指需要单独部署服务,客户端连接代理服务,由代理服务再和数据库交互,常见的开源中间件有:Apache的 Sharding-Proxy、阿里的 cobar、国产的 MyCat、360的 Atlas。另外还有 google的 vitess,它是基于 zookeeper,通过 RPC方式进行数据管理。
业界组件 | 原厂 | 功能特性 | 备注 |
---|---|---|---|
DBLE | 爱可生开源社区 | 专注于 mysql 的高可扩展性的分布式中间件 | 基于 MyCAT 开发出来的增强版。 |
Meituan Atlas | 美团 | 读写分离、单库分表 | 目前已经在原厂逐步下架。 |
Cobar | 阿里(B2B) | Cobar 中间件以 Proxy 的形式位于前台应用和实际数据库之间,对前台的开放的接口是 MySQL 通信协议 | 开源版本中数据库只支持 MySQL,并且不支持读写分离。 |
MyCAT | 阿里 | 是一个实现了 MySQL 协议的服务器,前端用户可以把它看作是一个数据库代理,用 MySQL 客户端工具和命令行访问,而其后端可以用 MySQL 原生协议与多个 MySQL 服务器通信 | MyCAT 基于阿里开源的 Cobar 产品而研发 |
Atlas | 360 | 读写分离、静态分表 | 2015 年后已经不在维护 |
Kingshard | 开源项目 | 由 Go 开发高性能 MySQL Proxy 项目,在满足基本的读写分离的功能上,Kingshard 的性能是直连 MySQL 性能的 80% 以上。 | |
TDDL | 阿里淘宝 | 动态数据源、读写分离、分库分表 | TDDL 分为两个版本,一个是带中间件的版本,一个是直接 Java 版本 |
Zebra | 美团点评 | 实现动态数据源、读写分离、分库分表、CAT 监控 | 功能齐全且有监控,接入复杂、限制多。 |
MTDDL | 美团点评 | 动态数据源、读写分离、分布式唯一主键生成器、分库分表、连接池及 SQL 监控 | |
Vitess | 谷歌、Youtube | 集群基于 ZooKeeper 管理,通过 RPC 方式进行数据处理,总体分为,server,command line,gui 监控 3 部分 | Youtube 大量应用 |
DRDS | 阿里 | DRDS(Distributed Relational Database Service)专注于解决单机关系型数据库扩展性问题,具备轻量 (无状态)、灵活、稳定、高效等特性,是阿里巴巴集团自主研 | |
Sharding-proxy | apache 开源项目 | 提供 MySQL 版本,它可以使用任何兼容 MySQL 协议的访问客户端 (如:MySQL Command Client, MySQL Workbench 等) 操作数据,对 DBA 更加友好。向应用程序完全透明,可直接当做 MySQL 使用。适用于任何兼容 MySQL 协议的客户端。 | Apache 项目,定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。 |
Sharding jdbc | apache 开源项目 | 完全兼容 JDBC 和各种 ORM 框架。适用于任何基于 Java 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC。基于任何第三方的数据库连接池,如:DBCP,C3P0, BoneCP, Druid, HikariCP 等。支持任意实现 JDBC 规范的数据库。目前支持 MySQL,Oracle,SQLServer 和 PostgreSQL | Apache 项目,定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动 |
参考: