Redis高可用之主從複製原理演進分析
在很久之前寫過一篇 Redis 主從複製原理的簡略分析,基本是一個筆記類文章。
主從複製,從名字可以看出,至少需要 2 臺 Redis 伺服器,一臺叫主 Redis 伺服器,一臺叫從 Redis 伺服器,也可以把他們叫做主節點(主 Redis 伺服器)從節點(從 Redis 伺服器)。然後把主 Redis 伺服器上的資料複製到從 Redis 伺服器上,這就是主從複製。後續也會源源不斷的把資料從主節點複製到從節點。
怎麼設定主 Redis 伺服器,怎麼設定從 Redis 伺服器?
比如有 2 臺 Redis 伺服器,ip 分別為:192.168.1.100 和 192.168.1.101。
設定方法:在 Redis 的組態檔 redis.conf 中設定:replicaof masterip masterport
比如將 192.168.1.100 這臺伺服器設定為主(master)伺服器,那麼就在伺服器 192.168.1.101 的組態檔裡設定如下:
replicaof 192.168.1.100 6379
然後重啟伺服器,這樣主伺服器就是 192.168.1.100,從伺服器就是 192.168.1.101。
還可以用 redis-cli 使用者端連線到 192.168.1.101,然後執行命令 replicaof 192.168.1.100 6379
。
這種方式如果從 Redis 重啟後,主從關係就消失了。
在 redis-server 啟動引數中增加 --replicaof 192.168.1.100 6379
引數
說明:Redis 5.0 後,replicaof 命令已經替換了 slaveof 命令,但是為了相容 slaveof 還是可以用。
一臺主伺服器也可以有多臺從伺服器,從伺服器也可以有從伺服器。
主從複製後就有多份資料,相當於有多個副本,既是備份也是容災。
為什麼要有主從複製功能?
其實問的就是 Redis 主從複製有什麼作用,帶來了啥好處。
資料量大的時候,為了減輕伺服器壓力,會用讀寫分離模式來分攤流量,主伺服器負責寫,從伺服器負責讀。當然主伺服器也可以讀。
主伺服器出現問題時候,從伺服器還可以繼續提供服務。並且也可以把從伺服器提升為主伺服器,這就是 Redis 的哨兵模式。
高可用的資料冗餘方式。
多了一份資料,故障了,就可以快速恢復資料。
主從資料同步就是把主伺服器生成的 RDB 資料檔案複製到從伺服器上,然後解析 RDB 檔案,在從伺服器上生成對應的資料。或同步相關的命令。
在 Redis2.8 之前,都是全量資料複製。也就是說,斷線重連後,也是重新全量複製資料。這種方式把很多原來同步過了的資料又重新同步一次,這種方式的資料同步效率太低。
在 Redis2.8 之後,增加了部分重同步模式,也就是增加增量資料同步,只同步需要同步的資料。這就改進了之前的資料同步模式。
什麼時候進行全量資料同步?第一次資料同步時候就進行全量資料同步。有時主從資料不一致時也需要全量同步。
什麼時候進行增量資料同步?比如斷線重連後,就進行增量資料同步。
Redis2.8 之前主從同步有 2 個部分:全量同步,命令傳播。
全量同步:主從節點建立連線,主節點回復後,從節點向主節點傳送 SYNC 命令,把從節點伺服器狀態更新到當前主節點伺服器狀態。主節點建立全量資料的 RDB 快照檔案,然後傳送給從節點,從節點載入 RDB 檔案恢復對應的資料。主節點再繼續傳送複製過程中積壓在緩衝區內的新增命令到從節點,使從節點的資料到達和主節點資料一致。
命令傳播:主節點和從節點保持連線,主節點將繼續向從節點傳送命令流,保證主節點上的資料集發生了變更同樣在從資料集上也發生變更。
流程圖:
以 redis6.0 版本來介紹。
Redis2.8 之後全量複製與上面(Redis2.8之前)複製步驟差不多,SYNC 命令變成了 PSYNC 命令,之後增加了部分重同步。部分重同步改進了之前的每次需要全量同步問題。
增加了部分重同步,這個要怎麼做才能相容之前的全量同步呢?怎麼知道從庫複製到哪兒了?第一個從庫肯定要記錄下從庫複製到哪兒了,下次斷線重連時就可以告訴主庫該從哪個地方開始複製了。主庫也要記錄自己的一些複製資訊。Redis 用了幾個概念就把這些問題給解決了,Replication ID,offset,replication_backlog。
Replication ID, offset,這一對來標識資料集版本。
Redis2.8之後就是用上面這幾個概念實現部分資料重同步的。從節點傳送主節點的 replid 和從節點的一個 offset,主節點拿到這個replid 和自己的 replid 比較,如果是一樣,並且這個 offset 也在 backlog 中能找到,那就可以可以進行部分重同步。
建立連線後,從節點使用命令 PSYNC <replid> <offset>
向主節點發起同步請求。如果主從節點是第一次複製,那麼命令為 PSYNC ? -1
,replid 為 ?,因為是第一次複製不知道主庫的 replid。offset 為 -1,表示第一次複製。
主節點收到 PSYNC 命令後,會用 FULLRESYNC 命令響應,帶上主節點的 replid 和 offset 返回給從庫,從庫會記錄下這兩個引數。便於以後判斷是否需要部分重同步。
主節點執行 bgsave 命令生成 RDB 檔案,生成完後把檔案傳送給從節點,從節點載入 RDB 檔案。這個過程中,主節點不會阻塞,依然會接收使用者端的命令請求,當然,這些請求不會寫在之前的 RDB 檔案裡,為了保持主從資料一致,這些命令會儲存在 replication buffer 中,記錄 RDB 檔案後的所有寫操作。
協商就是根據先前定義好步驟來傳送相關命令,為同步做準備工作。有點協定的意思。步驟如下:
當主庫把 RDB 檔案傳送給從節點完成後,就會把 replication buffer 中的寫命令操作傳送給從節點,從節點執行這些操作命令,主從節點同步完成。
之後會繼續向從節點傳送主節點的操作命令,從節點執行這些命令,保持主從資料的一致。
上面是一個主體的同步步驟,更加詳細的步驟要分析原始碼了。
傳送步驟與 Redis2.8 之前全量同步沒有多大區別。
部分資料同步,解決的是主從節點在同步命令時候,網路斷了在連上時,Redis2.8 之前會在全量同步資料,顯然開銷太大,不合理。能不能只把斷線後的資料同步一份,而不是全量同步?
網路斷線後,就有部分命令資料沒有同步到從節點上去,那我們能不能儲存這部分命令資料?重連後,將斷開期間的這部分命令重新同步給從節點,這樣就不需要全量同步。
Redis2.8 之後引入了 replication_backlog 複製積壓緩衝區,前面有講到這個概念。命令一方面會傳輸給從節點,另外還會記錄在這個複製積壓緩衝區裡。Redis 使用一個環形緩衝區的結構儲存最近的一些命令。在緩衝區中,對位元組進行編號,這個編號在 Redis 中叫複製偏移量。
是否部分同步條件?
如果滿足上面的 2 個條件,就進行部分資料重同步。
先看兩個問題
1.從節點重啟後丟失了原主節點的節點編號和複製偏移量,這導致重啟後需要全量複製,這個很好辦,把這些資訊儲存下來
2.主從切換後,主節點資訊變化了,導致從節點需要全量資料同步,這個也好辦,只要能確認新主節點資料是從原主節點複製過來就可以了
Redis4.0 後,對 PSYNC 進行了改進,提出了同源增量複製解決方案,來解決上面提到的兩個全量複製問題。
第1個:從節點重啟後,需要跟主節點全量資料同步,為什麼?本質原因,是從節點丟失了主節點的編號資訊和偏移量資訊。Redis4.0後,就把主節點的編號資訊寫入到 RDB 中持久化儲存。
第2個:主從切換後,從節點需要和主節點全量同步,為什麼?原因就是新的主節點不認識原來主節點的編號資訊。切換後怎麼才能識別到呢?Redis4.0 後,主從切換後,新的主節點會將先前的主節點資訊記錄下來,這樣新主節點就知道自己原先資料是從哪個舊主節點同步來的,大家都是從同一個地方出來的,應該接受部分資料同步策略。
什麼叫無盤?
原先的同步複製是通過 fork 一個子程序生成 RDB 快照檔案,RDB 儲存在磁碟上,然後傳輸 RDB 檔案,從節點伺服器在恢復 RDB 檔案資料。
無盤,就是說不生成 RDB 檔案,不通過 RDB 來傳輸資料。而是直接通過網路來傳輸資料。
怎麼做到無盤呢?
Redis6.0 後,它也是先 fork 一個子程序,這個子程序 dump 資料,它通過管道回寫給主節點,主節點在將資料傳送給從節點,這樣的過程就是無盤傳輸。
(from: https://mp.weixin.qq.com/s/UlHksrqFq0yfKh1uMFvYNg 作者:shooterIT)
如圖所示,對於 Redis 主庫,當用戶的寫請求到達時,主庫會將變更命令分別寫入所有從庫的緩衝區(OutputBuffer),以及複製積壓緩衝區(ReplicationBacklog)。全量同步也會執行該邏輯。所以在全量同步階段經常會觸發 client-output-buffer-limit,主庫斷開與從庫的連線,導致主從同步失敗,甚至出現迴圈持續失敗的情況。
所有從庫的連線在主庫上是獨立的,也就是說每個從庫 OutputBuffer 佔用的記憶體空間也是獨立的,那麼主從複製消耗的記憶體就是所有從庫緩衝區記憶體大小之和。如果我們設定從庫的 client-output-buffer-limit 為 1GB,如果有三個從庫,則在主庫上可能會消耗 3GB 的記憶體用於主從複製。另外,真實環境中從庫的數量不是確定的,這也導致 Redis 範例的記憶體消耗不可控。
from: https://mp.weixin.qq.com/s/UlHksrqFq0yfKh1uMFvYNg 作者:shooterIT
具體內容請看這裡:https://mp.weixin.qq.com/s/UlHksrqFq0yfKh1uMFvYNg
具體方案請看這裡:https://mp.weixin.qq.com/s/UlHksrqFq0yfKh1uMFvYNg 作者:shooterIT