扩容问题的来源

在项目初期,我们部署了三个数据库 A、B、C,此时数据库的规模可以满足我们的业务需求。为了将数据做到平均分配,我们在 Service 服务层使用 uid%3 进行取模分片,从而将数据平均分配到三个数据库中,哈希流程如图所示: 

MySQL 数据库平滑扩容方案剖析 - 第一篇_数据迁移

后期随着用户量的增加,用户产生的数据信息被源源不断的添加到数据库中,最终达到数据库的最佳存储容量。

如果此时继续向数据库中新增数据,会导致数据库的 增删改查等操作变慢,进而影响整个服务的响应速度。

这时,我们需要增加新的节点,对数据库进行水平扩容,那么加入新的数据库 D 后,数据库的规模由原来的 3 个变为 4 个,哈希流程如图所示:

MySQL 数据库平滑扩容方案剖析 - 第一篇_mysql扩容_02

此时由于分片规则发生了变化(uid%3 变为 uid%4),导致大部分的数据,无法命中原有的数据,需要重新进行分配,要做大量的数据迁移处理。

举例:

如果之前 uid=3,取模 3%3=0, 是分配在 A 库上;新加入 D 库后, 现在uid=3 取模 3%4=3,变成分配在 D 库上,但是读取的话D库上肯定不存在uid为3的数据,必须把旧数据都迁移正确才行。

以上就是数据库扩容问题的来源!

哈希流程和数据迁移如下图

MySQL 数据库平滑扩容方案剖析 - 第一篇_mysql扩容_03

哈希法扩容的总结:

新增节点时会有大量的旧数据需要迁移,迁移过程中可能需停服,等全部数据迁移完成后才能哈希到正确的数据库。但这样会面临大量的数据压力,并且对服务造成极大的不稳定性

方案一(停服迁移再开服方案 )

1. 发布停服公告

为了进行数据的重新拆分,在停止服务之前,我们需要提前通知用户,比如:我们的服务会在 yyyy-MM-dd 进行升级,给您带来的不便敬请谅解

2. 停服

关闭 Service,不再对数据库进行增删改查等操作

3. 增加新的数据库节点

购买或建立新的数据库,建好数据库和表

4. 旧数据迁移

将旧库中的全部数据按照新的哈希算法,将数据重新分配,更新到正确的数据库

5. 数据校验

开发一个程序对旧库和新库中的数据进行校验,比对,确保重分配是正确的

6. 更改数据库配置和哈希算法

Service配置中添加新库连接地址,账号密码等;修改 Service 层的算法,也就是将原来的 uid%3 变为 uid%4

7. 开服

重启 Service 服务

方案一总结

停止服务之后, 能够保证迁移工作的正常进行。 但是服务停止,伤害用户体验, 而且造成了时间压力, 必须在指定的时间内完成迁移,且不能出错,每一步都要有回滚预案