本文代碼基于 redis 4.0.14 版本斑芜,主要涉及PSYNC協(xié)議相關(guān)。
0. 一圖勝千言
1. 在 SLAVE 上執(zhí)行 slaveof 命令
通過查詢server.commands
找到處理該命令的函數(shù)為void slaveofCommand(client *c)
:
- L2014 如果參數(shù)為 no one祟霍,那么取消之前的同步杏头,將狀態(tài)設(shè)置為 MASTER;
- L2026 如果發(fā)送該命令的 client沸呐,本身就是 SLAVE醇王,那么返回錯(cuò)誤;
- L2039 如果命令中同步的地址與 redis 正在同步的地址相同崭添,那么直接返回寓娩;
- L2047 設(shè)置同步的地址。
- L1943-1944 設(shè)置需要連接的 MASTER 地址;
- L1945 如果當(dāng)前連接另外一個(gè) MASTER棘伴,那么斷開連接寞埠;
- L1952 如果當(dāng)前有 SLAVE,那么斷開連接焊夸;
- L1953 取消復(fù)制流程中的握手任務(wù)仁连;
- L1956 如果本身是 MASTER,那么將信息保存到
cached_master
阱穗; - L1957 最后將
repl_state
設(shè)置為REPL_STATE_CONNECT
饭冬。
至此 slaveof 命令執(zhí)行完畢。
2. SLAVE 上的 replicationCron 定時(shí)任務(wù)
slaveof 命令只是設(shè)置了信息和狀態(tài)揪阶,接下來 redis 的定時(shí)任務(wù)serverCron
會(huì)以每秒一次的頻率執(zhí)行replicationCron
昌抠。
在執(zhí)行 slaveof 命令之后,repl_state
為REPL_STATE_CONNECT
:
L2554 向設(shè)置的 MASTER 地址發(fā)起連接鲁僚。
建立連接扰魂,監(jiān)聽讀寫事件,將repl_state
設(shè)置為REPL_STATE_CONNECTING
蕴茴。
3. 與 MASTER 建立連接之后
連接建立之后會(huì)回調(diào)syncWithMaster
函數(shù):
L1609 如果 socket 有問題劝评,那么關(guān)閉連接,返回REPL_STATE_CONNECT
狀態(tài)倦淀。
L1617-1626 將狀態(tài)置為REPL_STATE_RECEIVE_PONG
蒋畜,向 MASTER 同步發(fā)送 PING 命令,如果失敗也退回REPL_STATE_CONNECT
狀態(tài)撞叽。
驗(yàn)證接收到的 PONG 響應(yīng)姻成,如果有認(rèn)證的需要,那么再加上 AUTH 過程愿棋,如果請(qǐng)求響應(yīng)正常科展,那么狀態(tài)置為REPL_STATE_SEND_PORT
。
接下來發(fā)送 REPLCONF listening-port糠雨,如果有配置slave_announce_ip
再發(fā)送 REPLCONF ip-address才睹,如果一切正常,那么狀態(tài)置為REPL_STATE_SEND_CAPA
甘邀。
接下來向 MASTER 發(fā)送自身支持的特性琅攘,最后狀態(tài)置為REPL_STATE_SEND_PSYNC
。
L1769 在slaveTryPartialResynchronization
方法中向 MASTER 發(fā)送 PSYNC 命令松邪,參數(shù)read_reply
為0時(shí)坞琴,發(fā)送 PSYNC 命令;參數(shù)read_reply
為1時(shí)逗抑,讀取響應(yīng)剧辐。
發(fā)送PSYNC命名寒亥,psync_replid
默認(rèn)為"?",psync_offset
默認(rèn)為"-1"荧关,如果本地有之前緩存的护盈,那么用之前的信息。
讀取 PSYNC 的響應(yīng)羞酗,如果為空繼續(xù)等待腐宋。
如果返回+FULLRESYNC,那么需要全同步檀轨,解析replid和offset信息胸竞。
如果返回+CONTINUE,那么可以增量同步参萄,這里為了 sub-slaves 在重連之后可以繼續(xù)增量同步卫枝,增加了 replid2 這個(gè)參數(shù),具體細(xì)節(jié)這里暫且略過讹挎。
L1547 replicationResurrectCachedMaster
函數(shù)設(shè)置server.master
的信息校赤,狀態(tài)置為REPL_STATE_CONNECTED。
L2240 注冊(cè)readQueryFromClient
函數(shù)筒溃,用于處理收到的增量數(shù)據(jù)马篮。(該函數(shù)的具體細(xì)節(jié)暫且略過)
如果返回錯(cuò)誤,如果是可恢復(fù)的怜奖,返回PSYNC_TRY_LATER重試浑测,如果是不可恢復(fù)的,返回PSYNC_NOT_SUPPORTED歪玲。
L1797 如果可以增量同步迁央,直接返回。
L1835 如果是全量同步滥崩,注冊(cè)readSyncBulkPayload
函數(shù)用于接收處理 RDB岖圈。(該函數(shù)的具體細(xì)節(jié)暫且略過)
如果接收 RDB 正常,最終狀態(tài)置為 REPL_STATE_CONNECTED钙皮,在replicationCreateMasterClient
函數(shù)中也會(huì)注冊(cè)readQueryFromClient
函數(shù)蜂科,用于處理收到的增量數(shù)據(jù)。
4. 再回到 replicationCron
- L2528 與 MASTER 建立 socket 之后株灸,如果超過
server.repl_timeout
閾值沒有進(jìn)行下一步 PING PONG崇摄,那么關(guān)閉連接擎值,退回 REPL_STATE_CONNECT 狀態(tài)慌烧。 - L2536 做全同步傳輸 RDB 期間,如果超過
server.repl_timeout
閾值沒有收到數(shù)據(jù)鸠儿,那么關(guān)閉連接屹蚊,退回 REPL_STATE_CONNECT 狀態(tài)厕氨。 - L2544 做增量同步期間,如果超過
server.repl_timeout
閾值沒有收到數(shù)據(jù)汹粤,那么關(guān)閉連接命斧,退回 REPL_STATE_CONNECT 狀態(tài)。
L2564 周期性向 MASTER 發(fā)送 REPLCONF ACK嘱兼。