分库分表会带来哪些问题

2,104 阅读6分钟

1 为什么要分库分表

肯定是数据库性能瓶颈的出现,才需要分库分表,但是只要出现性能瓶颈问题就一定要分库分表吗?不一定

1.1 数据库一般会出现什么问题

  • 无法获取连连接。数据库连接数是一种资源,由于数据库硬件的限制,一般都需要控制最大连接数。当并发量达到一定程度就会造成数据库连接不够用。
  • 操作数据变慢。一张表的数据量过大,导致插入、更新、查询、删除操作变慢。
  • 磁盘不足。某个数据库数据量太大,磁盘容量不够或者接近最大容量,导致写入或者查询都很慢。

1.2 出现问题应该怎么分析并解决

针对上述问题,我们应该如何思考?

  • 无法获取连接问题:(1)可以把单个操作改操批量操作,尤其是创建记录,减少获取连接的次数。(2)修改数据库配置,增加最大连接数和缓冲区。
  • 操作数据变慢问题:(1)优化sql和索引。对于慢查询语句,可以优化查询sql,使它尽量用到索引。对于更新和插入语句,可以把单个操作改操批量操作。(2)优化表结构和存储引擎。根据表的使用场景(读多写少、写多读少)合理选择存储引擎,或者对表字段进行拆分和优化。(3)使用集群,做负载均衡,利用主从库做读写分离。(4)缓存。在查询数据库前面做一层缓存。(5)分库分表。把数据存储到不同的数据库或者表,减轻数据库存储和访问的压力。
  • 磁盘不足问题:(1)分库分表。减轻单个数据库存储压力。(2)增加磁盘空间

2 分库分表解决了什么问题

主要是解决单个数据库存储和访问的压力。分库之后,单个数据库存储的数据量就少了,而且响应的请求也减少了。

一般有性能问题都可以采用分库分表解决,但是分库分表并不是性能问题的最优解。
例如无法获取连接问题,是因为单个数据库最大连接数有限,如果分库则可扩大连接数。
例如操作数据慢,分库之后操作也相应的分到了多个数据库商,操作肯定会加快。
例如磁盘不足,分库之后不同的库在不同的物理机器商,磁盘容量肯定比单个数据库大。

3 分库分表带来了什么问题

3.1分布式一致性问题

由于数据存储在不同的节点上,肯定会导致数据不一致。分布式不一致问题的研究可参考文章分布式一致性那些事儿

3.2 跨节点关联表

当A库的a表需要与B库的b表关联查询怎么办?有如下几种解决方案:

  • 冗余字段。如果a表只需要关联出b表的一个或者几个字段,可以考虑在a表中冗余这几个字段,这样就不需要关联b表了。
  • 基础数据冗余表。有的基础数据例如国家、货币等,不同的数据库都要关联它,则在每个数据库中冗余存储这些基础数据。
  • 冗余业务表。还是”A库的a表需要与B库的b表关联查询“场景,可以在A库中冗余存储B库的b表,通过数据同步机制保持与B库的b表数据一致,这样A库就可以直接关联冗余表了。
  • 绑定表。需要关联的数据放在一个节点上。比如按租户分库分表,不同租户之间不会有数据关联查询,同一个租户内的数据都在一个节点上,可以直接关联。 当出现了跨接待你关联的问题,一定要想一想业务逻辑是否合理,如果真的要跨节点关联,一般是通过rpc调用另外一个节点的数据,组装好再返回给前端或者第三方,对外无感知。

3.3 跨节点分页、排序、函数计算

跨节点多库进行查询时,会出现 limit 分页,order by 排序的问题。比如有两个节点,节点 1 存的是奇数 id=1,3,5,7,9……;节点 2 存的是偶数 id=2,4,6,8,10……执行 select*from user_info order by id limit 0,10,则需要在两个节点上各取出 10 条,然后合并数据,重新排序。

max、min、sum、count 之类的函数在进行计算的时候,也需要先在每个分片上执行相应的函数,然后将各个分片的结果集进行汇总和再次计算,最终将结果返回。

或者根据名称模糊分页查询,而名称字段单独存放在i18n表,这个时候就需要先从i18n表中查出所有符合模糊查询的记录,然后从主表中分页查询,当i18n表非常大的时候很耗性能。

3.4 全局主键不唯一

MySQL 的数据库里面字段有一个自增的属性,Oracle 也有 Sequence 序列。如果是一个数据库,那么可以保证 ID 是不重复的,但是水平分表以后,每个表都按照自己的规律自增,肯定会出现 ID 重复的问题,这个时候我们就不能用本地自增的方式了。

解决方案:

  • UUID。缺点是不是递增,而且在分布式环境中还可能出现重复。
  • 基于数据库把id统一存储。所有需要id的服务都从同一个数据库中获取,数据库确保id递增且唯一。但是这样增加了一层调用,当请求量大的时候对数据库也是一种压力。
  • 基于redis。比数据库速度快,也是增加了一层调用,有失败、超时的风险
  • 雪花算法。但是它强依赖机器时钟,如果时钟回拨,则可能导致生成 ID 重复。

3.5 数据库扩容、数据迁移问题

有的分库分表策略在数据库扩容的时候不方便。比如按id的奇偶分表,当某一天按奇偶分表还是太大,需要换再加一张表,则需要换一种分表策略,比如模3或者模5,则需要把之前的两张表数据读取出来重新分表;

有的表按月份分表,每个月增加一张表,则不需要迁移历史数据。

如果采用数值范围分片,只需要添加节点就可以进行扩容了,不需要对分片数据迁移。如果采用的是数值取模分片,则考虑后期的扩容问题就相对比较麻烦。

4 参考

【1】MySQL分库分表会带来哪些棘手的问题?
【2】分库分表需要考虑的问题及方案
【3】为什么需要分库分表
【4】分布式一致性那些事儿