Redis具有高可靠性,體現在兩方面:
- 一是資料儘量少丟失,通過前面介紹的持久化方式AOF和RDB,在當機時可以恢復資料。
- 二是服務儘量少中斷,通過副本冗餘來實現。
今天我們學習的就是通過主從複製實現副本冗餘,從而實現Redis的高可靠性。
什麼是主從複製
Redis提供主從庫模式,保證資料副本的一致,主從庫之間採用的是讀寫分離的方式。
為什麼要讀寫分離?
如果允許所有節點能夠處理讀寫請求,就需要解決加鎖、例項間協商、資料同步等操作,會帶來鉅額的開銷。
因此採用主從庫模式時,要配置主庫只寫,從庫只讀。
主從庫如何進行第一次同步?
當設定了主從庫模式,此時從庫是空的,如何進行主從庫的第一次同步呢?
Redis採用全量複製來進行第一次同步,具體有三個步驟,如下圖所示:
第一步,主從庫建立連線,協商同步。
- 從庫傳送psync命令,表示進行資料同步。其中runID表示主庫ID,第一次不知道主庫的runID,就設定為"?"
- 主庫收到psync命令後,用FULLRESYNC響應,返回runID(主庫ID)和offset(主庫目前的複製進度)。
- 從庫收到響應後,記錄這兩個引數
第二步:主庫同步資料給從庫。
從庫收到資料後,在本地完成資料載入。這過程依賴於RDB快照。
- 主庫執行bgsave命令,生成RDB檔案,再把檔案發強從庫。
- 從庫收到RDB檔案後,先清空當前資料庫,然後載入RDB檔案。
第三步,主庫傳送新寫命令給從庫
主庫在資料同步過程中,會記錄所有寫操作,避免丟失同步過程接收的新的寫命令。
- 主庫使用replication buffer來新的寫命令。
- 當從庫載入RDB檔案完成後,主庫再把replication buffer的內容傳送給從庫,從庫再執行這些操作實現同步。
關於replication buffer的更多內容,下面再介紹。
如果有多個從庫,每個從庫都要跟主庫進行全量同步,這樣主庫的壓力會很大。
主從級聯模式
Redis提供“主-從-從”模式將主庫生成RDB和傳輸RDB的壓力,以級聯的方式分散到從庫上。
簡單來說,構建父子從庫結構,子從庫的資料同步從父從庫獲取。如下圖所示:
在從庫上執行命令:replicaof 所選從庫的IP 6379
,就可以設定從庫的父從庫了。
至此,主從庫完成了第一次同步,那後續如何保持同步呢?
如何保持同步?
當主從庫完成同步後,會維護一個網路連線,主庫會通過這個連線將後續的命令同步給從庫。
但是這裡有潛在的風險點:如果網路斷連或者出現阻塞了,那怎麼辦呢?
主從庫間網路斷了怎麼辦?
在Redis 2.8之前,網路斷了後要重新進行全量複製。但在Redis 2.8之後,Redis提供了增量複製的方式。
當建立了主從結構後,主庫會把寫命令寫入repl_backlog_buffer緩衝區裡,當網路斷開並重新連線後,從庫會傳送同步命令,然後主庫再把未同步的命令傳送給從庫,從庫執行這些命令就恢復資料一致了。具體流程如下圖所示:
repl_backlog_buffer是一個環形緩衝區,如下圖所示:
由於其環形結構,當因為網路問題影響從庫讀取命令的速度,會出現寫滿後繼續寫入命令時,會覆蓋掉從庫還沒讀的內容,從而造成資料不一致,需要重新全量複製。
因此要根據情況來設定repl_backlog_buffer的大小,通過配置repl_backlog_size來調整緩衝區大小。配置公式為:緩衝空間大小 = 主庫寫入命令速度 * 操作大小 - 主從庫間網路傳輸命令速度 * 操作大小。而repl_backlog_size= 緩衝空間 * 2。
例如主庫寫操作2000/秒,每個操作大小2KB,網路傳輸1000個操作/秒,那緩衝空間大小=2000*2 - 1000*2=2MB,那repl_backlog_size就設定為4MB。
擴充
為什麼主庫間的資料複製同步不使用AOF?
有三方面原因:
- RDB檔案是經過二進位制壓縮的,檔案很小,這樣主從庫間傳輸就很快。
- 從庫載入RDB檔案速度很快,而AOF日誌還要逐行命令執行,速度很慢。
- 假設使用AOF,那就必須開啟AOF,Redis預設是不開啟AOF的,可能會影響Redis效能。
關於replication buffer
每個與Redis通訊的客戶端(從庫也算client),都會分配一個buffer,所有資料互動都是通過這個buffer進行的。
Redis先把資料寫到這個buffer中,然後再把buffer中的資料發到client的socket中,通過網路傳送出去,完成資料互動。
而主從同步的這個buffer,是用於保證主從資料一致的,所以才叫它replication buffer。
可以通過配置項client-output-buffer-limit
來配置這個buffer的大小。當儲存到buffer裡的內容超過限制,主庫會強制斷開這個client的連線。這樣會有潛在風險。
如果從庫處理主庫傳輸的命令非常慢,就會把這個buffer撐滿,然後主庫會斷開連線。中斷後,從庫再次發起複製請求,可能會導致惡性迴圈,引發複製風暴。
小結
- 主從庫模式是採用RDB快照的全量複製 + 基於長連線的網路通訊實現主從複製的。
- 通過“主-從-從”模式,將主庫生成RDB和傳輸RDB的壓力,以級聯的方式分散到從庫上。
- 當網路中斷,通過主庫的repl_backlog_buffer,實現增量複製,無須重新全量複製。
- repl_backlog_buffer是環形緩衝區,要根據網路狀況,合理配置其大小。
- 一個Redis例項的資料庫不要太大,在幾GB比較合適,這樣可以減少RDB檔案生成、傳輸和重新載入的開銷。