为什么使用分库分表
1.性能:关系型数据库多以B+树类型的索引,在数据量超过阈值的情况,索引深度的增加使得磁盘访问的IO次数增加,导致性能下降,同时,高并发访问使得集中数据库成为系统瓶颈。
2.可用性:服务化的无状态型,能够达到较小成本的随意扩容,导致系统的最终压力都落到数据库上。
3.运维成本:当一个数据库实例中的数据达到阈值,对于DBA的运维压力就会增大。
什么是分库分表
数据分片,指按照某个维度将存放在单一数据库中的数据分散地存放至多个数据库或者表中以达到提升性能瓶颈以及可用性的效果
数据分片的有效手段就是分库和分表
分库和分表都可以有效的避免由数据量超过可承受阈值而产生的查询瓶颈,分库还可以有效的分散数据库单点的访问量
分表虽然无法缓解数据库压力,但是能尽量将分布式事务转化为本地事务的可能
使用多主多重的分片方式,可以有效地避免数据单点,从而提升数据架构的可用性
数据分片的拆分方式又分为垂直分片和水平分片
垂直分片
按照业务拆分的方式成为垂直分片,又称为纵向拆分,核心理念就是专库专用,在拆分前,一个数据库多个表构成,每个表不同业务,拆分之后,按照业务将表进行归类,分布到不同数据库中,从而将压力分散到不同数据库
优点
库表职责单一,复杂度降低,易于维护
单库或者单表压力降低,相互之间的影响也会降低
缺点
部分表关联无法在数据库级别完成,需要在程序中完成
单表的大数据量仍然存在性能瓶颈
单表或者单库高热点访问依旧对DB压力大
事务处理相对复杂,需要分布式事务
拆分到一定程度,扩展性会受到限制
水平分片
又称为横向拆分,相对于垂直分片,不再将数据根据业务逻辑分类,而是通过某个字段,根据某种规则将数据分散至多个库或者表中,每个分片包含数据的一部分。
例如:根据主键分片,偶数主键的记录放入 0 库(或表),奇数主键的记录放入 1 库(或表)
优点
解决单库单表大数据量和高热点访问性能遇到的瓶颈问题
应用程序端整体架构改动相对较小
事务处理简单
难遇见扩展性限制
缺点
拆分规则更复杂,很难抽象出一个能够满足整个数据库的切分规则
后期数据的维护难度增加,人为手动定位数据困难
产品逻辑变得更加复杂
分库分表之后,常见问题
分库分表后的数据,对数据库的操作变得繁重
能够正确的运行在单节点数据库中的SQL, 在分片之后的数据库中不一定能够正确运行。
跨库事务也是分布式数据库集群遇到的问题
1.合理使用分表,可以在降低单表数据量的情况下,尽量使用本地事务,善于使用同库不同表可以有效避免分布式事务带来的麻烦
2.采用最终一致性的柔性事务代替强一致事务
分布式全局唯一ID
1.需要使用全局唯一ID,例如UUID,GUID等。
分库分表中间件
主要实现方式
1.Client模式
2.Proxy模式
常见的中间件
Cobar
MyCat
基于Cobar改造,属于Proxy层方案。
TDDL
Sharding Sphere
提供三种模式
1.Sharding-JDBC(属于Client层方案)
2.Sharding-Proxy
3.Sharding-Sidecar
Sharding-JDBC的优点就在于不用部署,运维成本低,不需要代理层的二次转发请求,性能高。
分片键的选择
信息表:使用id进行分片,例如,文章,商品信息等
业务表:使用user_id进行分片,例如,订单表,支付表等
日志表:使用create_time进行分片,例如访问日志,登录日志等
分片算法的选择
1.取余分片算法.例如说,有四个库,那么 user_id 为 10 时,分到第 10 % 4 = 2
个库。
- 当然,如果分片键是字符串,则需要先进行 hash 的方式,转换成整形,这样才可以取余。
- 当然,如果分片键是整数,也可以使用 hash 的方式。
2.范围算法。
- 例如说,时间范围
上述两种算法,各有优缺点。
- 对于取余来说:
- 好处,可以平均分配每个库的数据量和请求压力。
- 坏处,在于说扩容起来比较麻烦,会有一个数据迁移的过程,之前的数据需要重新计算 hash 值重新分配到不同的库或表。
- 对于 range 来说:
- 好处,扩容的时候很简单,因为你只要预备好,给每个月都准备一个库就可以了,到了一个新的月份的时候,自然而然,就会写新的库了。
- 缺点,但是大部分的请求,都是访问最新的数据。实际生产用 range,要看场景。
如果查询条件不带分片键,怎么办*
当查询不带分片键的时候,中间件一般会扫描所有库表,然后聚合结果进行返回
如何解决分布式事务
一个前提,需要保证本地事务,那么我们分库分表时,就需要有对应要求,数据库在分库分表时,需要保证一个逻辑中,能够形成本地事务。