马上DBScale 就要设计在线动态节点添加这个功能了, 对此自己稍微想了点,记录下。
在线数据节点添加分为2类:
1. 往主从复制的集群中添加一个新的slave节点
这个相对简单,根据之前sqlproxy的实现经验,主要步骤分为线下和线上两部分:
线下, a.选择一个集群中的slave节点 s,停止它的 sql thread (这种情况下dbscale会自动屏蔽这个节点)。
b. 记录slave节点 s执行到的master binlog位置(Relay_Master_Log_File, Exec_Master_Log_Pos)
c. 通过备份工具或手工拷贝将该slave s的数据复制到新的slave节点上
d. 恢复slave s的sql thread(当同步延迟减少到可接受范围内时dbscale会重新启用这个节点)
e. 让新slave节点
change master to 全局的master节点,位置为步骤b中记录的位置
线上,
a. dbscale 上个全局的系统锁,将新slave的信息添加进全局的集群拓扑元数据中
b. 解除全局系统锁
c. 当新slave的延迟减少到可接受范围内是dbscale会启用这个节点来提供服务
这个方案对系统的影响很小,主要是线上的全局系统锁,但那个很快就释放了。 线下的操作可以由脚本来完成。
通过把脚本的调用集成到dbscale的管理接口中可以实现自动化处理。
2. 往一个sharding集群中添加一个新的partition节点
这个过程较为复杂。 sharding指的是对一张大表的sharding, 把一张大表分散到多个逻辑节点上,而逻辑节点可能部署在不同的物理机器上。
首先是分区算法的单调性,这里主要指的是HASH分区算法 (range分区的单调性很容易), 例如一致性HASH算法, 可以参考下面这个连接:
http://blog.csdn.net/sparkliang/article/details/5279393
在确保了算法的单调性之后,我们就可以确保往集群中添加新节点的过程中发生的数据重新分布只会是数据从旧的节点移到新的节点。
这样问题就简化为如何在线地将一个partition中的部分数据迁移到一个新的partition中。
假设一个旧的partition 为p1, 新的partition为p2, p1的一个备份节点p3, p2 的备份节点p4
线下:
建立p2和p4的主从复制关系, 然后通过dbscale的管理接口将它们加入集群
线上:
1.和之前一样,将新的节点添加进集群的时候会上一次全局系统锁。
2. 根据新的集群拓扑计算出一个新的一致性HASH的环形分布(我们假设旧的分布为 hash1 新的为hash2)
3. dbscale 中断p1 和p3之间的主从复制, 并记录p3的执行到的master binlog位置
4. dbscale 模拟IO thread 从p1上根据步骤3记录的位置开始拉取p1的binlog
5. dbscale 根据hash 2将拉取到的binlog中的event分为两部分log1 和log2
log1为按照hash2应该落在p1节点的event, log2为按照hash2应该落在p2节点的event
6. dbscale根据hash 2将p3节点中相关的数据移动到p2 上
7. 当步骤6执行完, dbscale暂停从p1上拉取binlog,
把log1 开始作用到 p3节点, log2 开始作用到p4节点,
同时重新开始从p1拉binlog,并记录到log11 和log22
8. 当log1和log2执行结束后, dbcale将log11 和log 22应用到 p3和p2节点,
同时判断延迟,如果p3和p1的延迟较高,那么重新记录log1 和log2,
当log11和log22执行结束后,再次应用log1和log2
9. 重复步骤8 直到p3和p1的延迟可以接受, dbscale锁定节点p1 对应的partition分区,
还有要锁定全局的小表的写操作,等待p3和p2上所有日志执行完
10. 让p2分区开始提供服务(dbscale进行请求转发时先用hash1 计算,如果是发给p1的,再按照
hash2计算,如果是发给p2的,将请求发给p2)
11. 提升p3为p1对应分区的主节点, 记录p3的binlog位置(注意不是p3执行的master的binlog位置,
而是p3自己的binlog位置)。
12. dbscale解除p1对应partition分区的锁定
13. 对p1的数据根据hash2 删除属于p2的数据
14. 让p1 按照步骤11中记录的位置change master 到 p3.
到此位置一个分区的迁移结束,进入下一个分区的迁移。 当所有的分区迁移完成的时候 dbscale上全局系统锁,将hash1正式替换为hash2, 数据重分布完成。
这个方案对在线系统的可用性影响也不大,需要注意的是log1 log2是的执行过程中p2还从全局小表的master上同步数据,所以p1的binlog中关于小表的部分需要被写入log1,并在p3上执行。
另外在数据迁移过程中应尽可能保证集群稳定,如果发生主从切换的话,可能会出现混乱。。。
1. 往主从复制的集群中添加一个新的slave节点
这个方案对系统的影响很小,主要是线上的全局系统锁,但那个很快就释放了。 线下的操作可以由脚本来完成。
通过把脚本的调用集成到dbscale的管理接口中可以实现自动化处理。
2. 往一个sharding集群中添加一个新的partition节点
这个方案对在线系统的可用性影响也不大,需要注意的是log1 log2是的执行过程中p2还从全局小表的master上同步数据,所以p1的binlog中关于小表的部分需要被写入log1,并在p3上执行。
另外在数据迁移过程中应尽可能保证集群稳定,如果发生主从切换的话,可能会出现混乱。。。