Redis系列(三):深入解讀Redis主從同步機制
首發(fā)博客地址
https://blog.zysicyj.top/
Redis高可靠靠什么保證?
為什么要提這個呢,因為Redis主從庫目的呢其實就是為了實現(xiàn)高可靠。上篇文章中我們說過Redis的AOF、RDB日志其實就是為了減少數(shù)據(jù)丟失,這是高可靠的一部分。
這篇文章呢,我們聊聊Redis實現(xiàn)高可靠的另一方面:盡量減少服務中斷。這里Redis是怎么做的呢?Redis的做法是增加副本冗余,將一份數(shù)據(jù)同時保存在多個實例上。這樣某個實例掛掉并不影響其它實例提供對外服務,保證我們的業(yè)務正常運行。
Redis有哪些手段提高高可用呢?
數(shù)據(jù)持久化:Redis 支持多種數(shù)據(jù)持久化方式,包括快照(snapshotting)和日志(append-only file)??煺諘ㄆ趯却嬷械臄?shù)據(jù)保存到磁盤文件,而日志會記錄每次寫操作,以便在重啟時進行恢復。這些持久化方式可以確保即使服務器意外關閉,數(shù)據(jù)也不會丟失。
主從復制:Redis 支持主從復制機制,其中一個 Redis 實例作為主節(jié)點,負責寫操作,而其他實例作為從節(jié)點,負責復制主節(jié)點的數(shù)據(jù)。這種方式可以實現(xiàn)數(shù)據(jù)的備份和負載均衡,從而提高可靠性和性能。
Sentinel 哨兵:Redis Sentinel 是一個監(jiān)控和自動故障恢復系統(tǒng),可以監(jiān)控 Redis 實例的健康狀態(tài)并在主節(jié)點故障時自動進行故障切換。它可以確保系統(tǒng)在主節(jié)點發(fā)生故障時能夠自動切換到備用的從節(jié)點,保證服務的連續(xù)性。
Cluster 集群:Redis Cluster 是一種分布式系統(tǒng),將數(shù)據(jù)分布在多個節(jié)點上,以提高可用性和擴展性。每個節(jié)點都持有部分數(shù)據(jù),并且可以容忍部分節(jié)點的故障。當節(jié)點發(fā)生故障時,集群可以自動重新分配數(shù)據(jù),確保服務的可靠性和高可用性。
如何保證副本數(shù)據(jù)一致?
首先我們要知道,Redis提供了主從庫模式,以保證副本一致,主從庫之間采用的是讀寫分離的方式。

Redis中的讀寫分離基本原理和步驟
Redis 讀寫分離是一種架構設計,將讀操作和寫操作分別路由到不同的 Redis 節(jié)點上,以提高性能和擴展性。在 Redis 讀寫分離中,通常會有一個主節(jié)點負責寫操作,多個從節(jié)點負責讀操作。
主節(jié)點(寫節(jié)點):
主節(jié)點負責處理所有的寫操作,包括寫入、更新和刪除等。
寫操作在主節(jié)點上執(zhí)行,然后主節(jié)點將寫操作的結果同步到所有從節(jié)點。
從節(jié)點(讀節(jié)點):
從節(jié)點負責處理讀操作,例如獲取數(shù)據(jù)、查詢等。
從節(jié)點從主節(jié)點復制數(shù)據(jù),并在本地保存一份與主節(jié)點相同的數(shù)據(jù)副本。
讀寫分離的實現(xiàn):
客戶端根據(jù)需要的操作類型將請求分發(fā)到主節(jié)點或從節(jié)點。
讀操作可以通過負載均衡策略,將請求分發(fā)到不同的從節(jié)點,實現(xiàn)負載分擔。
寫操作仍然發(fā)送給主節(jié)點,確保數(shù)據(jù)的一致性和完整性。
需要注意的是,Redis 讀寫分離并不是完全的數(shù)據(jù)實時同步,因為從節(jié)點的數(shù)據(jù)可能會有一定的延遲。另外,讀寫分離適用于大多數(shù)場景下的負載均衡和性能優(yōu)化,但在一些特定情況下,例如有序集合等復雜數(shù)據(jù)結構的查詢,仍然需要訪問主節(jié)點。
實現(xiàn) Redis 讀寫分離需要正確配置主從節(jié)點的關系,以及在客戶端中使用合適的策略進行讀寫操作的路由。同時,需要注意主節(jié)點和從節(jié)點之間的數(shù)據(jù)同步和故障處理,以確保系統(tǒng)的穩(wěn)定性和可靠性。
Redis主從庫第一次同步是如何實現(xiàn)的?
建立連接: 從服務器會向主服務器發(fā)送
PSYNC
命令,表示要進行同步。主服務器收到PSYNC
命令后,會創(chuàng)建一個專門用于復制的后臺線程(replication thread),并等待從服務器的連接。全量復制(第一次同步): 當從服務器連接到主服務器后,主服務器會將自己的數(shù)據(jù)發(fā)送給從服務器。這個過程叫做全量復制,主服務器會遍歷自己的數(shù)據(jù)集,將所有數(shù)據(jù)發(fā)送給從服務器。
主服務器會在一個 RDB 文件中保存當前數(shù)據(jù)集的快照,然后將這個 RDB 文件發(fā)送給從服務器。從服務器接收到 RDB 文件后,會加載這個文件,將自己的數(shù)據(jù)集替換成主服務器的數(shù)據(jù)集。
在 RDB 文件傳輸?shù)倪^程中,主服務器會將在傳輸期間的寫操作記錄下來,稱為命令傳播(command propagation)。這樣一來,主服務器就能夠在發(fā)送完 RDB 文件后,將期間的寫操作重新發(fā)送給從服務器,以保證從服務器的數(shù)據(jù)集與主服務器保持一致。
增量復制: 在完成全量復制后,主從服務器之間會保持一個 TCP 連接,主服務器會將自己的寫操作發(fā)送給從服務器,從服務器執(zhí)行這些寫操作,從而保持數(shù)據(jù)一致性。增量復制的數(shù)據(jù)同步是異步的,但通過記錄寫操作,主從服務器之間的數(shù)據(jù)最終會達到一致狀態(tài)。
需要注意的是,在第一次全量復制的過程中,可能會有一些網(wǎng)絡故障、主從服務器負載等情況影響同步。為了提高穩(wěn)定性和安全性,Redis 提供了一些配置選項和機制,如持久化、復制偏移量、主服務器驗證等,來確保主從復制的正常進行。

PSYNC命令
當 Redis 主從復制中的從服務器(Slave)需要與主服務器(Master)進行數(shù)據(jù)同步時,可以使用 PSYNC(Partial SYNC)命令。PSYNC 命令在 Redis 2.8 版本引入,用于提高數(shù)據(jù)同步的效率和可靠性。
PSYNC 命令包括兩種模式:完全同步(Full Sync)和部分同步(Partial Sync)。
完全同步(Full Sync):完全同步在以下情況下發(fā)生:
完全同步的過程如下:
從服務器向主服務器發(fā)送一條 PSYNC 命令,并附帶上自己的復制積壓緩沖區(qū)的偏移量(offset)和 replid(復制 ID)。
主服務器使用
bgsave
命令,生成RDB文件,接著將文件發(fā)給從庫。從庫接收到RDB文件后,會先清空當前數(shù)據(jù)庫,然后加載RDB文件。
從服務器初次連接主服務器時。
從服務器需要進行初次同步,或者復制偏移量與主服務器的偏移量差距較大時。
主服務器沒有保存 RDB 快照文件,所以無法進行部分同步。
部分同步(Partial Sync):部分同步在以下情況下發(fā)生:
部分同步的過程如下:
主庫將后續(xù)所有寫操作記錄到內存中的replication buffer中
從服務器向主服務器發(fā)送一條 PSYNC 命令,并附帶上自己的復制積壓緩沖區(qū)的偏移量和 replid。
主庫將所有保存的寫操作發(fā)送給從庫,具體來說,就是當RDB發(fā)送完成后,就會把此時replication buffer中的修改發(fā)給從庫,從庫再重新執(zhí)行這些操作。這樣一來,主從庫就實現(xiàn)同步了
從服務器已經(jīng)復制了一部分數(shù)據(jù),并且復制偏移量與主服務器的偏移量差距較小時。
PSYNC 命令的目標是在保證數(shù)據(jù)一致性的前提下,盡可能地減少數(shù)據(jù)同步所需的數(shù)據(jù)傳輸量,從而提高復制效率。完全同步和部分同步的選擇取決于從服務器與主服務器之間的復制狀態(tài)和數(shù)據(jù)差距。
主庫的煩惱
這里我們能分析得到主庫做全量同步時的兩個耗時操作:
生成RDB文件
傳輸RDB文件
這里設想一個場景,如果是一主多從的架構,那么主節(jié)點就要生成多份RDB并傳輸給從節(jié)點,很顯然,這種操作是非常耗時的。這里主要占用兩塊資源
通過fork子進程生成RDB快照會阻塞主線程處理請求
傳輸RDB文件會占用網(wǎng)絡帶寬
那么有什么方法可以解決這些問題呢? 這里呀,我們就引入了“主-從-從”架構,很容易理解,就是主庫只需要同步一份給某從庫A,其他從庫從從庫A同步數(shù)據(jù)。
如何理解 主-從-從 架構?
主從(Master-Slave)架構是一種常見的數(shù)據(jù)庫復制和數(shù)據(jù)備份方案。在這種架構中,存在一個主數(shù)據(jù)庫(主服務器)和一個或多個從數(shù)據(jù)庫(從服務器),主數(shù)據(jù)庫負責處理寫操作和讀操作,從數(shù)據(jù)庫負責復制主數(shù)據(jù)庫的數(shù)據(jù),以提供讀取操作和備份。
主從架構的工作方式如下:
主數(shù)據(jù)庫(主服務器):
主數(shù)據(jù)庫是系統(tǒng)的主要數(shù)據(jù)庫,負責處理所有的寫操作(數(shù)據(jù)的插入、更新、刪除)和部分讀操作。
當主數(shù)據(jù)庫接收到寫操作時,會將這些寫操作記錄到自己的日志文件(例如 MySQL 的二進制日志)中,并發(fā)送給從數(shù)據(jù)庫。
主數(shù)據(jù)庫也會保存一個復制積壓緩沖區(qū)(replication backlog buffer),其中存儲了一部分的寫操作數(shù)據(jù),用于滿足部分同步和斷線重連的需求。
從數(shù)據(jù)庫(從服務器):
從數(shù)據(jù)庫是主數(shù)據(jù)庫的復制副本,負責從主數(shù)據(jù)庫復制數(shù)據(jù)以供讀取操作和備份。
從數(shù)據(jù)庫會連接到主數(shù)據(jù)庫,并發(fā)送復制請求(如 PSYNC 命令)以獲取主數(shù)據(jù)庫的數(shù)據(jù)更新。
從數(shù)據(jù)庫會持續(xù)地復制主數(shù)據(jù)庫的寫操作,將寫操作應用到自己的數(shù)據(jù)副本中,以保持與主數(shù)據(jù)庫的數(shù)據(jù)一致性。
從數(shù)據(jù)庫可以處理讀取請求,從而減輕主數(shù)據(jù)庫的讀取壓力。
主從架構的優(yōu)勢:
負載均衡: 通過將讀操作分發(fā)給從數(shù)據(jù)庫,可以分擔主數(shù)據(jù)庫的讀取壓力,提高整體系統(tǒng)的吞吐量。
高可用性: 當主數(shù)據(jù)庫出現(xiàn)故障時,可以將其中一個從數(shù)據(jù)庫提升為新的主數(shù)據(jù)庫,從而實現(xiàn)快速故障切換。
數(shù)據(jù)備份: 從數(shù)據(jù)庫可以作為主數(shù)據(jù)庫的數(shù)據(jù)備份,用于恢復數(shù)據(jù)和災難恢復。
數(shù)據(jù)分析: 從數(shù)據(jù)庫可以用于讀取操作,以進行數(shù)據(jù)分析、報表生成等工作,而不影響主數(shù)據(jù)庫的性能。
需要注意的是,主從架構并不是完全實時的,因為從數(shù)據(jù)庫需要時間來同步主數(shù)據(jù)庫的數(shù)據(jù)更新。因此,在考慮使用主從架構時,需要權衡數(shù)據(jù)一致性和性能之間的需求。

如何配置主從從架構呢
安裝和配置主服務器(Master):
安裝Redis主服務器并確保主服務器正常運行。
在主服務器的配置文件(redis.conf)中開啟持久化(通常使用RDB快照或AOF日志)和監(jiān)聽端口,確保配置項如下:
port?6379
save?900?1
appendonly?yes??#?如果使用AOF日志如果需要對外提供訪問,確保防火墻或網(wǎng)絡設置允許訪問主服務器的6379端口。
安裝和配置第一個從服務器(Slave1):
在從服務器1上安裝Redis數(shù)據(jù)庫。
在從服務器1的配置文件中配置主從關系。在配置文件中添加類似如下的內容,其中
masterauth
是主服務器的密碼,master
是主服務器的IP和端口:slaveof?master_ip?master_port
masterauth?your_master_password重啟從服務器1使配置生效。
安裝和配置第二個從服務器(Slave2):
在從服務器2上安裝Redis數(shù)據(jù)庫。
在從服務器2的配置文件中配置主從關系,與從服務器1相似。確保配置項不沖突。
重啟從服務器2使配置生效。
重啟主服務器:
在主服務器上查看主服務器的信息,如IP和端口。通常使用以下命令:
INFO?server
測試主從從架構:
在主服務器上進行寫操作,如插入、更新或刪除數(shù)據(jù)。
查看從服務器1和從服務器2是否同步了主服務器的數(shù)據(jù)。
需要注意的是,Redis的主從從架構在部署和配置上與主從架構類似,只是需要在從服務器上再次配置主從關系。另外,Redis還可以配置更多高可用性的功能,如哨兵(Sentinel)和集群(Cluster),以實現(xiàn)更強大的架構。具體配置細節(jié)可能會因版本和需求而有所不同,建議參考官方文檔或相關資源進行詳細了解和配置。
主從庫間網(wǎng)絡斷了怎么辦?
在 Redis 2.8 之前,如果主從庫在命令傳播時出現(xiàn)了網(wǎng)絡閃斷,那么,從庫就會和主庫重新進行一次全量復制,開銷非常大。
2.8之后呢是支持增量同步的,那么Redis是怎么實現(xiàn)增量同步的呢? 當Redis主從庫之間的網(wǎng)絡斷開后,網(wǎng)絡恢復時從庫需要進行增量同步,以獲取在網(wǎng)絡斷開期間主庫中的更新數(shù)據(jù)。Redis實現(xiàn)增量同步的方式是通過Redis復制機制,具體流程如下:
保存主服務器的數(shù)據(jù): 主服務器會將更新的數(shù)據(jù)寫入內存,并在內存中保存一份副本。同時,主服務器會將更新的數(shù)據(jù)寫入AOF(Append-Only File)日志文件,以便在斷電或宕機情況下能夠進行數(shù)據(jù)恢復。
記錄復制偏移量: 在主服務器的復制過程中,主服務器會記錄一個復制偏移量(replication offset),表示從服務器在主服務器中的數(shù)據(jù)位置。這個偏移量會隨著數(shù)據(jù)的更新而遞增。
網(wǎng)絡恢復: 當網(wǎng)絡恢復時,從服務器會嘗試連接主服務器并請求進行復制。
發(fā)送SYNC命令: 從服務器會發(fā)送SYNC命令給主服務器。如果是初次連接復制,從服務器發(fā)送的SYNC命令中不包含任何參數(shù)。如果是增量同步,從服務器會發(fā)送帶有偏移量參數(shù)的SYNC命令。
全量復制或部分復制: 根據(jù)情況,主服務器會執(zhí)行全量復制或部分復制:
全量復制(初次連接): 如果是初次連接復制,主服務器會執(zhí)行全量復制。它會創(chuàng)建一個RDB快照(數(shù)據(jù)庫快照),將數(shù)據(jù)庫中的數(shù)據(jù)快照發(fā)送給從服務器。這樣從服務器就能夠擁有主服務器的完整數(shù)據(jù)集。
部分復制(增量同步): 如果是增量同步,主服務器會從記錄的偏移量處開始,將從偏移量后的所有更新數(shù)據(jù)發(fā)送給從服務器。這樣從服務器就能夠獲取在斷開網(wǎng)絡期間主服務器的更新數(shù)據(jù)。
復制數(shù)據(jù)傳輸: 主服務器會將全量數(shù)據(jù)或增量數(shù)據(jù)通過網(wǎng)絡傳輸給從服務器。從服務器會接收并處理這些數(shù)據(jù),更新自己的數(shù)據(jù)集。
復制過程繼續(xù): 一旦復制數(shù)據(jù)傳輸完成,從服務器會持續(xù)地與主服務器保持連接,接收來自主服務器的增量更新。這樣,主從庫之間的數(shù)據(jù)保持同步。
需要注意的是,當網(wǎng)絡斷開時間較長或斷開期間數(shù)據(jù)更新較大時,增量同步可能會導致從服務器落后于主服務器。在網(wǎng)絡恢復后,從服務器需要足夠的時間來接收和處理更新數(shù)據(jù),以保持與主服務器的數(shù)據(jù)同步。

一般的排查流程
檢查網(wǎng)絡連接問題: 首先,確保網(wǎng)絡連接問題的確是造成主從庫通信中斷的原因。檢查網(wǎng)絡配置、防火墻規(guī)則、路由等設置,確保主從庫之間可以互相訪問。
重新連接網(wǎng)絡: 如果網(wǎng)絡問題是暫時的,你可以嘗試恢復網(wǎng)絡連接,讓主從庫之間恢復通信。
檢查主從狀態(tài): 在主從庫網(wǎng)絡連接恢復后,使用
INFO replication
命令檢查主從庫的同步狀態(tài)。確保主庫已將數(shù)據(jù)同步到從庫。手動重新同步: 如果主從庫之間的網(wǎng)絡斷開時間較長,可以考慮進行手動重新同步:
在從庫上,使用
SLAVEOF NO ONE
命令解除從庫狀態(tài)。在從庫上,刪除持久化文件(RDB文件或AOF文件)。
在從庫上,執(zhí)行
SLAVEOF master_ip master_port
命令,將其重新設置為主庫的從庫。在主庫上,執(zhí)行
SLAVEOF NO ONE
命令解除主庫狀態(tài)。在主庫上,執(zhí)行
SLAVEOF slave_ip slave_port
命令,將其重新設置為從庫的主庫。手動復制數(shù)據(jù): 如果網(wǎng)絡斷開時間較長且重新同步不可行,你可能需要手動復制數(shù)據(jù)。在主庫上導出數(shù)據(jù),并在從庫上導入數(shù)據(jù)。
備份和恢復: 如果網(wǎng)絡問題無法解決,你可能需要在網(wǎng)絡恢復后考慮從主庫重新備份數(shù)據(jù),然后在從庫上進行數(shù)據(jù)恢復。
總結
文章中介紹了Redis主從庫架構以及如何配置、維護和解決主從庫網(wǎng)絡斷開的問題。以下是文章中涉及到的主要內容:
Redis主從庫架構及其保證的高可靠性:
Redis主從庫的目的是實現(xiàn)高可靠性,通過數(shù)據(jù)持久化、主從復制、Sentinel哨兵和Cluster集群等方式來保障數(shù)據(jù)的安全性和可用性。
如何保證副本數(shù)據(jù)一致:
Redis通過全量復制和部分復制(增量同步)來保證主從庫之間的數(shù)據(jù)一致性。復制偏移量和復制積壓緩沖區(qū)等機制用于記錄和傳輸數(shù)據(jù)。
主從庫第一次同步的過程:
主從庫之間的第一次同步涉及主服務器創(chuàng)建RDB快照,發(fā)送給從服務器,以及記錄期間的寫操作進行命令傳播。
PSYNC命令和增量同步:
PSYNC命令用于主從庫網(wǎng)絡斷開后的增量同步。完全同步用于初次連接,部分同步用于增量同步,從而減少數(shù)據(jù)傳輸量。
主從從架構及其優(yōu)勢:
主從從架構是在主從架構基礎上的擴展,通過級聯(lián)的方式減輕主服務器的復制壓力,實現(xiàn)更高的可用性和負載均衡。
配置主從從架構的步驟:
安裝和配置主服務器,從服務器1和從服務器2。
重啟主服務器,查看主服務器信息。
進行測試,驗證主從庫之間是否同步。
解決主從庫間網(wǎng)絡斷開問題:
檢查網(wǎng)絡連接問題,確保主從庫之間可以互相訪問。
重新連接網(wǎng)絡,恢復通信。
檢查主從狀態(tài),確保同步。
手動重新同步,嘗試恢復數(shù)據(jù)一致性。
手動復制數(shù)據(jù)或備份恢復數(shù)據(jù)。