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文件生成、傳輸和重新加載的開銷。