为什么要分库分表
性能
随着单库中的数据量越来越大、数据库的查询QPS越来越高,对数据库的读写所需要的时间也越来越多。数据库的读写性能可能会成为业务发展的瓶颈。对应的,就需要做数据库性能方面的优化。如果数据库的查询QPS过高,就需要考虑拆库,通过分库来分担单个数据库的连接压力。如果单表数据量过大,当数据量超过一定量级后,无论是对于数据查询还是数据更新,在经过索引优化等纯数据库层面的传统优化手段之后,还是可能存在性能问题。这是量变产生了质变,这时候就需要去换个思路来解决问题,比如:从数据生产源头、数据处理源头来解决问题,既然数据量很大,那我们就来个分而治之,化整为零。这就产生了分表,把数据按照一定的规则拆分成多张表,来解决单表环境下无法解决的存取性能问题。
可用性
单个数据库如果发生意外,很可能会丢失所有数据。尤其是云时代,很多数据库都跑在虚拟机上,如果虚拟机/宿主机发生意外,则可能造成无法挽回的损失。因此,除了传统的 Master-Slave、Master-Master 等部署层面解决可靠性问题外,我们也可以考虑从数据拆分层面解决此问题。
分库分表的场景和解决问题
| 方式 | 解决问题 |
|---|---|
| 只分库不分表 | 数据库读写 qps过高,数据库连接不足 和磁盘io瓶颈 |
| 只分表不分库 | 单表数据库 存储性能瓶颈 |
| 即分表又分库 | 连接数不足,数据量过大存储瓶颈 |
怎么分分多少
分表数量
一般根据业务增长速度 计算5年左右的业务数量 到时候考虑数据迁移到冷库
分库数量
分库要考虑平时的业务峰值读写QPS外,还要考虑到大促期间可能达到的峰值,需要提前做好预估。根据我们的实际业务场景,可以根据历史QPS、RT等数据评估。
常见的方式
读写分离
无法解决集中写入瓶颈的问题。本质是将访问压力分散到集群中的多个节点,但是没有分散存储压力
基本原理是将数据库读写操作分散到不同的节点上
方式
- 中间件封装
- 程序代码封装
常见问题
主从复制延迟
解决方式
- mysql采用半同步复制
- 写操作后的读操作指定发给数据库主服务器
- 读从库失败后再读一次主机
- 关键业务读写操作全部指向主库,非关键业务采用读写分离
分库
垂直分库:根据业务分库指的是按照业务模块将数据分散到不同的数据库服务器 减少互相的影响
水平分库:业务分库之后数据量还是过多,可以做主从 读写分离 解决数据库读写 qps过高,数据库连接不足 磁盘io过高的问题
怎么分参考分库数量章节
方式
- 中间件封装
- 程序代码封装
分表
垂直分表 是对数据表列的拆分,把一张列比较多的表拆分为多张表。
水平分表 是对数据表行的拆分,把一张行比较多的表拆分为多张表,可以解决单一表数据量过大的问题。
拆分原则看sql where语句后字段出现频率) 如果查询语句无法带分表字段,一般采用异构索引表解决
水平分表路由方式
| 路由算法 | 优点 | 缺点 |
|---|---|---|
| 范围路由算法 | 可以随着数据的增加平滑地扩充新的表 可以方便的算出数据落到哪个库哪个表 | 分布不均匀某些时间段数据激增,某些时间段数据量很少导致数据倾斜 无法解决集中写入瓶颈的问题。 |
| 取模(常用根据业务主键) | 简单方便 算法容易理解 可以方便的算出数据落到哪个库哪个表 | 分片键的值的类型受限,必须是纯数字,不能包括字母等 会造成数据倾斜(因为原理是取模) |
| 配置路由(路由表)算法 | 配置路由设计简单,使用起来非常灵活, 尤其是在扩充表的时候,只需要迁移指定的数据,然后修改路由表就可以了 | 必须多查询一次,会影响整体性能路由表本身如果太大(例如,几亿条数据),性能同样可能成为瓶颈, |
| Hash 路由算法(常用根据业务主键) | 1. 简单方便 2.算法容易理解 3.分片键的值的类型不受限,支持分片值非纯数字类型 | 不方便的快速算出数据落到哪个库哪个表(需要先计算分片键的哈希值再取模) 会造成数据倾斜(因为原理是取模) |
| 一致性hash | 数据分布较平滑 数据迁移方便 | 算法比较复杂没有现有实现 不方便的快速算出数据落到哪个库哪个表 |
分库分表
既可以分散访问压力,又可以分散存储压力
结合分库和分表即可
问题1、join 操作问题
同一个数据库中的表分布在了不同的数据库中,导致无法使用 join 操作。这样就导致我们需要手动进行数据的封装,比如你在一个数据库中查询到一个数据之后,再根据这个数据去另外一个数据库中找对应的数据。,可以采用多次查询业务层进行数据组装的方法。不过,这种方法需要考虑业务上多次查询的事务性的容忍度。
问题2、事务问题
同一个数据库中的表分布在了不同的数据库中,如果单个操作涉及到多个数据库,那么数据库自带的事务就无法满足我们的要求了。这个时候,我们就需要引入分布式事务
问题3 跨库聚合查询问题:
分库分表会导致常规聚合查询操作,如 group by,order by 等变得异常复杂。这是因为这些操作需要在多个分片上进行数据汇总和排序,而不是在单个数据库上进行。为了实现这些操作,需要编写复杂的业务代码,或者使用中间件来协调分片间的通信和数据传输。这样会增加开发和维护的成本,以及影响查询的性能和可扩展性。
问题4 ID不唯一
问题5 分页
分表分页/跨库分页 难玩却不代表没有玩法 - 掘金
Sharding-Sphere 的解决方案
剖析Sharding-Sphere系列——结果归并 · ShardingSphere - 博客