Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > Mysql分库分表

Mysql分库分表实现方式

作者:暴躁的鱼

这篇文章详细介绍了分库分表的概念,原因,如何实现,以及不同中间件的优缺点,同时,也介绍了如何进行数据迁移和扩容缩容,以及如何处理分库分表后的ID和事务问题

1、背景

Mysql作为做流行的开源数据库,在各大互联网公司被广泛使用。通常我们用一个库就可以满足需求,但是随着业务的增长,数据量和并发量迅速膨胀。

Mysql单表数据量到百万以上的时候,查询效率就会受到影响,另外Mysql单库能承受的并发也有限。

这个时候我们需要做分库分表,来提高数据库的性能和扩展性

2、为什么分库分表

2.1 分表

单表数据量太大会极大的影响sql执行效率,一般来说单表达到几百万的时候,性能就相对较差了,就需要分表了

2.2 分库

单个库一般最大支持到2000并发,超过就需要分库了,一个健康的单库并发值最好控制在1000左右

#分库分表前分库分表后
并发支撑情况MySQL 单机部署,扛不住高并发MySQL 从单机到多机,能承受的并发增加了多倍
磁盘使用情况MySQL 单机磁盘容量几乎撑满拆分为多个库,数据库服务器磁盘使用率大大降低
SQL 执行性能单表数据量太大,SQL 越跑越慢单表数据量减少,SQL 执行效率明显提升

数据量大,就分表;并发高,就分库。

2.3 带来的问题

3、不同分库中间件的优缺点

3.1 Sharding-jdbc

1、当当开源的,client层方案

2、支持分库分表,读写分离,分布式ID生成,柔性事物(最大努力送达型事物,TCC事物)

3、社区比较活跃

适合中小型公司

3.2 Mycat

1、proxy层方案

2、支持的功能完善

3、很流行,社区非常活跃

适合大型公司

3.3 如何选择

推荐使用sharding-jdbc和mycat:

4、如何拆分

4.1、水平拆分(用的最多)

把一个表的数据拆分到多个表中,但是每个表的结构都一样,把数据均匀的放到不同的表里,用多个表来抗并发

根据特定字段来拆分:

比如订单表根据订单ID来拆分,分到32个库,每个库32张表,那么orderID%32决定落在哪个库,orderID/32%32决定落在那个表。

而且这儿还有两种分库分表的方式:

各自优缺点:

4.2、垂直拆分

把一个有很多字段的表拆分到多个表或者多个库上去,把访问频率高的热点字段和访问频率低的非热点字段分开放到不同的表。因为数据库有缓存,热点字段越少,缓存里可以存更多的行

5、分库分表方案确定后,还需要解决以下问题

5.1 如何设计才可以让系统从未分库分表平滑的动态切换到分库分表上?

停机迁移

双写迁移方案

这种方案不用停机。

简单来说,就是在线上系统里面,之前所有写库的地方,增删改操作,除了对老库增删改,都加上对新库的增删改,这就是所谓的双写,同时写俩库,老库和新库。

然后系统部署之后,新库数据差太远,用之前说的导数工具,跑起来读老库数据写新库,写的时候要根据 gmt_modified 这类字段判断这条数据最后修改的时间,除非是读出来的数据在新库里没有,或者是比新库的数据新才会写。简单来说,就是不允许用老数据覆盖新数据。

导完一轮之后,有可能数据还是存在不一致,那么就程序自动做一轮校验,比对新老库每个表的每条数据,接着如果有不一样的,就针对那些不一样的,从老库读数据再次写。反复循环,直到两个库每个表的数据都完全一致为止。

接着当数据完全一致了,就 ok 了,基于仅仅使用分库分表的最新代码,重新部署一次,不就仅仅基于分库分表在操作了么,还没有几个小时的停机时间,很稳。所以现在基本玩儿数据迁移之类的,都是这么干的。

这个方法的缺点就是代码里需要同时支持两个库的过度阶段,稍微麻烦一点,但是不需要停机,可以平滑迁移。

5.2 动态扩容缩容的分库分表方案?

分库分表完成后,如果数据继续增加,原来的方案不能满足业务了,需要继续扩大更多库更多表,那么还要再来一次分库分表吗?

这样处理会很麻烦,因为后续可能还不够,分库分表数据迁移非常费劲。那么我们可以采取一次性分足够多的库和表,这样避免了后续迁移数据的问题。

一开始分库一次性分够,32库*32表,一共1024张表,根据某个 id 先根据 32 取模路由到库,再根据 32 取模路由到库里的表。

orderIdid % 32 (库)id / 32 % 32 (表)
25938
118955
352011
45931715

刚开始的时候,这个库可能就是逻辑库,建在一个数据库上的,就是一个 MySQL 服务器可能建了 n 个库,比如 32 个库。后面如果要拆分,就是不断在库和 MySQL 服务器之间做迁移就可以了。然后系统配合改一下配置即可。

比如说最多可以扩展到 32 个数据库服务器,每个数据库服务器是一个库。如果还是不够?最多可以扩展到 1024 个数据库服务器,每个数据库服务器上面一个库一个表。因为最多是 1024 个表。

这么搞,是不用自己写代码做数据迁移的,都交给 DBA 来搞好了,但是 DBA 确实是需要做一些库表迁移的工作,但是总比你自己写代码,然后抽数据导数据来的效率高得多吧。

这里对步骤做一个总结:

  1. 设定好几台数据库服务器,每台服务器上几个库,每个库多少个表,推荐是 32 库 * 32 表,对于大部分公司来说,可能几年都够了。
  2. 路由的规则,orderId 模 32 = 库,orderId / 32 模 32 = 表
  3. 扩容的时候,申请增加更多的数据库服务器,装好 MySQL,呈倍数扩容,4 台服务器,扩到 8 台服务器,再到 16 台服务器。
  4. 由 DBA 负责将原先数据库服务器的库,迁移到新的数据库服务器上去,库迁移是有一些便捷的工具的。
  5. 我们这边就是修改一下配置,调整迁移的库所在数据库服务器的地址。
  6. 重新发布系统,上线,原先的路由规则变都不用变,直接可以基于 n 倍的数据库服务器的资源,继续进行线上系统的提供服务。

6、分库分表之后,id 主键如何处理?

6.1、设置数据库 sequence 或者表自增字段步长

适合的场景:

6.2、UUID

不具有有序性,作为ID对索引不友好,会导致 B+ 树索引在写的时候有过多的随机写操作(连续的 ID 可以产生部分顺序写),不适合做主键。

适合的场景:

6.3、获取当前系统时间, 并发高的时候可能会重复

适合的场景:

6.4、snowflake 算法

7、分库分表后,事务如何处理?

分库分表以后,可能会出现跨库事务,这种事务怎么处理呢?

7.1 优化方案避免出现跨库事务

7.2 跨库事务的处理

Mycat也能支持XA事务。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文