redis 主從同步原理
1.為什麼需要主從同步
在使用redis服務的時候如果時單機服務,一旦單機服務宕機了,那麼可能導致我們整個系統處於不可用狀態,或者當系統的訪問量大了以後單機的redis服務成功了整個系統的瓶頸,這時候就到了主從複製展示伸手的時候了.主從複製可以幫我們完成以下功能.
1.1 資料冗餘:主從複製實現了資料的熱備份,是持久化之外的一種資料冗餘方式。
1.2 故障恢復:當主節點出現問題時,可以由從節點提供服務,實現快速的故障恢復;實際上是一種服務的冗餘。
1.3 負載均衡:在主從複製的基礎上,配合讀寫分離,可以由主節點提供寫服務,由從節點提供讀服務(即寫Redis資料時應用連線主節點,讀Redis資料時應用連線從節點),分擔伺服器負載;尤其是在寫少讀多的場景下,通過多個從節點分擔讀負載,可以大大提高Redis伺服器的併發量。
1.4 高可用基石:主從複製還是哨兵和叢集能夠實施的基礎,因此說主從複製是Redis高可用的基礎。
2.相關配置
1.replicaof
在5.0之前redis可以通過在從伺服器上執行slaveof ip port來執行主伺服器,在5.0之後可以通過replicaof ip port來指定主伺服器.
2.slave-read-only
redis的主從只能是主伺服器的寫命令同步到從伺服器,而不能反過來,所以為了保證資料一致性,從伺服器只能接收讀請求,而不接收寫和修改請求.redis提供了slave-read-only引數進行控制,
3.min-slaves-to-write
當一個主伺服器有多個從伺服器的時候,為了保證資料的可靠性,需要在有超過n個從伺服器的時候才允許主伺服器執行寫操作命令.為此redis提供了min-slaves-to-write引數進行控制,min-slaves-max-lag來確定從伺服器的延遲
4.client-output-buffer-limit
設定生成rdb檔案的時候緩衝區(replication_buffer)的大小
語法:client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds>
class可選值有三個,Normal,Slaves和Pub/Sub;hard limit: 緩衝區大小的硬性限制。soft limit: 緩衝去大小的軟性限制。soft seconds: 緩衝區大小達到了(超過)soft limit值的持續時間。
5.repl-backlog-size
設定增量同步的時候寫命令緩衝區(repl_backlog_buffer)的大小
3.原理分析
3.1 主從同步流程
3.1.1.建立連線
a).當從庫執行了replicaof ip port命令之後從伺服器儲存主伺服器的ip和porti資訊,
b).從伺服器和主伺服器建立socket連線,
c).從伺服器傳送ping命令,並且接收主伺服器的pong命令,如果沒有接收到pong命令則從新建立連線
d).如果主伺服器設定了訪問密碼則進行許可權校驗,如果許可權校驗通過則開始進行資料同步
2.確定同步方式
a).從伺服器傳送psync runid offset命令到主伺服器,第一次同步的時候由於還沒有主伺服器的runid,所以使用?代替
b).主伺服器收到psync命令之後首先判斷runid是否和自己的runid一致,如果不一致或者為?,則進行全量同步,主伺服器返回給從伺服器fullresync響應,如果runid和主伺服器一致則判斷offset是否還在repl-backlong_buffer緩衝區的範圍內,如果不在該緩衝區的範圍內了,則進行全量同步,主伺服器返回給從伺服器fullresync響應,如果在緩衝區範圍內則進行增量同步,主伺服器返回給從伺服器continue響應.如果主伺服器詳情的是fullresync則還會帶上當前伺服器runid和目前主庫的複製進度offset
3.2 全量同步
當主伺服器響應給從伺服器fullresync響應之後,主伺服器開始執行bgsave命令,生成RDB檔案,並且在rdb檔案生成完之後會把整個rdb檔案傳送給從伺服器,從伺服器接收到rdb檔案之後會清空自己的資料庫,然後把rdb檔案讀取到自己的資料庫中.由於主伺服器在生成rdb檔案的時候是不阻塞的,主伺服器還可以繼續向外提供服務,這時候為了保證主從伺服器的資料一致性,主伺服器需要把從開始執行bgsave命令到傳送rdb檔案到從伺服器和從伺服器把rdb檔案恢復到記憶體中這段時候的所有寫命令儲存下來然後發給從伺服器執行,儲存這些寫命令的空間就是replication_buffer.他是專門用來儲存主伺服器在生成rdb檔案的時候的寫命令的.
如果在主伺服器生成rbd到從伺服器根據rdb檔案把資料恢復到記憶體中這段時間產生的寫命令太多導致replication_buffer儲存不了會導致主伺服器主動斷開主從連線,主伺服器會釋放掉相關資料,這時候會重新開始主從複製.如果replication_buffer太小會導致這個過程無限迴圈.所以推薦把replication_buffer設定的大一些,防止出現這種情況
3.3 增量同步
當全量同步完成之後,由於從伺服器已經拿到了主伺服器的runid和offset,這時候主從伺服器之間開始進行增量複製.增量複製的時候主伺服器並不是同步的把所有的寫命令直接傳送給從伺服器而是把寫命令快取到一個交repl_backlog_buffer的空間中,然後集中把寫命令和offset傳送給從伺服器,從伺服器在接收到命令執行完成之後會把執行了的命令的offset傳送給主伺服器,這樣主伺服器可以根據從伺服器返回的offset判斷哪些命令還沒有執行,然後決定下次傳送給從伺服器的命令和offset.
repl_backlog_buffer是一個環形空間,時間久了新寫入的資料會把之前寫入的資料覆蓋掉,如果從伺服器返回的offset不在這個環形空間中,則主伺服器會判定資料不一致,然後觸發一次全量同步.
repl_backlog_buffer還用在了當主從伺服器之間斷開連線重新連線之後,從伺服器傳送psync命令,並且帶了runid和offset引數,如果主伺服器返現offset還在環形空間中,則不會進行全量服務,而是返回continue繼續增量複製.
3.4無盤複製
通常來講,一個完全重新同步需要在磁碟上建立一個RDB檔案,然後載入這個檔案以便為從伺服器傳送資料。如果使用比較低速的磁碟,這種操作會給主伺服器帶來較大的壓力。特別是當系統正在進行 AOF 的 fsync 操作時如果發生快照,fsync 將會被推遲執行,這就會嚴重影響主節點的服務效率。所以從 Redis 2.8.18 版開始支援無盤複製。所謂無盤複製是指主伺服器直接通過套接字將快照內容傳送到從節點,生成快照是一個遍歷的過程,主節點會一邊遍歷記憶體,一遍將序列化的內容傳送到從節點,從節點還是跟之前一樣,先將接收到的內容儲存到磁碟檔案中,再進行一次性載入。