数据库分库分表入门
前言:想搞一下读写分离,看到读写分离经常和分库分表一起出现,所以一起来探究下分库分表到底是什么与其使用场景,有点复杂搞得我也有点晕,一些优点缺点都是复制的,还有其它一些,可能有点不准确,凑合看理解意思吧,供本人复习之用
参考:
https://www.jianshu.com/p/658bc9151e7b
https://blog.csdn.net/weixin_44062339/article/details/100491744
https://blog.csdn.net/vipshop_fin_dev/article/details/81416725
目录
第一章 分库分表概念
1.1 垂直分库
将一个数据库中的一些关系紧密的表拆出来组成新的数据库
优点:
- 业务系统解耦。
- 与微服务治理类似,便于集中管理,监控,扩展
- 高并发情况下提升IO,数据库连接数,单机硬件资源瓶颈
缺点:
- 多表join只能通过应用程序解决,加大开发复杂度
- 分布式事务处理复杂
- 单表数据总量无法解决
1.2 垂直分表
如果有的表字段比较多,有的字段不常用或者字段长度较大,可以将这些字段拆分到扩展表中,mysql是按照数据页进行存储的,如果单行数据过大,会导致数据跨页,造成额外的性能开销。
适用情况:
优点:
为了避免IO争抢并减少锁表的几率
充分发挥热门数据的操作效率
解释:为什么大字段IO效率低:第一是由于数据量本身大,需要更长的读取时间;第二是跨页,页是数据库存储单位,很多查找及定位操作都是以页为单位,单页内的数据行越多数据库整体性能越好,而大字段占用空间大,单页内存储行数少,因此IO效率较低。第三,数据库以行为单位将数据加载到内存中,这样表中字段长度较短且访问频率较高,内存能加载更多的数据,命中率更高,减少了磁盘IO,从而提升了数据库性能。
1.3 水平分库
数据库中某表的数据特别多,有几千万数据,所以对此表进行一些操作的话会很慢,这时需要水平分库。水平分库就是把库中表里的数据按某一规则进行进行拆分,最后拆分到两个库里。
适用情况:
优点:
- 解决了单库大数据,高并发的性能瓶颈。
- 提高了系统的稳定性及可用性。
- 切分后表结构相同,程序改动小
缺点:
- 同一个表被分配在不同的数据库,需要额外进行数据操作的路由工作,因此大大提升了系统复杂度。
- 数据扩容
- 分片规则难以抽象(不同的库,难以固定某个字段拆分,比如商品可以商品IDhash到某个库中,订单表需要根据用户IDhash到某个库中)
- 分布式事务,部分业务无法关联join
1.4 水平分表
水平分表也是为了解决表的数据量过大的问题,但是它把表拆成两个后依旧放在一个数据库中。
优点:
-
优化单一表数据量过大而产生的性能问题
-
避免IO争抢并减少锁表的几率
缺点:
- 操作复杂度提升(分页啥的)
写在最后:感觉水平分库和水平分表差不多,是不是可以分在一个类别里面呢?
第二章 分库分表时的策略
2.1 垂直分库策略
感觉就是业务相近的表分在一个库里面吧,如商品库,订单库
2.2 垂直分表策略
将访问频次低的,占用空间较大的放在一个单独表里,访问频次高的放在一张表里。或者经常组合查询的列放在一张表里。
2.3 水平分库分表策略
感觉这两种策略一样就拉一起来说了,水平划分通常是先确定主表,将主表与其关联表和间接关联表划分到同一个sharding。如确定答题卡表为主表,那么与其关联的答案表也一起划分到同一个sharding(个人感觉意思应该是我们以答题卡上有很多答案,我们先对答题卡进行分片,然后要对答案进行分片时直接参考答题卡的分片就行了,即答题卡在哪片,对象的答案就在哪片)。
2.3.1 连续分片
连续分片,比如确定userId为关键字,userId在(0,10000000]在shard_0,userId在(10000000,20000000]在shard_1。
优点:扩容方面,连续分片更加容易扩容,当关键字增长到达某一个段的时候,添加新的分片即可,不需要进行数据迁移。
缺点:存在数据热度不一致的问题,比如1年前的微博数据和现在的微博数据热度差异巨大,连续分片的情况下会导致各个库的访问压力不均匀。
对于随机分片的数据迁移问题,也有一些优化的策略。比如采用一致性哈希算法进行分片,那么每次扩容的时候,所要迁移的数据量则会大大减少。
2.3.2 随便分片
通过对关键字进行hash取模进行分片,例如确定userId为关键字,划分成32个分片,则index=userId%32。
优点:数据热度通常更加均匀。
缺点:在进行扩容的时候需要进行数据迁移。
2.3.3. ID问题
一旦数据库被切分到多个物理结点上,我们将不能再依赖数据库自身的主键生成机制。一方面,某个分区数据库自生成的ID无法保证在全局上是唯一的;另一方面,应用程序在插入数据之前需要先获得ID,以便进行SQL路由。
我在这只简要说明下UUID和雪花生成策略,更详细的可以看这个:https://blog.csdn.net/qq_41428035/article/details/103165055
UUID:就是根据MAC,纳米级时间、芯片ID等等生成个不重复的长度36位的字符串,
雪花:根据时间、数据中心编号、机器编号等生成一个有序的长整型id
优缺点:
第三章 应用问题
3.1 水平分表分页排序问题
如果要分页排序的数据都在一个分片(数据库)上,那么跟单个数据源的没什么关系。
如果要对所有的数据进行分页排序,那要从各个分片上查出数据,然后汇总排序,分页的难度会随着页码的增加而增加。例如查询第一页的数据,只需要在各个分片上查询出第一页的数据,然后再汇总排序,但如果查询第20页的数据,就需要把各个分片的前20页的数据都查询出来(因为无法确保前20页的数据到底在哪,万一前20页的数据都在某一片呢),然后再汇总进行分页排序,这个数据量就非常大,性能也会急速下降。
解决跨分片的分页排序难题更多的是在产品设计上进行优化,比如尽量规避这种跨分片分页排序的需求;只允许用户查看前面几页;尽量缩小查询范围。
而技术角度的解决,通常是通过一些冗余数据来进行,可以冗余一张表,里面存与分页相关的数据,先根据表把分页数据的关键字找出来,再根据关键字去找数据。
具体例子:比如上述按照时间分页排序的需求如果很强烈的话,可以冗余一张时间和答案ID的映射关系表,先在这个表里查询出最终显示的答案ID,然后再根据这些答案ID去查询答案数据。或者通过大数据平台,把所有数据汇总起来解决。
3.2 垂直分库的事务问题
之前在一个数据库里可以直接通过数据库自带的事务解决,当分到不同的数据库里就不行了,需要使用分布式事务,具体可以参考:https://blog.csdn.net/q610376681/article/details/109090927