階段是主從庫間建立連接、協(xié)商同步的過程,主要是為全量復(fù)制做準備。在這一步,從庫和主庫建立起連接,并告訴主庫即將進行同步,主庫確認回復(fù)后,主從庫間就可以開始同步了。
具體來說,從庫給主庫發(fā)送 psync 命令,表示要進行數(shù)據(jù)同步,主庫根據(jù)這個命令的參數(shù)來啟動復(fù)制。psync 命令包含了主庫的 runID 和復(fù)制進度 offset 兩個參數(shù)。runID,是每個 Redis 實例啟動時都會自動生成的一個隨機 ID,用來唯一標記這個實例。當從庫和主庫次復(fù)制時,因為不知道主庫的 runID,所以將 runID 設(shè)為“?”。offset,此時設(shè)為 -1,表示次復(fù)制。主庫收到 psync 命令后,會用 FULLRESYNC 響應(yīng)命令帶上兩個參數(shù):主庫 runID 和主庫目前的復(fù)制進度 offset,返回給從庫。從庫收到響應(yīng)后,會記錄下這兩個參數(shù)。這里有個地方需要注意,F(xiàn)ULLRESYNC 響應(yīng)表示次復(fù)制采用的全量復(fù)制,也就是說,主庫會把當前所有的數(shù)據(jù)都復(fù)制給從庫。
第二階段,主庫將所有數(shù)據(jù)同步給從庫。從庫收到數(shù)據(jù)后,在本地完成數(shù)據(jù)加載。這個過程依賴于內(nèi)存快照生成的 RDB 文件。
具體來說,主庫執(zhí)行 bgsave 命令,生成 RDB 文件,接著將文件發(fā)給從庫。從庫接收到 RDB 文件后,會先清空當前數(shù)據(jù)庫,然后加載 RDB 文件。這是因為從庫在通過 replicaof 命令開始和主庫同步前,可能保存了其他數(shù)據(jù)。為了避免之前數(shù)據(jù)的影響,從庫需要先把當前數(shù)據(jù)庫清空。在主庫將數(shù)據(jù)同步給從庫的過程中,主庫不會被阻塞,仍然可以正常接收請求。否則,Redis 的服務(wù)就被中斷了。但是,這些請求中的寫操作并沒有記錄到剛剛生成的 RDB 文件中。為了保證主從庫的數(shù)據(jù)一致性,主庫會在內(nèi)存中用專門的 replication buffer,記錄 RDB 文件生成后收到的所有寫操作。
第三個階段,主庫會把第二階段執(zhí)行過程中新收到的寫命令,再發(fā)送給從庫。具體的操作是,當主庫完成 RDB 文件發(fā)送后,就會把此時 replication buffer 中的修改操作發(fā)給從庫,從庫再重新執(zhí)行這些操作。這樣一來,主從庫就實現(xiàn)同步了。