IT技术博客大学习 共学习 共进步

redis源代码分析 - replication

运维和开发 2011-07-16 20:49:07 浏览 4,343 次

   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:

""

建议继续学习

  1. redis源代码分析 - persistence (阅读 32,104)
  2. 关于IO的同步,异步,阻塞,非阻塞 (阅读 16,424)
  3. Redis消息队列的若干实现方式 (阅读 11,926)
  4. 基于Redis构建系统的经验和教训 (阅读 10,383)
  5. 浅谈redis数据库的键值设计 (阅读 9,222)
  6. redis运维的一些知识点 (阅读 8,521)
  7. redis在大数据量下的压测表现 (阅读 8,203)
  8. Redis和Memcached的区别 (阅读 7,943)
  9. redis 运维实际经验纪录之一 (阅读 7,583)
  10. Redis作者谈Redis应用场景 (阅读 7,543)