RSYNC 改造方案 - 少一
#1697
Replies: 2 comments 1 reply
-
1、优先简单配置文件传输的速度 |
Beta Was this translation helpful? Give feedback.
0 replies
-
@luky116 @wangshao1 当前3.5.1已经合入主从复制新机制。请问这个方案是否与实际方案完全一致? |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
背景
pika主从节点进行全量数据同步通过rsync命令实现。rsync命令需要单独启动一个进程来实现数据传输,在pika进程重启/退出或者机器故障等情况下与pika进程不同步。因此计划将dump文件传输的功能进行集成到pika进程中,使用单独线程进行处理。
团队调研了openrsync工具以及braft中下载snapshot的代码以及基于pika的网络pink自己实现文件传输的功能。综合对比后,考虑基于pink网络库实现文件传输。新的文件传输方式需同时实现:1.支持限速策略。2.容忍网络丢包,重传。3.支持文件级数据校验。
主从复制流程
Pika支持了redis中的slaveof命令用于在不同的pika实例间进行数据同步。数据同步包括全量同步和增量同步两部分。pika中使用了两个状态机和Auxilary_thread后台线程维护整个同步状态。
主从同步整体执行流程为:
整体同步流程涉及到两个状态机,一个状态机表示pika_server状态,主要用于slave节点收到slaveof请求之后到开始同步数据之前的状态流转。包括:
PIKA_REPL_NO_CONNECT,PIKA_REPL_SHOULD_META_SYNC,PIKA_REPL_META_SYNC_DONE,PIKA_REPL_ERROR。第二个状态机表示每个slot的状态,状态包括kNoConnect,kTryConnect,kTryDBSync,kWaitDBSync,kWaitReply,kConnected,kError,kDBNoConnect。状态流转图如下所示:
注:图中集中在增量同步之前阶段的状态转移,未包含请求错误导致状态流转到kError的情况,也没有包括连接keepalive超时或连接断开时状态被重置为kNoConnect的过程。
状态流转主要是通过auxiliary_thread线程的大while循环与网络库的回调函数完成状态的流转。大致流程为:
PIKA_REPL_NO_CONNECT -> PIKA_REPL_SHOULD_META_SYNC: 当slave节点收到slaveof节点请求之后,会调用removeMaster删除已有的master,接着调用SetMaster设置pika_server的状态为meta_sync。
PIKA_REPL_SHOULD_META_SYNC -> PIKA_REPL_SHOULD_METASYNC_DONE: PikaAuxiliaryThread在大循环中检测到该状态之后,执行SendMetaSyncRequest向master节点发起metasync请求。当slave节点收到metasync的回包之后,会执行HandleMetaSyncResponse函数,如果请求成功且解析成功,比对主从节点的db拓扑结构,如果一致,将状态变为PIKA_REPL_META_SYNC_DONE,同时激活SyncSlaveSlot状态机,将slot状态流转到kTryConnect。
**kNoConnect -> kTryConnect:**metasync阶段执行完成后,会启动SyncSlaveSlot的状态机,并将状态流转到kTryConnect。
**kTryConnect -> kWaitReply:**PikaAuxiliaryThread检测到某个slot处于该状态之后,发送trysync命令给master,状态流转到kWaitReply。
kWaitReply -> kConnected: 收到trysync命令的回包之后,如果master节点有对应binlog的offset,状态流转到kConnected。
kWaitReply -> kTryDBSync: 收到trySync命令的回包之后,如果master节点没有对应binlog的offset,状态流转到kTryDBSync。
kTryDBSync -> kWaitDBSync: 对处于kWaitDBSync状态的slot,auxiliaryThread会发送dbsync命令给master,slot状态重新流转到kWaitReply。
**kWaitReply -> kWaitDBSync: **收到dbsync回包之后,状态流转到kWaitDBSync。等待master通过rsync推送引擎文件。auxiliaryThread会周期性地对处于kWaitDBSync状态的slot执行TryUpdateMasterOffset,其主要工作就是检查数据同步是否已经完成,如果已经完成,切db,更新状态为kConnected。进行后续增量数据同步。
方案
本次主从复制修改的内容对应上一节中的步骤9。类似于rsync,数据同步也是基于client-server模式,主从节点在启动时都需要启动一个server,不同的是rsync需要启动一个子进程。同步文件时,slave节点作为client端,master节点作为server端,slave从server端拉取引擎文件并进行加载。整体交互流程如下图所示:
数据传输
新方案的数据传输方式是使用protobuf通信协议,slave节点主动向master拉取文件内容。每个文件可能被拆分为多次网络请求。具体每次请求中传输多少数据量根据限速策略进行调整。proto文件定义如下所示。
slave在GetFileRequest中会设置期望拉取的文件名,本次请求要拉取的字节数,文件的偏移量。master根据请求信息读取文件,将数据添加到GetFileResponse中。其中eof表示请求的文件是否已经读完,如果读取完成,将文件的checksum一同追加到回包中,slave节点在整个文件传输完成之后会比对MD5。
新的主从复制方式考虑使用slave从master拉取文件(pull)的方式。考虑不使用master推送(push)方式的原因包括:
下载限速
文件下载限速的逻辑,计划参考braft中install_snapshot的限速策略。即限制单位时间内下载的数据量。总体思路是:
限制单位时间内下载的数据量,有两个配置参数:_throttle_throughput_bytes,指每秒最多可以接收的字节数。_check_cycle:指每秒被分成多少个周期。在拉取snapshot之前,follower首先调用throttled_by_throughput,传入期望拉取的字节数,throttled_by_throughput内部会判断_cur_throughput_bytes + bytes是否大于_throttle_throughput_bytes/check_cycle,如果小于,表示当前统计周期内余额还没有用完,更新_cur_throughput_bytes即可。否则,表明当前周期内余额不足,检查下当前时间距离当前统计周期是否已经大于一个cycle,如果不是,表明还是在一个统计周期里,那么剩多少余额就返回多少余额。如果不是,表明可以使用新的周期里的余额,更新_last_throughput_check_time_us和_cur_throughput_bytes。
在请求收到回复之后,调用return_unused_throughput返回未使用的余额。分别传入当初成功申请的余额,实际传输的字节数和持续时间。函数内部会首先根据当前时间,_last_throughput_check_time_us和持续时间计算申请的时候是不是在上一个周期,如果是,什么都不做。如果不是,将未使用的token还给_cur_throughput_bytes中。
异常处理
对于slave节点来说,slave节点会记录此时期望拉取的filename和offset,同时会校验收到的GetFileResponse中的filename和offset是否与本地相等。如果不是期望的数据,将请求直接丢弃即可。所以请求是幂等的。
对于master节点来说,本地并不持有状态。对于重传的请求,损耗相当于多读了一次文件。不会对数据一致性造成影响。
2.同步历史数据过程中,如何应对master节点宕机?
master节点本身并不持有状态,只要master宕机重启之后,dump的文件存在且完整,即可正常对外提供服务。
3.同步历史数据过程中,如何应对slave节点宕机?
在之前版本的主从同步实现中,openrsync工具会进行增量同步,已经同步的文件不会再同步,减少不必要的IO。新的主从同步方案中,可以在slave端持久化一些meta信息用来在进程被重新拉起时恢复状态。具体实现是,slave节点在下载完一个文件之后,将文件名和md5 checksum记录在内存中,并周期性持久化到一个指定的文件中。当slave宕机重启恢复之后,进程在启动时会去加载该文件,读出记录的文件名和checksum,遍历记录的文件,计算checksum,如果文件存在且checksum校验通过,就不需要重新拉取,否则重新从master拉取文件。如此实现,可以保证slave节点宕机恢复之后,只需要重新拉取少部分重复文件。
风险点
兼容性。新的主从同步模式需要master和slave同时升级到新版本还可以,存在兼容性。因此初步考虑在第一版实现中,保留rsync和新方案两种方式,默认使用rsync方式,并支持通过client发命令修改主从的历史数据同步方式。
传输性能待验证。基于pink使用protobuf方式同步历史数据,传输性能是否会有降低待验证。目前想到的是如果传输性能不够,slave增加线程数量并行拉取文件。
测试场景
1.多slave建立同步关系。
2.测试主从同步时存量数据量要达到1TB。
Beta Was this translation helpful? Give feedback.
All reactions