Redis持久化、主從與哨兵架構詳解

圣辉發表於2024-05-02

參考

圖靈課堂

https://zhuanlan.zhihu.com/p/443951927

https://blog.csdn.net/weixin_37548768/article/details/124538778?spm=1001.2014.3001.5502

https://www.runoob.com/redis/redis-transactions.html

redis支援持久化到磁碟,這樣可用進一步保證資料的完整性。

redis持久化分為兩種,一個是RDB,一個是AOF。

RDB快照(snapshot)

RDB是Redis的一種資料持久化到磁碟的策略,是一種以記憶體快照形式儲存Redis資料的方式。所謂快照,就是把某一時刻的狀態以檔案的形式進行全量備份到磁碟,這個快照檔案就稱為RDB檔案,其中RDB是Redis DataBase的縮寫。

在預設情況下, Redis 將記憶體資料庫快照儲存在名字為 dump.rdb 的二進位制檔案中。
可以對 Redis 進行設定, 讓它在“ N 秒內資料集至少有 M 個改動”這一條件被滿足時, 自動儲存一次資料集。
比如說, 以下設定會讓 Redis 在滿足“ 60 秒內有至少有 1000 個鍵被改動”這一條件時, 自動儲存一次資料集:
# save 900 1
# save 300 10
# save 60 1000 //關閉RDB只需要將所有的save儲存策略註釋掉即可。

bgsave的寫時複製(COW)機制

Redis 藉助作業系統提供的寫時複製技術(Copy-On-Write, COW),在生成快照的同時,依然可以正常處理寫命令。因為不可能在複製的時候拒絕提供寫服務。
簡單來說,bgsave 子程序是由主執行緒 fork 生成的,可以共享主執行緒的所有記憶體資料。bgsave 子程序執行後,開始讀取主執行緒的記憶體資料,並把它們寫入 RDB 檔案。
此時,如果主執行緒對這些資料也都是讀操作,那麼,主執行緒和 bgsave 子程序相互不影響。
但是,如果主執行緒要修改一塊資料,那麼,這塊資料就會被複制一份,生成該資料的副本。然後,bgsave 子程序會把這個副本資料寫入 RDB 檔案(寫入副本的是修改之前的資料,後續全量RDB的時候修改的也會重新寫入),而在這個過程中,主執行緒仍然可以直接修改原來的資料。

save和bgsave的對比

命令  save bgsave
IO型別 同步 非同步
是否阻塞redis其它命令
否(在生成子程序執行呼叫fork函
數時會有短暫阻塞)
複雜度 O(n) O(n)
優點 不會消耗額外記憶體 不阻塞客戶端命令
缺點 阻塞客戶端命令
需要fork子程序,消耗記憶體

AOF(append-only file)

快照功能並不是非常耐久(durable): 如果 Redis 因為某些原因而造成故障停機, 那麼伺服器將丟失最近寫入、且仍未儲存到快照中的那些資料。容易丟失資料。但是恢復速度很快。
從 1.1 版本開始, Redis 增加了一種完全的持久化方式: AOF 持久化,支援將修改的每一條指令記錄進檔案appendonly.aof中(先寫入os cache,每隔一段時間fsync到磁碟)。
注意,如果執行帶過期時間的set命令,aof檔案裡記錄的是並不是執行的原始命令,而是記錄key過期的時間戳;例如:
比如執行“set tuling 888 ex 1000”,對應aof檔案裡記錄如下
3
$3
set
$6
tuling
$3
888
*3
$9
PEXPIREAT
$6
tuling
$13
1604249786301
開啟aof的配置:
# appendonly yes
可以配置 Redis 將資料 fsync 到磁碟頻次,有三個選項:
  • 1 appendfsync always:每次有新命令追加到 AOF 檔案時就執行一次 fsync ,非常慢,也非常安全。
  • 2 appendfsync everysec:每秒 fsync 一次,足夠快,並且在故障時只會丟失 1 秒鐘的資料。
  • 3 appendfsync no:從不 fsync ,將資料交給作業系統來處理。更快,也更不安全的選擇。
推薦(並且也是預設)的措施為每秒 fsync 一次, 這種 fsync 策略可以兼顧速度和安全性。

aof重寫

因為aof儲存的檔案是追加寫入的,所以aof檔案的大小會隨著時間的流逝而越來越大,所以AOF檔案裡可能有太多沒用指令;所以就有了針對aof檔案的重寫。
例如set key1 v1;set key1 v2;set key1 v3;經過最佳化之後會變成set key1 v3
如下兩個配置可以控制AOF自動重寫頻率
1 # auto‐aof‐rewrite‐min‐size 64mb //aof檔案至少要達到64M才會自動重寫,檔案太小恢復速度本來就很快,重寫的意義不大
2 # auto‐aof‐rewrite‐percentage 100 //aof檔案自上一次重寫後檔案大小增長了100%則再次觸發重寫。
當然AOF還可以手動重寫,進入redis客戶端執行命令bgrewriteaof重寫AOF
注意,AOF重寫redis會fork出一個子程序去做(與bgsave命令類似),不會對redis正常命令處理有太多影響

生產環境可以都啟用,redis啟動時如果既有rdb檔案又有aof檔案則優先選擇aof檔案恢復資料,因為aof一般來說資料更全一點。

混合持久化

重啟 Redis 時,我們很少使用 RDB來恢復記憶體狀態,因為會丟失大量資料。我們通常使用 AOF 日誌重放,但是重放 AOF 日誌效能相對 RDB來說要慢很多,這樣在 Redis 例項很大的情況下,啟動需要花費很長的時間。 Redis 4.0 為了解決這個問題,帶來了一個新的持久化選項——混合持久化。 4.0預設是開啟混合持久化的。
配置如下:
# aof‐use‐rdb‐preamble yes
但是使用混合持久化必須要先開啟aof持久化。
appendonly yes
如果開啟了混合持久化,AOF在重寫時,不再是單純將記憶體資料轉換為RESP命令寫入AOF檔案,而是將重寫這一刻之前的記憶體做RDB快照處理,並且將RDB快照內容和增量的AOF修改記憶體資料的命令存在一起,都寫入新的AOF檔案,新的檔案一開始不叫appendonly.aof,等到重寫完新的AOF檔案才會進行改名,覆蓋原有的AOF檔案,完成新舊兩個AOF檔案的替換。
於是在 Redis 重啟的時候,可以先載入 RDB 的內容,然後再重放增量 AOF 日誌就可以完全替代之前的AOF 全量檔案重放,因此重啟效率大幅得到提升。檔案字尾還是AOF。優先順序高於RDB。

Redis資料備份策略:

  • 1. 寫crontab定時排程指令碼,每小時都copy一份rdb或aof的備份到一個目錄中去,僅僅保留最近48小時的備份
  • 2. 每天都保留一份當日的資料備份到一個目錄中去,可以保留最近1個月的備份
  • 3. 每次copy備份的時候,都把太舊的備份給刪了
  • 4. 每天晚上將當前機器上的備份複製一份到其他機器上,以防機器損壞

Redis主從架構

1、複製一份redis.conf檔案

2、將相關配置修改為如下值:
port 6380
pidfile /var/run/redis_6380.pid  # 把pid程序號寫入pidfile配置的檔案
logfile "6380.log"
dir /usr/local/redis-5.0.3/data/6380  # 指定資料存放目錄

# 需要註釋掉bind # bind 127.0.0.1(bind繫結的是自己機器網路卡的ip,如果有多塊網路卡可以配多個ip,代表允許客戶端透過機器的哪些網路卡ip去訪問,內網一般可以不配置bind,註釋掉即可) 3、配置主從複製 replicaof 本機的IP 6379 # 從本機6379的redis例項複製資料,Redis 5.0之前使用slaveof replica-read-only yes # 配置從節點只讀 4、啟動從節點 redis-server redis.conf # redis.conf檔案務必用你複製並修改了之後的redis.conf檔案 5、連線從節點 redis-cli -p 6380 6、測試在6379例項上寫資料,6380例項是否能及時同步新修改資料 7、可以自己再配置一個6381的從節點

Redis主從工作原理

如果你為master配置了一個slave,不管這個slave是否是第一次連線上Master,它都會傳送一個PSYNC命令給master請求複製資料。
master收到PSYNC命令後,會在後臺進行資料持久化透過bgsave生成最新的rdb快照檔案,持久化期間,master會繼續接收客戶端的請求,它會把這些可能修改資料集的請求快取在記憶體中。當持久化進行完畢以後,master會把這份rdb檔案資料集傳送給slave,slave會把接收到的資料進行持久化生成rdb,然後再載入到記憶體中。然後,master再將之前快取在記憶體中的命令傳送給slave。然後保持這個連結,master的修改都會透過這個連線發給slave節點,保證資料的同步。(這整個過程的複製時redis的後臺執行緒來控制的)。
當master與slave之間的連線由於某些原因而斷開時,slave能夠自動重連Master,如果master收到了多個slave併發連線請求,它只會進行一次持久化,而不是一個連線一次,然後再把這一份持久化的資料傳送給多個併發連線的slave。如果短時間的斷聯,master的快取可以放下這段時間的修改,那麼就將快取中的資料傳送給slave;如果斷聯時間很長,那麼就會重新觸發一次RDB。

資料部分複製:斷點續傳

當master和slave斷開重連後,一般都會對整份資料進行復制。但從redis2.8版本開始,redis改用可以支援部分資料複製的命令PSYNC去master同步資料,slave與master能夠在網路連線斷開重連後只進行部分資料複製(斷點續傳)。
master會在其記憶體中建立一個複製資料用的快取佇列,快取最近一段時間的資料,master和它所有的slave都維護了複製的資料下標offset和master的程序id,因此,當網路連線斷開後,slave會請求master繼續進行未完成的複製,從所記錄的資料下標開始。如果master程序id變化了,或者從節點資料下標offset太舊,已經不在master的快取佇列裡了,那麼將會進行一次全量資料的複製。
透過這樣的方式可用減少主從同步的壓力,降低頻寬壓力。
主從複製(部分複製,斷點續傳)流程圖:

主從複製風暴

如果主節點掛載的從節點太多,那麼就可能會導致主節點複製壓力太大,從而影響對外部的服務。降低redis的可用性。這就是主從複製風暴。為了避免這樣的情況發生,可以將從節點掛載到從節點上,形成分層的結構。主節點直連的從節點數量降低。

主從架構的優缺點

Redis的主從架構(Master-Slave)是一種常用的資料複製和擴充套件策略,其優缺點主要體現在以下幾個方面:

優點:

  1. 資料備份和容災:主從架構提供了資料的備份功能,從節點可以實時或非同步地複製主節點的資料,確保資料的可靠性。當主節點發生故障時,從節點可以迅速切換為主節點,保證服務的連續性。
  2. 讀寫分離:主節點通常負責寫操作,而從節點則負責讀操作。這種讀寫分離的策略可以顯著提高系統的效能,因為讀操作通常比寫操作更頻繁,而多個從節點可以並行處理讀請求。
  3. 擴充套件性:主從架構允許透過增加從節點的數量來擴充套件系統的讀效能。當讀請求量增加時,可以新增更多的從節點來分擔讀壓力。
  4. 靈活性:主從架構支援多種同步策略,如全量同步和增量同步。全量同步適用於主從節點之間資料量差異較大的情況,而增量同步則適用於資料量差異較小的情況。

缺點:

  1. 可靠性問題:雖然主從架構提供了資料備份的功能,但仍然存在可靠性問題。如果主節點和從節點同時當機,那麼整個系統將無法提供服務。此外,如果主節點在當機前有部分資料未能及時同步到從節點,那麼在切換主節點後可能會導致資料不一致的問題。如果主節點異常,從節點並不能主動頂上去,還需要人工干預。
  2. 複雜性和管理成本:主從架構的配置和管理相對複雜,需要確保主節點和從節點之間的網路連線穩定可靠,並需要定期監控主從節點的狀態和效能。此外,當需要新增或刪除從節點時,也需要進行額外的配置和管理操作。
  3. 延遲問題:由於從節點需要複製主節點的資料,因此存在一定的延遲。這種延遲可能會影響系統的實時性和一致性。特別是當主節點的寫操作非常頻繁時,從節點的延遲可能會更加嚴重。
  4. 容量和效能瓶頸:雖然從節點可以擴充套件系統的讀效能,但整個系統的容量和效能仍然受限於主節點的處理能力。如果主節點的處理能力不足,那麼即使新增再多的從節點也無法提高系統的整體效能。

綜上所述,Redis的主從架構具有資料備份、讀寫分離、擴充套件性和靈活性等優點,但也存在可靠性問題、複雜性和管理成本、延遲問題以及容量和效能瓶頸等缺點。因此,在選擇是否使用主從架構時需要根據具體的業務需求和場景進行權衡和決策。

管道(Pipeline)

對於redis來說,每次在redis中運算元據是很快的;但是建立連線和資料傳輸不一定是很快的,所以為了提升效率,就提出了管道的概念,將多個請求一次性的傳送到redis中。
需要注意到是用pipeline方式打包命令傳送,redis必須在處理完所有命令前先快取起所有命令的處理結果。打包的命令越多,快取消耗記憶體也越多。所以並不是打包的命令越多越好。
pipeline中傳送的每個command都會被server立即執行,如果執行失敗,將會在此後的響應中得到資訊;也就是pipeline並不是表達“所有command都一起成功”的語義,管道中前面命令失敗,後面命令不會有影響,繼續執行。也就是說pipeline並不保證原子性。只是減少了和redis之間的互動,降低了網路壓力。如果出現了異常,要在業務側進行處理。

事務

Redis 事務可以一次執行多個命令, 並且帶有以下三個重要的保證:

  • 批次操作在傳送 EXEC 命令前被放入佇列快取。批次操作在傳送 EXEC 命令前被放入佇列快取,並不會被實際執行,也就不存在事務內的查詢要看到事務裡的更新,事務外查詢不能看到。
  • 收到 EXEC 命令後進入事務執行,事務中任意命令執行失敗,其餘的命令依然被執行。
  • 在事務執行過程,其他客戶端提交的命令請求不會插入到事務執行命令序列中。

一個事務從開始到執行會經歷以下三個階段:

  • 開始事務。
  • 命令入隊。
  • 執行事務。

單個 Redis 命令的執行是原子性的,但 Redis 沒有在事務上增加任何維持原子性的機制,所以 Redis 事務的執行並不是原子性的。

事務可以理解為一個打包的批次執行指令碼,但批次指令並非原子化的操作,中間某條指令的失敗不會導致前面已做指令的回滾,也不會造成後續的指令不做。

命令:

1 DISCARD
取消事務,放棄執行事務塊內的所有命令。
2 EXEC
執行所有事務塊內的命令。
3 MULTI
標記一個事務塊的開始。
4 UNWATCH
取消 WATCH 命令對所有 key 的監視。
5 WATCH key [key ...]
監視一個(或多個) key ,如果在事務執行之前這個(或這些) key 被其他命令所改動,那麼事務將被打斷。

注意事項:

若在事務佇列中存在命令性錯誤(類似於java編譯性錯誤),則執行EXEC命令時,所有命令都不會執行
例如出現了setget這樣,那麼佇列中的全部都不執行。
若在事務佇列中存在語法性錯誤(類似於java的1/0的執行時異常),則執行EXEC命令時,其他正確命令會被執行,錯誤命令丟擲異常。
不會出現回滾的現象。
不建議使用redis的事務。

lua指令碼

Redis在2.6推出了指令碼功能,允許開發者使用Lua語言編寫指令碼傳到Redis中執行。使用指令碼的好處如下:
1、減少網路開銷:本來5次網路請求的操作,可以用一個請求完成,原先5次請求的邏輯放在redis伺服器上完成。使用指令碼,減少了網路往返時延。這點跟管道類似。
2、原子操作:Redis會將整個指令碼作為一個整體執行,中間不會被其他命令插入。管道不是原子的,不過redis的批次操作命令(類似mset)是原子的。
3、替代redis的事務功能:redis自帶的事務功能很雞肋,而redis的lua指令碼幾乎實現了常規的事務功能,官方推薦如果要使用redis的事務功能可以用redis lua替代。
注意,不要在Lua指令碼中出現死迴圈和耗時的運算,否則redis會阻塞,將不接受其他的命令, 所以使用時要注意不能出現死迴圈、耗時的運算。redis是單程序、單執行緒執行指令碼。管道不會阻塞redis。

哨兵架構

sentinel哨兵是特殊的redis服務,不提供讀寫服務,主要用來監控redis例項節點。
哨兵架構下client端第一次從哨兵找出redis的主節點,後續就直接訪問redis的主節點,不會每次都透過sentinel代理訪問redis的主節點,當redis的主節點發生變化,哨兵會第一時間感知到,並且將新的redis主節點通知給client端(這裡面redis的client端一般都實現了訂閱功能,訂閱sentinel釋出的節點變動訊息)

哨兵啟動流程

在Redis哨兵架構中,通常需要先啟動服務節點(主節點和從節點),然後再啟動哨兵節點

這是因為哨兵節點的作用是監控Redis節點的狀態,並在主節點發生故障時自動將從節點切換為主節點,從而實現自動故障轉移。如果先啟動哨兵節點而沒有服務節點可監控,那麼哨兵節點將無法正常工作。具體來說,啟動Redis哨兵架構的步驟大致如下:

  1. 配置並啟動Redis服務節點,包括主節點和從節點。
  2. 配置Redis哨兵,指定要監控的主節點和從節點的資訊。這可以透過配置檔案或命令列引數來完成。
  3. 啟動Redis哨兵節點。在啟動後,哨兵節點會開始監控指定的Redis節點,並等待故障轉移事件的發生。

需要注意的是,在啟動哨兵節點之前,必須確保主從模式已經正確安裝和配置,並且所有的Redis工作節點都已經正常執行。這是因為哨兵模式依賴於主從模式來監控Redis節點的狀態,並在必要時進行故障轉移。

哨兵搭建過程

1、複製一份sentinel.conf檔案
cp sentinel.conf sentinel-26379.conf

2、將相關配置修改為如下值:
port 26379
daemonize yes
pidfile "/var/run/redis-sentinel-26379.pid"
logfile "26379.log"
dir "/usr/local/redis-5.0.3/data"
# sentinel monitor <master-redis-name> <master-redis-ip> <master-redis-port> <quorum>
# quorum是一個數字,指明當有多少個sentinel認為一個master失效時(值一般為:sentinel總數/2 + 1),master才算真正失效
sentinel monitor mymaster 本機IP 6379 2   # mymaster這個名字隨便取,客戶端訪問時會用到,必須是要和客戶端訪問值一模一樣

3、啟動sentinel哨兵例項
src/redis-sentinel sentinel-26379.conf

4、檢視sentinel的info資訊
src/redis-cli -p 26379
127.0.0.1:26379>info
可以看到Sentinel的info裡已經識別出了redis的主從

5、可以自己再配置兩個sentinel,埠26380和26381,注意上述配置檔案裡的對應數字都要修改
設定主節點是6379;兩個從節點分別是6380,6381.
sentinel叢集都啟動完畢後,會將哨兵叢集的後設資料資訊寫入所有sentinel的配置檔案裡去(追加在檔案的最下面),我們檢視下如下配置檔案sentinel-26379.conf,如下所示:
sentinel known-replica mymaster 192.168.0.60 6380 #代表redis主節點的從節點資訊 
sentinel known-replica mymaster 192.168.0.60 6381 #代表redis主節點的從節點資訊
sentinel known-sentinel mymaster 192.168.0.60 26380 52d0a5d70c1f90475b4fc03b6ce7c3c56935760f #代表感知到的其它哨兵節點
sentinel known-sentinel mymaster 192.168.0.60 26381 e9f530d3882f8043f76ebb8e1686438ba8bd5ca6 #代表感知到的其它哨兵節點

當redis主節點如果掛了,哨兵叢集會重新選舉出新的redis主節點,同時會修改所有sentinel節點配置檔案的叢集後設資料資訊,比如6379的redis如果掛了,假設選舉出的新主節點是6380,則sentinel檔案裡的叢集後設資料資訊會變成如下所示:

sentinel known-replica mymaster 192.168.0.60 6379 #代表主節點的從節點資訊 
sentinel known-replica mymaster 192.168.0.60 6381 #代表主節點的從節點資訊
sentinel known-sentinel mymaster 192.168.0.60 26380 52d0a5d70c1f90475b4fc03b6ce7c3c56935760f #代表感知到的其它哨兵節點
sentinel known-sentinel mymaster 192.168.0.60 26381 e9f530d3882f8043f76ebb8e1686438ba8bd5ca6 #代表感知到的其它哨兵節點

同時還會修改sentinel檔案裡之前配置的mymaster對應的6379埠,改為6380
sentinel monitor mymaster 192.168.0.60 6380 2

當6379的redis例項再次啟動時,哨兵叢集根據叢集後設資料資訊就可以將6379埠的redis節點作為從節點加入叢集

哨兵架構的優缺點

Redis哨兵(Sentinel)系統是Redis用來實現高可用性和監控的工具,它能夠幫助管理多個Redis伺服器例項,並在出現故障時進行適當的動作,比如自動故障遷移或傳送警告。以下是Redis哨兵架構的一些優缺點:
優點:
1. 高可用性:哨兵系統能夠確保在主Redis例項出現故障時,自動將備用例項提升為新的主例項,以實現服務的持續可用性。
2. 監控:哨兵會不斷地監控Redis例項的健康狀況,包括節點是否可達、是否響應命令等,並在出現問題時發出警告。
3. 故障遷移:當主Redis例項不可用時,哨兵可以根據配置的規則自動將一個從例項轉換為主例項,以實現故障的無縫遷移。
4. 配置靈活:哨兵允許使用者配置多種引數,如選舉超時時間、故障轉移的策略等,以適應不同的業務需求。
5. 支援多資料中心:哨兵支援設定多個哨兵例項,每個例項負責不同的Redis主從叢集,這樣就可以實現跨資料中心的故障轉移能力。
缺點:
1. 複雜性:相對於單例項的Redis,哨兵架構引入了更多的配置和元件,這可能會增加系統的複雜性。
2. 效能開銷:哨兵系統會有一部分的效能開銷,因為它需要監控和維護額外的資訊,並處理故障轉移等邏輯。
3. 多哨兵配置複雜:在複雜的環境中,多個哨兵之間的協調和配置可能會變得複雜,需要仔細規劃。
4. 不支援讀寫分離:哨兵架構不支援傳統的讀寫分離,因為從例項在故障轉移時可能被提升為新的主例項。
5. 資料一致性:在某些複雜的故障轉移情況下,可能會出現短暫的資料不一致問題,雖然Redis支援事務和持久化機制,但在極端情況下仍需注意資料一致性。
總體而言,Redis哨兵系統在提供高可用性和監控功能的同時,也帶來了一定的複雜性和效能考慮。對於需要高可用性的Redis應用場景,哨兵是一個很好的選擇,但在規劃和部署時需要仔細考慮上述優缺點。

同時哨兵架構中,主節點會儲存全部的資料,增加節點只是可以減少訪問併發的壓力,對寫入記憶體壓力來說沒有什麼提升。

哨兵模式下故障轉移過程

在Redis哨兵(Sentinel)模式下,故障轉移是指當主Redis例項因某些原因不可用時,哨兵系統將會觸發一個流程,將一個從例項(Slave)升級為新的主例項(Master),並確保所有從例項跟隨新的主例項。以下是故障轉移的基本流程:
1. **監控狀態**:哨兵系統持續監控Redis主例項和從例項的健康狀態。它透過向例項傳送PING命令並監聽例項的回覆來判斷例項是否健康。
2. **故障檢測**:如果哨兵檢測到主例項不可達或者響應命令出現異常,它將認為主例項出現了故障。
3. **選舉過程**:當哨兵確定主例項不可用時,它將開始一個選舉(Election)過程。選舉過程中,哨兵會嘗試聯絡其他哨兵例項,以確定是否有其他哨兵已經發起了一個有效的選舉。
4. **領導者選舉**:如果哨兵例項在選舉過程中被選為領導者(Leader),它將負責協調故障轉移過程。如果多個哨兵例項同時爭奪領導地位,它們將透過一個基於Redis投票機制的方式決定領導者。
5. **命令複製**:領導者哨兵會從剩餘的從例項中選擇一個例項(通常是具有最高執行序號的例項)作為新的主例項,並透過Redis命令複製協議(REPL)來同步這個例項的記憶體狀態到其他從例項。
6. **更新配置**:一旦新的主例項被選舉出來,哨兵將更新配置,使得其他從例項開始複製新的主例項的資料。這個過程可能包括更新從例項的配置檔案或者直接透過Redis命令來更改從屬關係。
7. **故障轉移完成**:在新的主例項準備好並配置所有從例項之後,故障轉移過程完成。此時,哨兵會向客戶端傳送訊息,告知它們新的主例項的位置,客戶端可以根據這個資訊更新它們的連線。
8. **後續處理**:舊的故障的主例項在恢復後,可能會被配置為從例項並開始複製新的主例項的資料,或者根據具體情況被移除或重新配置。
整個故障轉移過程是由哨兵系統自動完成的,不需要人工干預。但是,為了確保故障轉移的順利進行,需要正確配置哨兵系統,包括指定主例項和從例項、設定選舉超時時間、配置故障轉移策略等。

故障轉移中如何保證資料的一致性

在Redis哨兵(Sentinel)模式的故障轉移過程中,確保資料一致性是一個重要的考慮點。以下是一些措施和機制,用於確保在故障轉移過程中資料的一致性:
1. **寫入確認**:在故障轉移過程中,新的主例項在接替舊的主例項之前,會等待一些寫入操作被確認。這可以透過配置引數`redis-sentinel min-slaves-to-write`來實現,它指定了一個最小數量的從例項必須處於“線上”(UP)狀態,主例項才能執行寫操作。
2. **複製偏移量**:Redis使用複製偏移量(replication offset)來跟蹤主例項和從例項之間資料同步的位置。在故障轉移過程中,新的主例項會等待直到它的複製偏移量追趕上其他從例項,確保從例項有最新的一致性資料。
3. **斷線重連**:在故障轉移後,從例項會嘗試與新的主例項重新建立連線,並繼續同步資料。如果從例項在一定時間內無法連線到新的主例項,它會嘗試重新連線到舊的 主例項(如果舊的 主例項恢復了),這樣可以避免資料不一致。
4. **配置更新**:故障轉移後,從例項會根據新的主例項資訊更新它們的配置,確保所有從例項都知道新的主例項的位置。
5. **Sentinel監控**:哨兵系統會繼續監控所有例項的健康狀態,並在檢測到任何不一致性時採取行動。例如,如果一個從例項落後於新的主例項太多,哨兵可能會嘗試將該從例項從舊的 主例項那裡重新同步資料。
6. **客戶端重連**:客戶端應用需要監聽主例項的變化,並在必要時更新它們連線的主例項。通常,這可以透過使用Redis客戶端的哨兵支援來實現,客戶端會自動重連到新的主例項。
7. **持久化機制**:Redis提供了資料持久化機制,如RDB快照和AOF日誌,這些機制可以幫助在故障轉移後恢復資料。確保在故障轉移前有最新的快照或AOF日誌重做,可以減少資料不一致的風險。

透過上述機制,Redis哨兵系統在故障轉移過程中儘量保證了資料的一致性。然而,在實際操作中,特別是在故障轉移的初期階段,可能會存在短暫的資料不一致。因此,設計系統時應考慮這種短暫的不一致性,並在必要時實施額外的資料一致性保障措施。

請推薦一些確保資料一致性的最佳實踐。

確保資料一致性是分散式系統設計中的一個重要方面,特別是在像Redis這樣的資料儲存系統中。以下是一些確保資料一致性的最佳實踐:
1. **使用同步複製**:在Redis中,確保使用同步複製(sync replication)模式,這樣主例項在寫入資料後,會等待從例項確認接收到了這些資料,然後再回復客戶端。這可以透過設定`replica-ping-timeout`和`replica-offset-threshold`引數來調整。
2. **最小同步偏移量**:透過設定`min-slaves-to-write`引數,可以指定主例項需要至少有一定數量的從例項處於線上狀態並且同步偏移量小於閾值時,才能執行寫操作。這樣可以確保主例項寫入的資料被至少一個從例項確認。
3. **使用Redis事務**:雖然Redis事務不能像關係型資料庫那樣保證原子性和一致性,但在執行涉及多個操作的任務時,使用`MULTI`、`EXEC`、`DISCARD`和`WATCH`命令可以幫助避免部分寫入問題。
4. **使用Lua指令碼**:對於複雜的操作,可以使用Lua指令碼在Redis中執行,這樣可以確保多個步驟要麼全部成功,要麼全部失敗,從而保持資料的一致性。
5. **快照和持久化**:定期建立RDB快照和/或使用AOF日誌記錄所有的寫操作,可以幫助在系統故障時恢復資料。確保在發生故障轉移之前有最新的快照或AOF日誌重做。
6. **哨兵和叢集配置**:正確配置Redis哨兵,確保它在檢測到故障時可以正確地執行故障轉移。同時,如果使用Redis叢集,確保叢集模式下的資料分佈和複製配置是合理的。
7. **監控和報警**:實施監控系統來跟蹤Redis例項的健康狀態和效能指標。在檢測到任何異常時,確保有報警系統通知運維人員。
8. **分散式鎖或事務管理**:在需要原子性操作的場景中,可以使用分散式鎖或者其他事務管理工具(如Redis事務或基於Redis的分散式鎖庫)來確保資料一致性。
9. **客戶端重試機制**:在客戶端實現重試機制,當遇到資料不一致或服務不可用時,可以嘗試重新連線或重新執行操作。
10. **最小化資料不一致視窗**:在設計系統時,儘量減少資料不一致性的視窗時間。例如,使用分散式訊息佇列或其他佇列技術來緩衝寫入操作,直到資料一致性得到保證。
11. **定期審查和測試**:定期審查系統的資料一致性措施,並進行故障轉移和恢復流程的測試,以確保在實際故障發生時,系統能夠按照預期工作。
這些實踐可以幫助設計更加健壯和一致性的Redis應用程式,但需要注意的是,在分散式系統中完全消除資料不一致性是不可能的,關鍵是要在可用性和一致性之間找到合適的平衡點。

相關文章