Redis主備同步
slave狀態變遷
#define REDIS_REPL_NONE 0 /* No active replication */
#define REDIS_REPL_CONNECT 1 /* Must connect to master */
#define REDIS_REPL_CONNECTING 2 /* Connecting to master */
#define REDIS_REPL_RECEIVE_PONG 3 /* Wait for PING reply */
#define REDIS_REPL_TRANSFER 4 /* Receiving .rdb from master */
#define REDIS_REPL_CONNECTED 5 /* Connected to master */
server.repl_state儲存slave當前的複製狀態
* redis啟動時初始化為REDIS_REPL_NONE
* 當接受到slaveof命令後,該redis轉換為slave,同時狀態變為REDIS_REPL_CONNECT
周期性執行的replicationCron會檢查slave當前的狀態,來執行不同的操作
- 如果slave處於REDIS_REPL_CONNECT,調用connectWithMaster建立到master的連接,狀態轉換為REDIS_REPL_CONNECTING
- 連接建立後,向master發送PING,狀態轉換為REDIS_REPL_RECEIVE_PONG
- 接受到PONG後,如果master配置了需要認證,則slave發送AUTH消息,AUTH通過後;slave發送REPLCONF listening-port消息到master告知自身監聽的端口;最後向master發送SYNC命令來請求同步rdb文件,同時狀態轉換為REDIS_REPL_TRANSFER。
- 當master向slave發送rdb後,slave就開始讀取rdb文件(master發送rdb前會先告知rdb文件的總長度),slave接受完rdb文件後,會emptyDb清空數據庫,然後調用rdbLoad加載從master接受到的rdb文件,加載完成後狀態變為REDIS_REPL_CONNECTED,接下來slave會繼續接受從master同步過來的新操作,以保證主備的一致性。
master狀態變遷
#define REDIS_REPL_WAIT_BGSAVE_START 6 /* We need to produce a new RDB file. */
#define REDIS_REPL_WAIT_BGSAVE_END 7 /* Waiting RDB file creation to finish. */
#define REDIS_REPL_SEND_BULK 8 /* Sending RDB file to slave. */
#define REDIS_REPL_ONLINE 9 /* RDB file transmitted, sending just updates. */
server.slaves裏維護所有的slave列表,slave.replstate裏記錄著每個slave當前的同步狀態(從master的視角看)。
- 當master接受到slave發來的sync/psync命令時,將該slave的狀態轉換為REDIS_REPL_WAIT_BGSAVE_START
- master為該slave後台啟動rdbSaveBackground,並將該slave的狀態轉換為REDIS_REPL_WAIT_BGSAVE_END (如果master己收到sync時,master正在為某個slave轉儲rdb文件,則新的slave可以直接進入REDIS_REPL_WAIT_BGSAVE_END狀態)
- 當rdbSaveBackground完成後,slave的狀態轉換為REDIS_REPL_SEND_BULK,master開始將rdb文件發送給slave,發送前會先發送rdb文件的長度信息。
- 當rdb文件發送完成後,slave的狀態轉換為REDIS_REPL_ONLINE。
master在為slave啟動rdbSaveBackground後,master上的更新會累積到slave的連接緩衝區,等到slave接受完rdb文件之後,將緩衝區裏累積的更新同步到slave上
主備同步時序
- 管理員向server發送slaveof master-ip master-port,將該server變為master的slave
- slave建立到master的網絡連接
- slave向master發送PING檢測網絡狀態,master回複+PONG
- slave向master發送AUTH進行認證(可選),master恢複+OK
- slave向master發送REPLCONF listening-port,master恢複+OK
- slave向master發送sync/psync,master開始後台轉儲rdb文件
- master轉儲rdb完成後,向slave發送rdb文件,slave接受rdb文件並清空數據庫,load從master接受到的rdb文件
- master將rdb轉儲及傳輸期間累積的更新操作同步到slave
- master與slave數據到達一致,接下來master接受到的所有更新操作都會同步到slave
主備同步狀態維護
master周期性的ping slave(默認10s),當ping不通slave超過60s(默認)後,就會認為slave掛掉了,便會斷開與該slave的連接;同理,slave如果超過一定時間沒有接受到master的PING,會認為master掛掉了,便會斷開與master的連接。
當master、slave連接斷開後,slave需要重新向master請求同步rdb文件;2.8版本裏redis一定程度支持增量同步,master將同步數據同步給slave時,會同時存儲到一個環形緩衝區(默認1M大小),這個緩衝區永遠存儲最新的同步數據;另外master、slave都會記錄當前同步的offset。
當slave與master斷開後,slave會先嚐試進行PSYNC增量同步,如果連接斷開期間,master沒有重啟過,並且slave的offset在master的環形緩衝區內,則可直接進行增量同步,比如:
假設環形緩衝區的長度為1000, master的同步offset為10000,此時緩衝區裏記錄的是9001-10000的同步數據,slave同步到9500時,與master斷開了連接;slave重新建立與master連接後,會帶上offset 9500,請求增量同步,master發現該slave的offset在9001-10000之間,可以進行增量同步,將9501-10000的同步數據發送給slave,以達到主備一致的狀態。
最後更新:2017-04-01 13:37:09