redis源代碼分析-replication九月 1, 2011 by Eugene · Leave a Comment edis的復(fù)制方法和機(jī)制都比較簡單。 slaveof masterip port 在slave端鍵入命令之后,,就開啟了從master到slave的復(fù)制,。一個master可以有多個slave,master有變化的時候會主動 的把命令傳播給每個slave,。slave同時可以作為其他的slave的master,,前提條件是這個slave已經(jīng)處于穩(wěn)定狀態(tài) (REDIS_REPL_CONNECTED)。slave在復(fù)制的開始階段處于阻塞狀態(tài)(sync_readline)無法對外提供服務(wù),。 數(shù)據(jù)的有向圖會讓redis的運(yùn)維很有搞頭,。 slaveof no one 從slave狀態(tài)的轉(zhuǎn)換回master狀態(tài),切斷與原master的數(shù)據(jù)同步,。 復(fù)制的順序是從左到右。綠色的過程表示replstate復(fù)制狀態(tài)的變遷,復(fù)制相關(guān)的函數(shù)主要在src/replication.c里,,紅色為master的復(fù)制函數(shù),,藍(lán)色的為slave使用的復(fù)制函數(shù)。 slave端接收到客戶端的slaveof masterip ort命令之后,,根據(jù)readonlyCommandTable找到對應(yīng)的函數(shù)為slaveofCommand,。slaveofCommand會保存 masterip,masterport,,并把server.replstate改成REDIS_REPL_CONNECT,,然后返回給客戶端OK。 slave端主線程在已經(jīng)注冊時間事件serverConn(redis.c 518)里執(zhí)行replicationCron(redis.c 646)來開始與master的連接,。調(diào)用syncWithMaster()開始與master的通信,。經(jīng)過校驗(yàn)之后,會發(fā)送一個SYNC command給master端,,然后打開一個臨時文件用于存儲接下來master發(fā)過來的rdb文件數(shù)據(jù),。再添加一個文件事件注冊 readSyncBulkPayload函數(shù),這個就是接收rdb文件的數(shù)據(jù)的函數(shù),,然后修改狀態(tài)為REDIS_REPL_TRANSFER,。 master接收到SYNC command后,跳轉(zhuǎn)到syncCommand函數(shù)(replication.c 556),。syncCommand會調(diào)度rdbSaveBackground函數(shù),,啟動一個子進(jìn)程做一個全庫的持久化rdb文件,并把狀態(tài)改為 REDIS_REPL_WAIT_BGSAVE_END,。 master的主線程的serverCron會等待做持久化的子進(jìn)程的退出,,并判斷退出的狀態(tài)是否是正常。 if ((pid = wait3(&statloc,WNOHANG,NULL)) != 0) { if (pid == server.bgsavechildpid) { backgroundSaveDoneHandler(statloc); } else { .... 如果子進(jìn)程正常退出,,會轉(zhuǎn)到backgroundSaveDoneHandler函數(shù),。backgroundSaveDoneHandler 處理每次rdbSaveBackground成功后的收尾工作,并打開剛剛產(chǎn)生的rdb文件,。然后注冊一個sendBulkToSlave函數(shù)用于發(fā)送 rdb文件,,狀態(tài)切換至REDIS_REPL_SEND_BULK。 sendBulkToSlave作用就是根據(jù)上面打開的rdb文件,,讀取并發(fā)送到slave端,,當(dāng)文件全部發(fā)送完畢之后修改狀態(tài)為REDIS_REPL_ONLINE。 我們回到slave,,上面講到slave通過readSyncBulkPayload接收rdb數(shù)據(jù),,接收完整個rdb文件后,會清空整個數(shù)據(jù)庫 emptyDb()(replication.c 374),。然后就通過rdbLoad函數(shù)載入接收到的rdb文件,,于是slave和master數(shù)據(jù)就一致了,再把狀態(tài)修改為 REDIS_REPL_CONNECTED。 接下來就是master和slave之間增量的傳遞的增量數(shù)據(jù),,另外slave和master在應(yīng)用層有心跳檢測(replication.c 543),和超時退出(replication.c 511),。 最后再給出一個replstate狀態(tài)圖 slave端復(fù)制狀態(tài) REDIS_REPL_NONE:未復(fù)制的狀態(tài) REDIS_REPL_CONNECT:已經(jīng)接收到slaveof命令,,但未發(fā)出sync命令給master REDIS_REPL_TRANSFER:已經(jīng)發(fā)出sync,但還沒接收完rdb文件 REDIS_REPL_CONNECTED:已經(jīng)接收完rdb文件,,開始增量接收復(fù)制內(nèi)容 maste端redis_client的復(fù)制狀態(tài) REDIS_REPL_WAIT_BGSAVE_START:bgsave被搶占,,等待bgsave為其持久化進(jìn)行工作。 REDIS_REPL_WAIT_BGSAVE_END:等待bgsave持久化rdb文件,。 REDIS_REPL_SEND_BULK:rdb文件已經(jīng)生成,。開始拷貝給slave。 REDIS_REPL_ONLINE:rdb拷貝完畢,,開始增量復(fù)制,。 另外在syncCommand函數(shù)里有幾種可能性 bgsave進(jìn)程未啟動,則啟動,。 bsave已啟動,,且已經(jīng)存在另外的一個slave連接,已經(jīng)由這個連接開啟了bgsave,,則等待bgsave完畢,,共享這次的持久化。 bsave已啟動,,但不是由slave連接所啟動的,,則等待下次bgsave的退出。在updateSlavesWaitingBgsave函數(shù)里再次啟動bgsave進(jìn)程,。 update:
關(guān)聯(lián)性文章: 淺談redis數(shù)據(jù)庫的鍵值設(shè)計(jì) redis源代碼分析–protocol
原創(chuàng)文章,,轉(zhuǎn)載請注明: 文章地址redis源代碼分析-replication |
|