Redis高可用之主從復制原理演進分析( 二 )


增加了部分重同步,這個要怎么做才能兼容之前的全量同步呢?怎么知道從庫復制到哪兒了?第一個從庫肯定要記錄下從庫復制到哪兒了,下次斷線重連時就可以告訴主庫該從哪個地方開始復制了 。主庫也要記錄自己的一些復制信息 。Redis 用了幾個概念就把這些問題給解決了 , Replication ID,offset,replication_backlog 。

  • Replication ID:復制 ID 。這是一個較大的隨機字符串,標記一個給定的數據集 。每個主節點都會用這個 Repli ID 來標識內部數據集,從節點 ID 。當從節點加入時 , 這個 repli id 就初始化了 。
  • offset:復制偏移量 。每個主節點都有這個 offset 偏移量 , 主節點將自己產生的數據發送給從節點時,發送多少字節數據,自身 offset 就會增加多少 。從節點也有自己 offset,從節點寫入數據時,offset 也會增加 。斷線重連時,就可以知道從哪里開始同步了 。offset 需配合下面的復制積壓緩沖區工作 。
  • replication_backlog:復制積壓緩沖區 。它是在主節點上的一個環形緩沖區,用來存儲主節點向從節點傳遞的命令 。它是大小固定 , 存儲的命令有限,所有超出了就會刪除 。從節點進行增量同步時,主節點會根據 offset 從 replication_backlog 中拷貝從節點缺失的數據到從節點 。
Replication ID, offset,這一對來標識數據集版本 。
Redis2.8之后就是用上面這幾個概念實現部分數據重同步的 。從節點發送主節點的 replid 和從節點的一個 offset,主節點拿到這個replid 和自己的 replid 比較,如果是一樣,并且這個 offset 也在 backlog 中能找到,那就可以可以進行部分重同步 。
全量復制步驟
  1. 主從節點先建立連接
建立連接后,從節點使用命令 PSYNC <replid> <offset> 向主節點發起同步請求 。如果主從節點是第一次復制,那么命令為 PSYNC ? -1 , replid 為 ?,因為是第一次復制不知道主庫的 replid 。offset 為 -1,表示第一次復制 。
主節點收到 PSYNC 命令后,會用 FULLRESYNC 命令響應,帶上主節點的 replid 和 offset 返回給從庫,從庫會記錄下這兩個參數 。便于以后判斷是否需要部分重同步 。
  1. 同步數據
主節點執行 bgsave 命令生成 RDB 文件,生成完后把文件發送給從節點 , 從節點加載 RDB 文件 。這個過程中,主節點不會阻塞,依然會接收客戶端的命令請求,當然,這些請求不會寫在之前的 RDB 文件里,為了保持主從數據一致,這些命令會存儲在 replication buffer 中 , 記錄 RDB 文件后的所有寫操作 。
  1. 同步緩沖的命令數據
協商就是根據先前定義好步驟來發送相關命令,為同步做準備工作 。有點協議的意思 。步驟如下:
當主庫把 RDB 文件傳送給從節點完成后,就會把 replication buffer 中的寫命令操作發送給從節點,從節點執行這些操作命令,主從節點同步完成 。
  1. 命令傳播
之后會繼續向從節點發送主節點的操作命令,從節點執行這些命令,保持主從數據的一致 。
上面是一個主體的同步步驟,更加詳細的步驟要分析源碼了 。
發送步驟與 Redis2.8 之前全量同步沒有多大區別 。
部分數據同步部分數據同步,解決的是主從節點在同步命令時候,網絡斷了在連上時,Redis2.8 之前會在全量同步數據 , 顯然開銷太大,不合理 。能不能只把斷線后的數據同步一份,而不是全量同步?
網絡斷線后,就有部分命令數據沒有同步到從節點上去,那我們能不能保存這部分命令數據?重連后 , 將斷開期間的這部分命令重新同步給從節點,這樣就不需要全量同步 。
Redis2.8 之后引入了 replication_backlog 復制積壓緩沖區,前面有講到這個概念 。命令一方面會傳輸給從節點,另外還會記錄在這個復制積壓緩沖區里 。Redis 使用一個環形緩沖區的結構保存最近的一些命令 。在緩沖區中,對字節進行編號 , 這個編號在 Redis 中叫復制偏移量 。
Redis高可用之主從復制原理演進分析

文章插圖
是否部分同步條件?
  • 從節點 replid 和 主節點的 replid 相同
  • 復制偏移量 offset 在復制積壓緩沖區的 backlog_off 和 offset 范圍之間 。
如果滿足上面的 2 個條件,就進行部分數據重同步 。

推薦閱讀