0

分库分表相关的问题

2024.09.11 | cuithink | 97次围观

(1)为什么要进行分库操作?

分库指的是将存储在一个数据库中的数据拆分到多个数据库中进行存储。主要原因如下:

1、性能提升:随着业务量的增长,单一数据库可能会面临性能瓶颈。分库可以将数据和请求分散到多个数据库上,从而提高系统的吞吐量和响应时间

2、容量扩展:单一数据库可能收到硬件资源(磁盘,CPU,内存)的限制,分库可以将数据分散到多个数据库上,从而突破这些限制,实现容量的线性扩展

3、可靠性提升:分库可以提高系统的可靠性。当某个数据库出现故障时,其他数据库仍然可以正常工作,从而保证业务的连续性

4、安全性提升:分库可以降低数据泄露的风险。通过将数据分散到多个数据库上,即使某个数据库被攻破,攻击者也无法获取全部数据

5、运维便利性:分库可以提高运维的便利性。每个数据库可以独立进行备份、恢复、监控等操作,降低了运维的复杂性和难度

(2)为什么要进行分表操作?

分表操作是指将一个大表按照一定的规则分解成多张具有独立空间的表的过程。主要原因如下:

1、性能提升:随着业务的发展,数据库中的数据量会不断增长,导致单表的数据量变得非常大。当表的数据量过大时,查询和插入操作会变得非常耗时,性能低下。分表可以将数据分散到多个表中,减少单个表的数据量,从而提高查询和插入的效率。

2、减轻IO和CPU压力:当单表数据量过大时,查询操作可能需要扫描大量的数据,导致磁盘IO和网络IO的压力增大,同时也可能增加CPU的负担。分表可以将数据分散到多个表中,减少单次查询需要扫描的数据量,从而减轻IO和CPU的压力。

3、方便数据管理:随着数据量的增长,单表的数据管理可能会变得非常复杂。分表可以将数据按照一定的规则进行划分,使得数据管理变得更加简单和清晰。

4、 避免锁竞争:在并发访问较高的情况下,单表可能会成为锁竞争的热点,导致性能下降。分表可以将数据分散到多个表中,减少锁竞争的可能性。

(3)如何选择分片键?

分片键的选择并没有啥具体的原则,重点还是结合业务和需求来进行判断,比如可以进行如下选择和判断:

1、选择合适的业务逻辑主体:比如面向用户的应用,可以使用用户id作为分片键,在电商系统重,可以选择订单、卖家等作为分片键

2、如果没有特别明确的业务主体,那么可以考虑数据分布和访问均衡度,尽可能的使每个分表重的数据相对均衡的分布在不同的物理分表中,比如在电商系统中,可以按照商品id和用户id将数据均衡的分布,在金融行业,可以按照用户id或者交易时间进行分表,在物流行业,可以按照订单id或者运输轨迹进行分布,在社交媒体行业,可以按照用户id或者发布时间进行分布

注意:时间类型是一个很好的分片键选择,可以将数据均衡分布

(4)非分片键如何查询?

当按照某一个或者某几个分片键进行分库分表之后,在一些业务场景,难免需要按照非分片键进行查询,此时可以按照如下方式进行查询:

1、对所有库所有表进行遍历查询,找到符合条件的记录,此时的效率一定很低,不建议使用

2、将需要查询的数据信息同步到ES中,在ES中进行高效查询,此方式效率较高,但是需要进行mysql和ES的数据同步

3、可以考虑在不同的分表中存储一些冗余数据,能够在此分表上直接进行查询,而不需要跨表查询,比如,在一个有大量用户但是活跃用户较少的系统中,可以将活跃用户的数据冗余在单独的表中,查询的时候直接查询这张表,而不需要扫描全部的表

4、可以考虑使用基因法,比如在电商系统中,让同一个用户的所有订单全部存储到一个表中,且查询的时候既可以通过用户id,也可以通过订单id。

(5)如何实现跨节点的join关联

在没有分库分表的场景中,join关联多张表的时候非常简单,但是分库分表之后,相关联的表可能不再同一个数据库中,那么如何解决跨库的join操作呢?

1、字段冗余:把需要关联的字段放入主表中,避免关联操作;比如订单表保存了卖家ID(sellerId),你把卖家名字sellerName也保存到订单表,这就不用去关联卖家表了。这是一种空间换时间的思想。

2、全局表:比如系统中所有模块都可能会依赖到的一些基础表(即全局表),在每个数据库中均保存一份。

3、数据抽象同步:比如A库中的a表和B库中的b表有关联,可以定时将指定的表做同步,将数据汇合聚集,生成新的表。一般可以借助ETL工具。

4、应用层代码组装:分开多次查询,调用不同模块服务,获取到数据后,代码层进行字段计算拼装。

(6)分库后,事务问题如何解决?

分库分表后,假设两个表在不同的数据库中,那么本地事务已经无效了,此时需要考虑分布式事务,常见的分布式事务解决方案如下:

1、两阶段提交

2、三阶段提交

3、TCC

4、saga

5、本地消息表

6、最大努力通知

(7)分库分表的分页问题

方案1(全局视野法):

在各个数据库节点查到对应结果后,在代码端汇聚再分页。这样优点是业务无损,精准返回所需数据;缺点则是会返回过多数据,增大网络传输,也会造成空查,

比如分库分表前,你是根据创建时间排序,然后获取第2页数据。如果你是分了两个库,那你就可以每个库都根据时间排序,然后都返回2页数据,然后把两个数据库查询回来的数据汇总,再根据创建时间进行内存排序,最后再取第2页的数据。

方案2(业务折衷法-禁止跳页查询):

这种方案需要业务妥协一下,只有上一页和下一页,不允许跳页查询了。

这种方案,查询第一页时,是跟全局视野法一样的。但是下一页时,需要把当前最大的创建时间传过来,然后每个节点,都查询大于创建时间的一页数据,接着汇总,内存排序返回。

(8)垂直分库、水平分库、垂直分表、水平分表的区别

垂直分库:将原本一个数据库中的表按照业务功能分布到不同的数据库中,每个数据库只包含部分表

水平分库:将一个数据库中的表按照数据行进行拆分,分不到多个数据库中国,每个数据库都包含完成的表结构,但只包含部分数据

垂直分表:将一个数据库中的列拆分到不同的表中,这些表具有相同的主键,但包含不同的列

水平分表:将一个数据库表中的数据拆分到多个相同结构的表中,每个表都包含部分数据行,通常按照一定的规则拆分

(9)分表要停服嘛?不停服怎么做?

不用停服。不停服的时候,应该怎么做呢,主要分五个步骤:

1、编写代理层,加个开关(控制访问新的DAO还是老的DAO,或者是都访问),灰度期间,还是访问老的DAO。

2、发版全量后,开启双写,既在旧表新增和修改,也在新表新增和修改。日志或者临时表记下新表ID起始值,旧表中小于这个值的数据就是存量数据,这批数据就是要迁移的。

3、通过脚本把旧表的存量数据写入新表。

4、停读旧表改读新表,此时新表已经承载了所有读写业务,但是这时候不要立刻停写旧表,需要保持双写一段时间。

5、当读写新表一段时间之后,如果没有业务问题,就可以停写旧表啦


粤ICP备16076548号
发表评论