Redis能保證資料不丟失嗎?

萤火架构發表於2024-02-23

大家即使沒用過Redis,也應該都聽說過Redis的威名。

Redis是一種Nosql型別的資料儲存,全稱Remote Dictionary Server,也就是遠端字典伺服器,用過Dictionary的應該都知道它是一種鍵值對(Key-Value)的資料結構,所以Redis也稱為KV儲存。

Redis的用途十分廣泛,包括幫助網頁快速載入,管理登入狀態,更新社交動態、遊戲積分排名、電商搶購秒殺,等等,有點規模的應用後邊都有它的身影。

Redis能保證資料不丟失嗎?

Redis之所以這麼流行,首先是因為它的處理速度特別快,它主要在記憶體中處理資料;其次它提供了多種資料結構,使用起來比較方便,而且這些資料結構的操作時間複雜度都很優秀;最後Redis會將資料儲存到磁碟中,提供一定的永續性。

但是很多同學常常對Redis的資料安全有所擔憂,大家經常問:Redis能保證資料不丟失嗎?怎麼做到的?本文會簡單說說Redis的資料保護機制,它的好處和侷限,以及我們應該怎樣設定、有哪些高階技巧。

Redis面臨的資料丟失風險

Redis中的資料是有可能丟失的。

首先,咱們搞清楚一個概念——資料永續性。簡單來說,資料永續性就是確保你的資料在遇到各種意外情況時,比如斷電、系統崩潰等,之後還能安然無恙的存在。就像是手機,即使沒電了,充上電之後,裡面的照片和資訊都還在,沒有丟失。

那麼,Redis面臨的資料丟失風險有哪些呢?

上文說到Redis主要在記憶體中運算元據,記憶體是一種臨時儲存,一旦斷電(或者硬體故障、軟體錯誤等),記憶體中的資料就會煙消雲散。有的同學會說,資料不是會儲存到硬碟嗎?是的,但是還是可能會有一些資料來不及寫入硬碟,這是Redis的持久化機制導致的,下邊會進行詳細說明。

而且,即使Redis將全部資料都及時儲存到了硬碟,硬碟出現問題也可能會導致Redis的資料丟失。

另外有的同學會說,我只是在Redis中快取資料,所有的資料在資料庫中都有完整的記錄。這個問題雖然有點超綱,但是這裡還是簡單交代下。這種情況下如果要恢復的資料量比較大,從資料庫恢復資料的時間會比較長,這會延長故障的恢復時間。而且如果系統訪問量比較大,還可能導致快取穿透的問題,擊垮資料庫。

所以,儘管Redis給我們的應用帶來了極速體驗,但是如果不採取措施,資料丟失的風險是實實在在的。下面,我們將探討Redis如何透過各種持久化策略來應對這些風險,儘量保證資料的安全。

基礎策略

保證資料不丟失的基礎策略就是使用Redis自帶的持久化機制,Redis提供了兩種主要的資料持久化方法:RDB(快照)和AOF(追加檔案)。這兩種方法各有千秋,讓我們來詳細瞭解一下。

RDB機制

RDB持久化是透過建立資料集的快照來工作的,在指定的時間間隔內,Redis會自動將記憶體中的資料集寫入硬碟的一個檔案(通常是dump.rdb)。這就像是給資料拍了一張快照,當需要的時候可以隨時從這個快照恢復。

Redis能保證資料不丟失嗎?

優點:

  • 效能高:快照生成時,用到了寫時複製技術,此時Redis主程序只負責寫入資料,實際儲存工作由子程序完成,因此對效能影響較小。
  • 恢復快:與AOF相比,使用RDB檔案恢復資料通常更快。

缺點

  • 資料可能丟失:如果Redis異常停止,那麼最後一次快照之後的所有資料更改都會丟失。
  • 大資料集恢復時間長:雖然比AOF快,但是如果資料集非常大,恢復過程仍然可能需要較長時間。

AOF機制

AOF持久化透過記錄每個寫操作到一個日誌檔案中,實現資料的持久化。這就像是把每次資料變動都先記錄下來,然後再更新到記憶體中,需要恢復時,按照這個操作日誌一步步來就行了。

Redis能保證資料不丟失嗎?

需要注意AOF記錄也很難做到每個寫操作都先持久化到硬碟中,這是因為硬碟的讀寫速度一般都很慢,比記憶體操作低幾個數量級,如果每次都先寫到硬碟,Redis也做不到目前的低延遲高併發。所以寫操作一般都是先快取一段時間,然後再批次flush到硬碟。

優點:

  • 資料安全性高:AOF持久化可以配置不同的同步頻率,例如每秒同步,這樣可以在保證效能的同時,減少資料丟失的風險。
  • 可讀的日誌檔案:AOF檔案是一個純文字檔案,可以被人讀懂,便於理解和問題排查。

缺點

  • 檔案體積大:由於記錄了所有寫操作,AOF檔案的體積通常會大於RDB檔案。
  • 恢復速度慢:與RDB相比,AOF在恢復大量資料時通常更慢,因為需要重新執行所有操作。

配置建議

RDB配置建議

大部分情況下都建議開啟RDB,因為RDB需要的資源相對AOF小很多。如果對資料完整性的要求不高,或者能很快的從其它渠道恢復資料,一般只需要開啟RDB就可夠了。

合理設定快照間隔

Redis的RDB持久化允許我們配置多個不同的快照條件,以適應不同的資料更新頻率和保證資料安全。我們可以在 redis.conf 配置檔案中設定多個快照規則。以下是一個示例配置,展示瞭如何根據資料變化的頻繁程度來設定快照的條件:

# 在900秒內如果至少有1個鍵被改變,則進行一次快照
save 900 1
# 在300秒內如果至少有10個鍵被改變,則進行一次快照
save 300 10
# 在60秒內如果至少有1000個鍵被改變,則進行一次快照
save 60 1000

這樣的配置意味著:

  • 如果資料變化不是很頻繁,我們不需要那麼頻繁地進行快照儲存,以避免不必要的效能開銷。
  • 當資料變化變得更加頻繁時,我們透過更緊密的快照來減少資料丟失的風險。

動態調整快照規則

除了在配置檔案中靜態設定快照規則外,Redis還提供了命令讓我們可以在執行時動態調整快照規則。使用CONFIG SET命令,我們可以根據應用的當前狀態和需求,動態地調整快照條件:

# 動態設定快照規則
redis-cli CONFIG SET save "60 1000 300 10 900 1"

注意事項

  • 效能考量:雖然頻繁的快照可以減少資料丟失的風險,但也可能會對效能產生影響,特別是在資料集很大的情況下。因此,需要根據實際情況權衡快照頻率和效能。
  • 監控與調整:建議監控Redis的效能指標,並根據實際執行情況調整快照規則。隨著業務的發展,可能需要定期回顧和調整這些設定。

AOF配置建議

當資料僅儲存在Redis中,或對資料的丟失難以容忍時,建議開啟AOF。

考慮到效能和資料安全,建議設定為每秒同步一次。這樣既可以保證資料的及時性,又不會對效能影響太大。

以下是一個示例配置:

appendfsync everysec

定期重寫AOF

隨著時間的推移,AOF檔案可能會變得很大,不僅會佔用更多的磁碟空間,而且重啟後或從故障恢復時處理的會比較慢。緩解這個問題,可以使用Redis提供的定期重寫機制。

在AOF重寫過程中,Redis會建立一個新的AOF檔案,這個新檔案僅包含重建當前資料集所需的最小命令集合。例如,如果一系列的INCR命令將某個鍵的值從0遞增到了100,那麼在重寫後的AOF檔案中可能只會記錄一條SET命令來直接設定這個鍵為100,從而大大減小檔案。

透過 auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 引數可以配置自動重寫的條件。

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
  • auto-aof-rewrite-percentage:重寫時機:當前AOF檔案大小相對於上一次重寫後的檔案大小的增長百分比。例如,若設定為100,則表示每當AOF檔案大小翻倍時,Redis將自動觸發AOF重寫。
  • auto-aof-rewrite-min-size:即使滿足了增長百分比條件,Redis也不會立即進行重寫,還需要AOF檔案達到一個最小尺寸。只有當檔案大小超過這個設定值時,才會真正觸發重寫。

透過以上配置,在保證Redis效能的同時,資料安全性也有了基礎的保證。

高階策略

從對基礎策略的分析中我們瞭解到即使採用AOF日誌,因為寫日誌的延遲,資料仍存在丟失的可能性。而且即使資料都寫入到了硬碟,也無法處理單機硬碟故障導致資料丟失的問題。

這一小節就讓我們來看下處理這個問題的一些高階策略,包括主從架構、哨兵系統和叢集架構。這些策略可以提高資料的安全性和可用性。

主從架構實現多副本儲存

在Redis的主從架構中,資料會從一個主節點複製到一個或多個從節點。這樣做的好處是,即使主節點出現問題,我們也可以從從節點中恢復資料,而且從節點可以繼續提供查詢服務。

工作原理:主節點負責處理所有的寫操作,並將這些操作記錄同步到從節點。從節點則可以處理讀請求,分擔主節點的讀負載。

Redis能保證資料不丟失嗎?

優點

  • 資料冗餘:透過在多個從節點上儲存資料副本,提高了資料的可靠性。
  • 讀負載均衡:從節點可以處理讀請求,幫助分擔主節點的讀負載。

配置示例:

# 從節點配置 
slaveof <masterip> <masterport>

主節點無需特別配置,只需正常啟動。從節點的配置檔案中增加slaveof配置,masterip、masterport是主節點的IP和埠。

哨兵系統實現故障轉移

哨兵系統(Sentinel)是一種用於監控Redis主從節點狀態的系統,能夠在主節點故障時自動進行故障轉移。

工作原理:哨兵透過傳送命令,檢查主從節點的健康狀態。如果主節點不可達,哨兵會自動將其中一個從節點提升為新的主節點,並更新其他從節點以指向新的主節點。

Redis能保證資料不丟失嗎?

優點:

  • 自動故障轉移:提高了系統的可用性,當主節點出現故障時,能夠快速恢復。
  • 監控:哨兵還負責監控Redis節點的執行狀態,提供了一定程度的自動管理。

配置示例:

# 哨兵配置檔案 sentinel.conf
sentinel monitor mymaster <masterip> <masterport> 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
  • sentinel monitor mymaster:這條命令讓哨兵監控一個名為 mymaster 的主節點,其IP和埠分別為 masterip 和 masterport 。數字2表示當至少有兩個哨兵認為主節點不可達時,才會進行故障轉移。這是為了避免因為網路閃斷導致的誤判。這也告訴我們如果需要更高的可用性,哨兵程序也要部署多個,一般3個或5個就夠了。
  • sentinel down-after-milliseconds mymaster 5000:設定哨兵判斷主節點為“下線”的時間。例如,這裡設定為5000毫秒(5秒),如果哨兵在這段時間內無法達到主節點,則認為主節點下線。因為各種原因,哨兵可能會出現誤判的問題,多等一會說不定又能訪問主節點。
  • sentinel failover-timeout mymaster 60000:設定故障轉移的超時時間,單位是毫秒。在這個例子中,設定為60000毫秒(60秒)。如果故障轉移操作在這段時間內沒有完成,則會被取消。
  • sentinel parallel-syncs mymaster 1:設定在故障轉移後,同時可以有多少個從節點同時對新的主節點進行同步。這裡設定為1,意味著一次只有一個從節點可以同步。在故障轉移後,所有從伺服器都需要與新的主伺服器進行全量同步以保證資料一致性。由於全量同步會阻塞從節點,並且可能會消耗較大的網路頻寬和CPU資源,所以透過限制併發同步的從節點數量,可以避免過多從節點同時進行同步帶來的資源壓力過大問題。

叢集架構實現資料冗餘

Redis叢集透過分片的方式來儲存資料,每個分片儲存不同的資料。透過多個節點的協作,實現資料的冗餘和分散式儲存。

工作原理:Redis叢集將所有的資料分為16384個雜湊槽,每個節點負責一部分雜湊槽。客戶端根據特定的雜湊規則,將資料儲存到相應的節點上。

Redis能保證資料不丟失嗎?

優點

  • 資料分片:實現了資料的自動分片,便於管理大規模資料。
  • 高可用性:叢集中的節點可以相互備份,即使部分節點失敗,也不會影響整個叢集的可用性。

配置示例: 配置Redis叢集涉及到啟動多個Redis例項,可使用redis-cli工具建立叢集:

# 啟動Redis例項(假設啟動6個例項作為示例)
redis-server --port 7000 --cluster-enabled yes --cluster-config-file nodes-7000.conf --cluster-node-timeout 5000 --appendonly yes --appendfilename appendonly-7000.aof --dbfilename dump-7000.rdb --logfile 7000.log
# 重複上述命令,修改埠為7001-7005

# 使用redis-cli建立叢集
redis-cli --cluster create <ip1>:7000 <ip2>:7001 <ip3>:7002 <ip4>:7003 <ip5>:7004 <ip6>:7005 --cluster-replicas 1
  • --cluster-enabled yes:啟用Redis叢集模式。
  • --cluster-config-file nodes-7000.conf:指定叢集的配置檔案。這個檔案由Redis自動維護,記錄了叢集中所有節點的資訊。
  • --cluster-node-timeout 5000:設定節點超時時間,單位是毫秒。如果一個節點在這段時間內沒有響應,叢集會認為該節點已經下線。
  • --appendonly yes:啟用AOF持久化模式。在叢集模式下,推薦使用AOF持久化來保證資料安全。
  • --appendfilename appendonly-7000.aof:指定AOF檔案的名字。這裡根據不同的埠號,為每個例項指定了不同的AOF檔名,以避免衝突。
  • --dbfilename dump-7000.rdb:指定RDB檔案的名字。同樣地,根據不同的埠號為每個例項指定了不同的RDB檔名。
  • --logfile 7000.log:指定日誌檔案的名字。這有助於在出現問題時進行故障排查。

透過主從架構、哨兵系統和叢集架構,可以有效地實現資料的多副本儲存、故障轉移和資料冗餘,提高系統的可靠性和可用性,基本上可以避免單機系統的資料丟失問題。

跨機房部署

伺服器所在的機房也可能出現問題,比如光纜被挖斷了、空調系統壞了、機房著火了等實際出現過的狀況,為了解決這些問題,我們還可以透過跨機房的方法來提升Redis的資料可靠性和可用性。

  • 在不同機房間部署主從複製架構。在一個資料中心內設定主節點,在另一個或多個資料中心設定從節點。
  • Sentinel(哨兵)叢集也應跨機房部署,以避免單點故障。
  • 使用Redis Cluster進行跨機房部署,每個機房都可以有多個分片(shard),並且每個分片的主節點和從節點分別位於不同的地理位置,這樣即使一個機房完全不可用,其他機房的副本仍然能夠提供服務。

跨機房部署時需要自行解決網路的通訊問題,讓各個節點之間可以無障礙的相互訪問,機房間最好使用低延遲、高頻寬的專線連線,以加速資料同步過程並降低網路問題導致的資料不一致風險。

還有面試中經常提及的兩地三中心的多活架構,也可以安排上。每個機房都部署一套完整的、獨立處理讀寫請求的Redis叢集,並透過分散式鎖或者資料同步中介軟體等技術保證各個叢集間資料的一致性。

  • 分散式鎖可以採用ZooKeeper、etcd、redis等,確保在多個資料中心進行同步更新時,只有一個資料中心的Redis叢集在給定時間內對某個資源擁有寫許可權。
  • 資料同步中介軟體主要用於實時或近實時地將一個資料中心的寫入操作同步到另一個資料中心。可以使用訊息佇列、專業的資料同步工具(比如阿里巴巴開源的Canal)等。
  • 多活架構還要設計資料分片策略、資料路由機制以及事務處理方式,比如根據地域或者一致性Hash分片來區分使用者,然後使用客戶端驅動路由或者閘道器路由來把使用者導向不同的機房,最後使用分散式事務提交資料。

多活架構比較複雜,我也沒有實際搞過,這裡就不多說了。

其他運維措施

日常運維中的定期檢查和檔案備份,雖然平時看起來不起眼,但在關鍵時刻卻能發揮巨大作用。

運維工具檢測

就像我們用手錶監測心率一樣,使用專業的運維工具可以幫助我們實時監控Redis伺服器的狀態,包括效能指標、資源使用情況、可能的瓶頸等。

具體做法:

  • 選擇合適的工具:市面上有許多優秀的運維監控工具,如Prometheus結合Grafana、Zabbix等,可以根據自己的需求和環境選擇。
  • 定製監控項:根據你的具體需求,定製監控項。比如,記憶體使用率、磁碟使用率、命令執行延遲、連線數等,這些都是常見的監控指標。
  • 設定告警:設定閾值,一旦監控到的資料超過這個閾值,就會觸發告警。這就像是你的手錶在你心率異常時提醒你,幫助你及時發現並處理問題。

定期備份資料

備份就是我們給檔案買了一份保險,無論是誤操作還是系統故障,都能夠確保資料不會丟失,可以快速恢復到備份時的狀態。

具體做法

  • 定期執行:設定一個合理的備份頻率,比如每天凌晨進行一次。頻率的選擇取決於你的業務需求和資料變化的頻繁程度。
  • 自動化:利用crontab等工具自動化備份流程,讓備份工作自動化進行,減少人為遺忘的風險。
  • 遠端儲存:將備份檔案儲存在遠端伺服器或雲端儲存服務上。這樣做的好處是,即使本地發生災難性事件,資料仍然是安全的。

透過實施這些常規措施,我們可以大大提高資料的安全性和系統的穩定性。

總結

說了這麼多,讓我們做一個總結。

如果你的業務對資料的完整性要求非常高,建議開啟AOF持久化,並設定合理的fsync策略(如每秒同步一次)。同時,配合使用主從複製和哨兵系統,以確保資料的高可用性和安全性。

對於讀寫效能有極高要求的場景,可以考慮只使用RDB持久化或者RDB與AOF結合的方式(資料完整性要求高,AOF用於故障恢復,RDB用於重啟加速)。同時,透過增加從節點和合理分配讀寫負載,可以進一步提升效能、提高資料安全性。

如果業務資料量巨大,單個Redis例項難以滿足儲存需求,那麼Redis叢集是一個不錯的選擇。它透過分片來實現資料的分散式儲存,同時保持高可用性。

日常的監控和備份也要搞起來,如果服務和資料及其重要,跨機房部署可以提供極大的資料安全性和系統穩定性。至於傳說中的多活架構,不到萬不得已不要輕易嘗試,極為複雜,成本很高。

最後不要忘了定期演練,搞了這麼多的機制到底能不能發揮作用?有沒有被不小心搞壞,定期演練可以提前發現問題,及時解決,避免更大的損失。


以上就是本文的主要內容。

關注螢火架構,加速技術提升!

相關文章