Redis學習 主從複製(master-replica)架構介紹及實現

人生長恨水發表於2019-04-12

以下筆記以及實驗皆出自於 中華石杉大佬的視訊教學,我跟著做了實驗,並且把課上的筆記整理了一下。

redis的主從架構

在一個專案中使用redis必然是因為我們想要做成高併發,redis是整個大型的快取架構中,支撐高併發的非常重要的一個環節, 但是光redis是不夠的。

redis不能支撐高併發的瓶頸就是 單機 單機的redis不可能說QPS超過10萬+,除非你的機器效能特別好,維護做的好, 而且你的整體的操作不能太複雜。

所以讀寫分離一般來說是用來支撐高併發,寫的請求比較少,大量的請求都是讀,那麼redis的主從架構就是比較好的選擇, 主從架構 -> 讀寫分離 -> 水平擴容支撐讀高併發,主節點用來寫,從節點用來讀。

PS:在我使用的5.0.4版本中slave這個術語已經被replica代替了,嗯~ 這個單詞的意思確實有點不好聽哈。反正官方已經改掉了,我也就全換掉了。

master-replica

redis replication(主從複製)的核心機制

  • redis採用非同步方式複製master節點資料到replica節點,不過redis 2.8開始,replica node會週期性地確認自己每次複製的資料量
  • 一個master node是可以配置多個replica node的
  • replica node也可以連線其他的replica node
  • replica node做複製的時候,是不會block master node的正常工作的
  • replica node在做複製的時候,也不會block對自己的查詢操作,它會用舊的資料集來提供服務; 但是複製完成的時候,需要刪除舊資料集,載入新資料集,這個時候就會暫停對外服務了
  • replica node主要用來進行橫向擴容,做讀寫分離,擴容的replica node可以提高讀的吞吐量

redis 主從複製的核心原理

當啟動一個 replica node 的時候,它會傳送一個 PSYNC 命令給 master node。

如果 replica node 使用 PSYNC 初次連線到 master node,那麼會觸發一次 full resynchronization 全量複製。此時 master 會啟動一個後臺執行緒, 開始生成一份 RDB 快照檔案,同時還會將從客戶端 client 新收到的所有寫命令快取在記憶體中。RDB 檔案生成完畢後, master 會將這個 RDB 傳送給 replica, replica 會先寫入本地磁碟,然後再從本地磁碟載入到記憶體中,接著 master 會將記憶體中快取的寫命令傳送到 replica,replica 也會同步這些資料。replica node 如果跟 master node 有網路故障,斷開了連線,會自動重連,連線之後 master node 僅會複製給 replica 部分缺少的資料。

流程圖

什麼是PSYNC命令呢

簡單來說PSYNC完成的使命就是判斷從伺服器是否需要全量複製還是增量複製,畢竟每次因為一點點網路波動重新連線主節點,都要全量複製,非常的低效

PSYNC格式:

PSYNC runid offset

runid

每個Redis伺服器都會有一個表明自己身份的ID。在PSYNC中傳送的這個ID是指之前連線的Master的ID,如果沒儲存這個ID, PSYNC的命令會使用”PSYNC ? -1” 這種形式傳送給Master,表示需要全量複製。

offset(複製偏移量)

在主從複製的Master和replica雙方都會各自維持一個offset。Master成功傳送N個位元組的命令後會將Master的offset加上N, replica在接收到N個位元組命令後同樣會將replica的offset增加N。Master和replica如果狀態是一致的那麼它的的offset也應該是一致的。

全量複製流程

  • 主節點master收到全量複製的命令後 執行 bgsave ,在本地生成一份 rdb 快照檔案;並使用一個緩衝區(稱為複製緩衝區)記錄從現在開始執行的所有寫命令 redis配置檔案中有個引數:client-output-buffer-limit replica 256MB 64MB 60

如果在複製期間,記憶體緩衝區超過60秒一直消耗超過 64MB,或者一次性超過 256MB,那麼停止複製,複製失敗。後兩個引數是配合使用的,假如:消耗超過64MB 一直持續了59秒,但是60秒的時候不超過64MB了,那麼就保持連線繼續複製。

  • master node 將 rdb 快照檔案傳送給 replica node,如果 rdb 複製時間超過 60秒(redis配置檔案引數:repl-timeout),那麼 replica node 就會認為複製失敗, 可以適當調大這個引數(對於千兆網路卡的機器,一般每秒傳輸 100MB,6G 檔案,很可能超過 60s)

  • master node 在生成 rdb 時,會將所有新的寫命令快取在記憶體中,在 replica node 儲存了 rdb 之後,再將新的寫命令複製給 replica node; 從節點首先清除自己的舊資料,然後載入接收的RDB檔案

  • 主節點將前述複製緩衝區中的所有寫命令傳送給從節點,從節點執行這些寫命令,如果從節點開啟了AOF,則會觸發bgrewriteaof的執行,從而保證AOF檔案更新至主節點的最新狀態

部分複製流程(增量複製)

  • 如果全量複製過程中,master-replica 網路連線斷掉,那麼 replica 重新連線 master 時,會觸發增量複製。

  • master 直接從自己的 backlog 中獲取部分丟失的資料,傳送給 replica node,預設 backlog 就是 1MB。

  • master 就是根據 replica 傳送的 psync 中的 offset 來從 backlog 中獲取資料的。

例如,如果主節點的offset是1000,而從節點的offset是500,那麼部分複製就需要將offset為501-1000的資料傳遞給從節點

完整的複製流程

replica node 啟動時,會在自己本地儲存 master node 的資訊,包括 master node 的host和ip,但是複製流程沒開始。

replica node 內部有個定時任務,每秒檢查是否有新的 master node 要連線和複製,如果發現,就跟 master node 建立 socket 網路連線; 然後 replica node 傳送 ping 命令給 master node。如果 master 設定了 requirepass(就是redis的登入密碼), 那麼 replica node 必須傳送 masterauth 的口令過去進行認證;master node 第一次執行全量複製,將所有資料發給 replica node; 而在後續,master node 持續將寫命令,非同步複製給 replica node。

redis-master-slave-replication-detail

  • 第一步:從節點伺服器內部維護了兩個欄位,即masterhost和masterport欄位,用於儲存主節點的ip和port資訊。

  • 第二步:建立socket連線,即從節點每秒1次呼叫複製定時函式replicationCron(),如果發現了有主節點可以連線,便會根據主節點的ip和port,建立socket連線

  • 第三步:身份驗證,如果從節點中設定了masterauth選項,則從節點需要向主節點進行身份驗證;沒有設定該選項,則不需要驗證; 從節點進行身份驗證是通過向主節點傳送auth命令進行的,auth命令的引數即為配置檔案中的masterauth的值;如果主節點設定密碼的狀態, 與從節點masterauth的狀態一致(一致是指都存在,且密碼相同,或者都不存在),則身份驗證通過,複製過程繼續;如果不一致,則從節點斷開socket連線,並重連。

  • 第四步:資料同步,就是全量複製或者增量複製,而且在複製階段繼續有寫命令會存在主節點記憶體中,後續會非同步傳送給replica node

replica node如果跟master node有網路故障,斷開了連線,會自動重連。master如果發現有多個replica node都來重新連線, 僅僅會啟動一個rdb save操作,用一份資料服務所有replica node。

主從複製的斷點續傳

從redis 2.8開始,就支援主從複製的斷點續傳,如果主從複製過程中,網路連線斷掉了,那麼可以接著上次複製的地方,繼續複製下去,而不是從頭開始複製一份

master node會在記憶體中常見一個backlog,master和replica都會儲存一個replica offset還有一個master id,offset就是儲存在backlog中的。 如果master和replica網路連線斷掉了,replica會讓master從上次的replica offset開始繼續複製

但是如果沒有找到對應的offset,那麼就會執行一次resynchronization(全量複製)

無磁碟化複製

master 在記憶體中直接建立 RDB,然後傳送給 replica,不會在自己本地落地磁碟了。只需要在配置檔案中開啟 repl-diskless-sync yes 即可。

repl-diskless-sync yes

# 等待 5s 後再開始複製,因為要等更多 replica 重新連線過來
repl-diskless-sync-delay 5
複製程式碼

過期key處理

replica不會過期key,只會等待master過期key。如果master過期了一個key,或者通過LRU淘汰了一個key,那麼會模擬一條del命令傳送給replica。

heartbeat

主從節點互相都會傳送 heartbeat 資訊。

master 預設每隔 10秒 傳送一次 heartbeat,replica node 每隔 1秒 傳送一個 heartbeat。

master持久化對於主從架構的安全保障的意義

如果採用了主從架構,那麼建議必須開啟master node的持久化! 如何實現redis的持久化

而且不建議使用replica node作為master node的資料熱備如果你關掉master的持久化,可能在master當機重啟的時候資料是空的,然後可能一經過複製,replica node資料也丟了

另外,master 的各種備份方案,也需要做。萬一本地的所有檔案丟失了,從備份中挑選一份 rdb 去恢復 master,這樣才能確保啟動的時候,是有資料的 即使採用了後續講解的高可用機制,replica node可以自動接管master node,但是也可能sentinal還沒有檢測到master failure,master node就自動重啟了, 還是可能導致上面的所有replica node資料清空故障。

實現redis的主從複製架構(一主一從)

node hostname IP port
master node eshop-cache01 192.168.0.30 6379
replica node eshop-cache02 192.168.0.31 6379

在除了安裝redis時配置的引數外,從節點還需要額外配置以下內容

配置主節點(eshop-cache01)配置檔案

  • 在配置檔案中修改 bind 127.0.0.1bind 192.168.0.30 自己本身的ip地址

或者配置成 bind 0.0.0.0 如果配置成本身ip地址,則需要在使用redis的客戶端時,使用redis-cli -h 192.168.0.30進入客戶端了

  • 配置認證密碼 requirepass redis-pass , 就是登入redis 的登入密碼

配置從節點(eshop-cache02)配置檔案

  • 在配置檔案中修改 bind 127.0.0.1bind 192.168.0.31 自己本身的ip地址

  • 配置 replicaofreplicaof eshop-cache01 6379 eshop-cache01我是在 master node /etc/hosts 中配置了對映本機的ip

replicaof 填寫主節點的ip 和 埠號

  • 開啟安全認證 masterauth redis-pass 填寫的就是 master node 的登入密碼,需要在主節點配置檔案中配置

  • 強制讀寫分離 replica-read-only yes 這個預設是開啟的

可以自由選擇是否開啟AOF持久化

測試主從複製(讀寫分離)

先後啟動主節點和從節點的redis例項,進入主節點客戶端,set k1 v1 然後在從節點中看是否能讀取到資料,讀取到資料即代表成功。

master-replica

info replication命令可以檢視本身的角色是主節點 還是 從節點

擴充套件閱讀

相關文章