开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第18天,点击查看活动详情
一、为什么要分库分表
当前数据库连接已经无法满足日益增长的数据连接要求。随着公司业务快速发展,数据库中的数据量猛增,访问性能也变慢了,优化迫在眉睫,及时添加从库、优化索引,做很多操作时性能仍下降严重。IO瓶颈,CPU瓶颈,最终都会导致数据库的活跃连接数增加,进而逼近甚至达到数据库可承载活跃连接数的阈值。
分库分表的目的就是为了解决由于数据量过而导致数据库性能降低的问题,将原来独立的数据库拆分为若干数据库组成,将数据大表拆分成若干数据表,使得单一数据库、单一数据表的数据量变小,从而达到提升数据库性能的目的。
二、分库分表的方式
1、垂直分库
是指按照业务将表进行分类,分布到不同的数据库上面,每个库可以放在不同的服务器上,它的核心理念是专库专用。比如把商铺表和商品表分别放置两个独立的数据库。作用是:
- 解决业务层面的耦合,业务清晰
- 能对不同业务的数据进行分级管理、维护、监控和扩展等
- 高并发场景下,垂直分库一定程度上提升IO、数据库连接和降低单机硬件资源的瓶颈
2、水平分库
水平分库就是把同一个表的数据按一定规则拆到不同的数据库中,每个库可以放在不同的服务器上。垂直分库是不同表拆到不同数据库中,它是对数据行的拆分,不影响表结构。
作用是:
- 解决了单库大数据,高并发的性能瓶颈。
- 提高了系统的稳定性和可用性。
3、垂直分表
将一个大表用户信息字段,按照活性强度抽取字段分成多表,每个表存储其中一部分字段。作用是:
- 为了避免IO争抢并减少锁表的几率,查看详情的用户与商品信息浏览互不影响。
- 充分发挥热门数据的操作效率,商品信息的操作的高效率不会被商品描述的低效率拖累。
4、水平分表
在同一个数据库内,把同一个表的数据按一定规则拆到多个表中(对数据的拆分,不影响表结构)。作用是:
- 优化单一表数据量过大而产生的性能问题。
- 避免IO争抢并减少锁表的几率。
三、分库分表工具
- sharding-sphere:jar,前身是sharding-jdbc;
- TDDL:jar,Taobao Distribute Data Layer;
- Mycat:中间件。
四、分库分表步骤
- 根据容量(当前容量和增长量)评估分库或分表个数
- 选取分片键key(均匀)
- 确定分表规则(hash或range等)
- 执行(一般双写)
- 扩容问题(尽量减少数据的移动)
五、分库分表问题
1.分布式事务问题
由于垂直分库、水平分库,将数据分摊在不同库中,甚至不同的服务器上,势必带来了分布式事务的问题。
解决方案: ① 采用补偿事务,例如TCC来解决分布式事务问题。 ② 用记录日志等方式来解决分布式事务问题。
2.分布式主键ID冲突问题
解决方案: ① 利用Redis的incr命令生成主键。 ② 用UUID生成主键,缺点是字段比较长、不好排序。 ③ 利用snowake算法生成主键。
3.跨库join问题
在切分之前关联查询非常简单,直接SQL JOIN便能解决,但是切分之后数据分摊在不同的节点上,此时JOIN就比较麻烦了,因此切分之后尽量避免JOIN。
解决方案: ① 绑定表:将有E-R关系的表存储到一个库中。 ② 广播表:对于数据量少的表建成全局表,分布到各个库中 ③ 对于必须跨库join的,最多支持跨两张表的跨库join。④ 通过数据组装和冗余字段法处理
4.分页、排序、聚合等问题
跨数据节点进行分页、排序或者一些聚合函数,筛选出来的仅仅是针对当前节点,仅仅保证的单节点的有序,而不是整个节点的有序,需要数据汇总后手动处理再次排序。
5.扩容迁移问题
面临性能和存储的瓶颈时,才会考虑分片设计,此时就不可避免的需要考虑历史数据迁移的问题;根据当前的数据量和QPS,以及业务发展的速度,进行容量规划,推算出大概需要多少分片。