redis源代码分析 - replication
redis的复制方法和机制都比较简单。
slaveof masterip port
在slave端键入命令之后,就开启了从master到slave的复制。一个master可以有多个slave,master有变化的时候会主动的把命令传播给每个slave。slave同时可以作为其他的slave的master,前提条件是这个slave已经处于稳定状态(REDIS_REPL_CONNECTED)。slave在复制的开始阶段处于阻塞状态(sync_readline)无法对外提供服务。
数据的有向图会让redis的运维很有搞头。
slaveof no one
从slave状态的转换回master状态,切断与原master的数据同步。
下面根据图形来描述一个复制全过程。
复制的顺序是从左到右。绿色的过程表示replstate复制状态的变迁,复制相关的函数主要在src/replication.c里,红色为master的复制函数,蓝色的为slave使用的复制函数。
slave端接收到客户端的slaveof masterip ort命令之后,根据readonlyCommandTable找到对应的函数为slaveofCommand。slaveofCommand会保存masterip,masterport,并把server.replstate改成REDIS_REPL_CONNECT,然后返回给客户端OK。
slave端主线程在已经注册时间事件serverConn(redis.c 518)里执行replicationCron(redis.c 646)来开始与master的连接。调用syncWithMaster()开始与master的通信。经过校验之后,会发送一个SYNC command给master端,然后打开一个临时文件用于存储接下来master发过来的rdb文件数据。再添加一个文件事件注册readSyncBulkPayload函数,这个就是接收rdb文件的数据的函数,然后修改状态为REDIS_REPL_TRANSFER。
master接收到SYNC command后,跳转到syncCommand函数(replication.c 556)。syncCommand会调度rdbSaveBackground函数,启动一个子进程做一个全库的持久化rdb文件,并把状态改为REDIS_REPL_WAIT_BGSAVE_END。
master的主线程的serverCron会等待做持久化的子进程的退出,并判断退出的状态是否是正常。
if ((pid = wait3(&statloc,WNOHANG,NULL)) != 0) { if (pid == server.bgsavechildpid) { backgroundSaveDoneHandler(statloc); } else { ....
如果子进程正常退出,会转到backgroundSaveDoneHandler函数。backgroundSaveDoneHandler 处理每次rdbSaveBackground成功后的收尾工作,并打开刚刚产生的rdb文件。然后注册一个sendBulkToSlave函数用于发送rdb文件,状态切换至REDIS_REPL_SEND_BULK。
sendBulkToSlave作用就是根据上面打开的rdb文件,读取并发送到slave端,当文件全部发送完毕之后修改状态为REDIS_REPL_ONLINE。
我们回到slave,上面讲到slave通过readSyncBulkPayload接收rdb数据,接收完整个rdb文件后,会清空整个数据库emptyDb()(replication.c 374)。然后就通过rdbLoad函数载入接收到的rdb文件,于是slave和master数据就一致了,再把状态修改为REDIS_REPL_CONNECTED。
接下来就是master和slave之间增量的传递的增量数据,另外slave和master在应用层有心跳检测(replication.c 543),和超时退出(replication.c 511)。
最后再给出一个replstate状态图
slave端复制状态
REDIS_REPL_NONE:未复制的状态
REDIS_REPL_CONNECT:已经接收到slaveof命令,但未发出sync命令给master
REDIS_REPL_TRANSFER:已经发出sync,但还没接收完rdb文件
REDIS_REPL_CONNECTED:已经接收完rdb文件,开始增量接收复制内容
maste端redis_client的复制状态
REDIS_REPL_WAIT_BGSAVE_START:bgsave被抢占,等待bgsave为其持久化进行工作。
REDIS_REPL_WAIT_BGSAVE_END:等待bgsave持久化rdb文件。
REDIS_REPL_SEND_BULK:rdb文件已经生成。开始拷贝给slave。
REDIS_REPL_ONLINE:rdb拷贝完毕,开始增量复制。
另外在syncCommand函数里有几种可能性
bgsave进程未启动,则启动。
bsave已启动,且已经存在另外的一个slave连接,已经由这个连接开启了bgsave,则等待bgsave完毕,共享这次的持久化。
bsave已启动,但不是由slave连接所启动的,则等待下次bgsave的退出。在updateSlavesWaitingBgsave函数里再次启动bgsave进程。
update:
建议继续学习:
- redis源代码分析 - persistence (阅读:31116)
- 关于IO的同步,异步,阻塞,非阻塞 (阅读:14458)
- Redis消息队列的若干实现方式 (阅读:10686)
- 基于Redis构建系统的经验和教训 (阅读:9256)
- 浅谈redis数据库的键值设计 (阅读:8264)
- redis在大数据量下的压测表现 (阅读:7363)
- redis运维的一些知识点 (阅读:7391)
- Redis和Memcached的区别 (阅读:6740)
- Redis作者谈Redis应用场景 (阅读:6545)
- redis 运维实际经验纪录之一 (阅读:6451)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:hoterran 来源: 运维和开发
- 标签: redis replication 同步
- 发布时间:2011-07-16 20:49:07
- [65] Oracle MTS模式下 进程地址与会话信
- [64] Go Reflect 性能
- [64] 如何拿下简短的域名
- [58] IOS安全–浅谈关于IOS加固的几种方法
- [58] 【社会化设计】自我(self)部分――欢迎区
- [57] android 开发入门
- [57] 图书馆的世界纪录
- [51] 视觉调整-设计师 vs. 逻辑
- [46] 读书笔记-壹百度:百度十年千倍的29条法则
- [45] 界面设计速成