Redis复制部分解析

237 阅读2分钟

最近在看 Redis 复制部分的代码,结合 《Redis设计与实现》 写篇文章记录下收获。

replication的状态很重要,

参考 《Redis设计与实现》 15.6.1 步骤1:设置主服务器的地址和端口

执行 slaveof 127.0.0.1 6379 时,调用的命令为 slaveofCommand() ,slaveofCommand() 中调用 replicationSetMaster() 设置主服务器的IP和Port,同时状态(repl_state)会变为 REPL_STATE_CONNECT ,

image.png

参考 《Redis设计与实现》 15.6.2 步骤2:建立套接字连接

在 serverCron() 中,每秒调用一次 replicationCron() ,在 replicationCron() 中如果发现状态(repl_state)为 REPL_STATE_CONNECT ,会调用 connectWithMaster() 连接主服务器, connectWithMaster() 中会为文件描述符建立读写事件监听,并把 syncWithMaster() 设置为回调函数,同时状态(repl_state)会变为 REPL_STATE_CONNECTING ,

image.png

image.png

image.png

参考 《Redis设计与实现》 15.6.3 步骤3:发送PING命令

回调函数 syncWithMaster() 中,做了如下操作:1.删除文件描述符上的写事件,这样就可以等主服务器的 PONG 回复了;2.状态(repl_state)变为 REPL_STATE_RECEIVE_PONG ;3.发送 PING 命令; 从服务器收到主服务器返回的 PONG 后,会触发 回调函数 syncWithMaster() ,并把状态(repl_state)设置为 REPL_STATE_SEND_AUTH ,

image.png

参考 《Redis设计与实现》 15.6.4 步骤4:身份验证

如果从服务器设置 masterauth 选项,发送 auth 命令,并把repl_state 设置为 REPL_STATE_RECEIVE_AUTH,如果主服务器返回的信息不以 – 开头,将状态(repl_state)设置为 REPL_STATE_SEND_PORT , 如果从服务器没有设置 masterauth 选项,直接将 repl_state 设置为 REPL_STATE_SEND_PORT ,

参考 《Redis设计与实现》 15.6.5 步骤5:发送端口信息

执行命令 replconf listening-port ,把状态(repl_state)设置为 REPL_STATE_RECEIVE_PORT ,读取主服务器返回的消息,如果不以 – 开头,将状态(repl_state)设置为 REPL_STATE_SEND_IP ,从服务器执行命令 replconf ip-address <slave_announce_ip> ,将状态(repl_state)设置为 REPL_STATE_RECEIVE_IP ,从服务器读取主服务器返回的消息,将状态(repl_state)设置为 REPL_STATE_SEND_CAPA , 执行命令 replconf capa eof capa psync2 ,将状态(repl_state)设置为 REPL_STATE_RECEIVE_CAPA ,读取主服务器返回消息,并将状态(repl_state)设置为 REPL_STATE_SEND_PSYNC ,

参考 《Redis设计与实现》 15.6.6 步骤6:同步

当状态(repl_state)为REPL_STATE_SEND_PSYNC时,调用 slaveTryPartialResynchronization() ,并将状态设置为 REPL_STATE_RECEIVE_PSYNC 。

image.png

在 slaveTryPartialResynchronization() 中,组装出runid和复制偏移量,然后发送PSYNC命令。这时主服务器调用syncCommand()进行响应,如果主服务器判断出从服务器不需要全量同步,那么直接返回;否则全量同步。

image.png

调用 startBgsaveForReplication() ,执行bgsave,不支持无盘同步的话,会调用 rdbSaveBackground() 将RDB文件保存到硬盘上。如果RDB执行成功,调用 replicationSetupSlaveForFullResync() 给从服务器发送 FULLRESYNC 命令,同时发送runid和复制偏移量。

image.png

image.png

接下来,从服务器继续调用 slaveTryPartialResynchronization() 从主服务器读取返回数据。

image.png

如果返回结果为 PSYNC_FULLRESYNC ,创建临时文件,并监听fd的读事件,并把回调函数设置为 readSyncBulkPayload() ,

image.png

参考 《Redis设计与实现》 15.6.7 步骤7:命令传播