內存快照:宕機后Redis如何實現快速恢復?

文章目錄

    • 給哪些內存數據做快照?
    • 快照時數據能修改嗎?
    • 可以每秒做一次快照嗎?
    • 小結
    • 每課一問

更多redis相關知識

上節課,我們學習了 Redis 避免數據丟失的 AOF 方法。這個方法的好處,是每次執行只需要記錄操作命令,需要持久化的數據量不大。一般而言,只要你采用的不是 always 的持久化策略,就不會對性能造成太大影響。
但是,也正因為記錄的是操作命令,而不是實際的數據,所以,用 AOF 方法進行故障恢復的時候,需要逐一把操作日志都執行一遍。如果操作日志非常多,Redis 就會恢復得很緩慢,影響到正常使用。這當然不是理想的結果。那么,還有沒有既可以保證可靠性,還能在宕機時實現快速恢復的其他方法呢?
當然有了,這就是我們今天要一起學習的另一種持久化方法:內存快照。所謂內存快照,就是指內存中的數據在某一個時刻的狀態記錄。這就類似于照片,當你給朋友拍照時,一張照片就能把朋友一瞬間的形象完全記下來。
對 Redis 來說,它實現類似照片記錄效果的方式,就是把某一時刻的狀態以文件的形式寫到磁盤上,也就是快照。這樣一來,即使宕機,快照文件也不會丟失,數據的可靠性也就得到了保證。這個快照文件就稱為 RDB 文件,其中,RDB 就是 Redis DataBase 的縮寫。
和 AOF 相比,RDB 記錄的是某一時刻的數據,并不是操作,所以,在做數據恢復時,我們可以直接把 RDB 文件讀入內存,很快地完成恢復。聽起來好像很不錯,但內存快照也并不是最優選項。為什么這么說呢?
我們還要考慮兩個關鍵問題:
對哪些數據做快照?這關系到快照的執行效率問題;
做快照時,數據還能被增刪改嗎?這關系到 Redis 是否被阻塞,能否同時正常處理請求。
這么說可能你還不太好理解,我還是拿拍照片來舉例子。我們在拍照時,通常要關注兩個問題:
如何取景?也就是說,我們打算把哪些人、哪些物拍到照片中;
在按快門前,要記著提醒朋友不要亂動,否則拍出來的照片就模糊了。
你看,這兩個問題是不是非常重要呢?那么,接下來,我們就來具體地聊一聊。先說“取景”問題,也就是我們對哪些數據做快照。

給哪些內存數據做快照?

Redis 的數據都在內存中,為了提供所有數據的可靠性保證,它執行的是全量快照,也就是說,把內存中的所有數據都記錄到磁盤中,這就類似于給 100 個人拍合影,把每一個人都拍進照片里。這樣做的好處是,一次性記錄了所有數據,一個都不少。
當你給一個人拍照時,只用協調一個人就夠了,但是,拍 100 人的大合影,卻需要協調 100 個人的位置、狀態,等等,這當然會更費時費力。同樣,給內存的全量數據做快照,把它們全部寫入磁盤也會花費很多時間。而且,全量數據越多,RDB 文件就越大,往磁盤上寫數據的時間開銷就越大。
對于 Redis 而言,它的單線程模型就決定了,我們要盡量避免所有會阻塞主線程的操作,所以,針對任何操作,我們都會提一個靈魂之問:“它會阻塞主線程嗎?”RDB 文件的生成是否會阻塞主線程,這就關系到是否會降低 Redis 的性能。
Redis 提供了兩個命令來生成 RDB 文件,分別是 save 和 bgsave。
save:在主線程中執行,會導致阻塞;
bgsave:創建一個子進程,專門用于寫入 RDB 文件,避免了主線程的阻塞,這也是 Redis RDB 文件生成的默認配置。
好了,這個時候,我們就可以通過 bgsave 命令來執行全量快照,這既提供了數據的可靠性保證,也避免了對 Redis 的性能影響。
接下來,我們要關注的問題就是,在對內存數據做快照時,這些數據還能“動”嗎? 也就是說,這些數據還能被修改嗎? 這個問題非常重要,這是因為,如果數據能被修改,那就意味著 Redis 還能正常處理寫操作。否則,所有寫操作都得等到快照完了才能執行,性能一下子就降低了。

快照時數據能修改嗎?

在給別人拍照時,一旦對方動了,那么這張照片就拍糊了,我們就需要重拍,所以我們當然希望對方保持不動。對于內存快照而言,我們也不希望數據“動”。
舉個例子。我們在時刻 t 給內存做快照,假設內存數據量是 4GB,磁盤的寫入帶寬是 0.2GB/s,簡單來說,至少需要 20s(4/0.2 = 20)才能做完。如果在時刻 t+5s 時,一個還沒有被寫入磁盤的內存數據 A,被修改成了 A’,那么就會破壞快照的完整性,因為 A’不是時刻 t 時的狀態。因此,和拍照類似,我們在做快照時也不希望數據“動”,也就是不能被修改。
但是,如果快照執行期間數據不能被修改,是會有潛在問題的。對于剛剛的例子來說,在做快照的 20s 時間里,如果這 4GB 的數據都不能被修改,Redis 就不能處理對這些數據的寫操作,那無疑就會給業務服務造成巨大的影響。
你可能會想到,可以用 bgsave 避免阻塞啊。這里我就要說到一個常見的誤區了,避免阻塞和正常處理寫操作并不是一回事。此時,主線程的確沒有阻塞,可以正常接收請求,但是,為了保證快照完整性,它只能處理讀操作,因為不能修改正在執行快照的數據。
為了快照而暫停寫操作,肯定是不能接受的。所以這個時候,Redis 就會借助操作系統提供的寫時復制技術(Copy-On-Write, COW),在執行快照的同時,正常處理寫操作。
簡單來說,bgsave 子進程是由主線程 fork 生成的,可以共享主線程的所有內存數據。bgsave 子進程運行后,開始讀取主線程的內存數據,并把它們寫入 RDB 文件。
此時,如果主線程對這些數據也都是讀操作(例如圖中的鍵值對 A),那么,主線程和 bgsave 子進程相互不影響。但是,如果主線程要修改一塊數據(例如圖中的鍵值對 C),那么,這塊數據就會被復制一份,生成該數據的副本(鍵值對 C’)。然后,主線程在這個數據副本上進行修改。同時,bgsave 子進程可以繼續把原來的數據(鍵值對 C)寫入 RDB 文件。
!https://s3-us-west-2.amazonaws.com/secure.notion-static.com/ddb8be0d-aac2-446b-bc45-ba757b3d8374/1.png
這既保證了快照的完整性,也允許主線程同時對數據進行修改,避免了對正常業務的影響。
到這里,我們就解決了對“哪些數據做快照”以及“做快照時數據能否修改”這兩大問題:Redis 會使用 bgsave 對當前內存中的所有數據做快照,這個操作是子進程在后臺完成的,這就允許主線程同時可以修改數據。
現在,我們再來看另一個問題:多久做一次快照?我們在拍照的時候,還有項技術叫“連拍”,可以記錄人或物連續多個瞬間的狀態。那么,快照也適合“連拍”嗎?

可以每秒做一次快照嗎?

對于快照來說,所謂“連拍”就是指連續地做快照。這樣一來,快照的間隔時間變得很短,即使某一時刻發生宕機了,因為上一時刻快照剛執行,丟失的數據也不會太多。但是,這其中的快照間隔時間就很關鍵了。
如下圖所示,我們先在 T0 時刻做了一次快照,然后又在 T0+t 時刻做了一次快照,在這期間,數據塊 5 和 9 被修改了。如果在 t 這段時間內,機器宕機了,那么,只能按照 T0 時刻的快照進行恢復。此時,數據塊 5 和 9 的修改值因為沒有快照記錄,就無法恢復了。
!https://s3-us-west-2.amazonaws.com/secure.notion-static.com/61474440-7276-49de-ab79-8b19978f1893/2.png
所以,要想盡可能恢復數據,t 值就要盡可能小,t 越小,就越像“連拍”。那么,t 值可以小到什么程度呢,比如說是不是可以每秒做一次快照?畢竟,每次快照都是由 bgsave 子進程在后臺執行,也不會阻塞主線程。
這種想法其實是錯誤的。雖然 bgsave 執行時不阻塞主線程,但是,如果頻繁地執行全量快照,也會帶來兩方面的開銷。
一方面,頻繁將全量數據寫入磁盤,會給磁盤帶來很大壓力,多個快照競爭有限的磁盤帶寬,前一個快照還沒有做完,后一個又開始做了,容易造成惡性循環。
另一方面,bgsave 子進程需要通過 fork 操作從主線程創建出來。雖然,子進程在創建后不會再阻塞主線程,但是,fork 這個創建過程本身會阻塞主線程,而且主線程的內存越大,阻塞時間越長。如果頻繁 fork 出 bgsave 子進程,這就會頻繁阻塞主線程了(所以,在 Redis 中如果有一個 bgsave 在運行,就不會再啟動第二個 bgsave 子進程)。那么,有什么其他好方法嗎?
此時,我們可以做增量快照,所謂增量快照,就是指,做了一次全量快照后,后續的快照只對修改的數據進行快照記錄,這樣可以避免每次全量快照的開銷。
在第一次做完全量快照后,T1 和 T2 時刻如果再做快照,我們只需要將被修改的數據寫入快照文件就行。但是,這么做的前提是,我們需要記住哪些數據被修改了。你可不要小瞧這個“記住”功能,它需要我們使用額外的元數據信息去記錄哪些數據被修改了,這會帶來額外的空間開銷問題。如下圖所示:
!https://s3-us-west-2.amazonaws.com/secure.notion-static.com/bdcdc43e-fc85-471e-ac3e-5b096e46d3db/3.png
如果我們對每一個鍵值對的修改,都做個記錄,那么,如果有 1 萬個被修改的鍵值對,我們就需要有 1 萬條額外的記錄。而且,有的時候,鍵值對非常小,比如只有 32 字節,而記錄它被修改的元數據信息,可能就需要 8 字節,這樣的畫,為了“記住”修改,引入的額外空間開銷比較大。這對于內存資源寶貴的 Redis 來說,有些得不償失。
到這里,你可以發現,雖然跟 AOF 相比,快照的恢復速度快,但是,快照的頻率不好把握,如果頻率太低,兩次快照間一旦宕機,就可能有比較多的數據丟失。如果頻率太高,又會產生額外開銷,那么,還有什么方法既能利用 RDB 的快速恢復,又能以較小的開銷做到盡量少丟數據呢?
Redis 4.0 中提出了一個混合使用 AOF 日志和內存快照的方法。簡單來說,內存快照以一定的頻率執行,在兩次快照之間,使用 AOF 日志記錄這期間的所有命令操作。
這樣一來,快照不用很頻繁地執行,這就避免了頻繁 fork 對主線程的影響。而且,AOF 日志也只用記錄兩次快照間的操作,也就是說,不需要記錄所有操作了,因此,就不會出現文件過大的情況了,也可以避免重寫開銷。
如下圖所示,T1 和 T2 時刻的修改,用 AOF 日志記錄,等到第二次做全量快照時,就可以清空 AOF 日志,因為此時的修改都已經記錄到快照中了,恢復時就不再用日志了。
!https://s3-us-west-2.amazonaws.com/secure.notion-static.com/5cff1961-2b48-4d69-9c9d-ad940c847a32/4.png
這個方法既能享受到 RDB 文件快速恢復的好處,又能享受到 AOF 只記錄操作命令的簡單優勢,頗有點“魚和熊掌可以兼得”的感覺,建議你在實踐中用起來。

小結

這節課,我們學習了 Redis 用于避免數據丟失的內存快照方法。這個方法的優勢在于,可以快速恢復數據庫,也就是只需要把 RDB 文件直接讀入內存,這就避免了 AOF 需要順序、逐一重新執行操作命令帶來的低效性能問題。
不過,內存快照也有它的局限性。它拍的是一張內存的“大合影”,不可避免地會耗時耗力。雖然,Redis 設計了 bgsave 和寫時復制方式,盡可能減少了內存快照對正常讀寫的影響,但是,頻繁快照仍然是不太能接受的。而混合使用 RDB 和 AOF,正好可以取兩者之長,避兩者之短,以較小的性能開銷保證數據可靠性和性能。
最后,關于 AOF 和 RDB 的選擇問題,我想再給你提三點建議:
數據不能丟失時,內存快照和 AOF 的混合使用是一個很好的選擇;
如果允許分鐘級別的數據丟失,可以只使用 RDB;
如果只用 AOF,優先使用 everysec 的配置選項,因為它在可靠性和性能之間取了一個平衡。

每課一問

我曾碰到過這么一個場景:我們使用一個 2 核 CPU、4GB 內存、500GB 磁盤的云主機運行 Redis,Redis 數據庫的數據量大小差不多是 2GB,我們使用了 RDB 做持久化保證。當時 Redis 的運行負載以修改操作為主,寫讀比例差不多在 8:2 左右,也就是說,如果有 100 個請求,80 個請求執行的是修改操作。你覺得,在這個場景下,用 RDB 做持久化有什么風險嗎?你能幫著一起分析分析嗎?
到這里,關于持久化我們就講完了,這塊兒內容是熟練掌握 Redis 的基礎,建議你一定好好學習下這兩節課。如果你覺得有收獲,希望你能幫我分享給更多的人,幫助更多人解決持久化的問題。
到這里,關于持久化我們就講完了,這塊兒內容是熟練掌握 Redis 的基礎,建議你一定好好學習下這兩節課。如果你覺得有收獲,希望你能幫我分享給更多的人,幫助更多人解決持久化的問題。

若有錯誤與不足請指出,關注DPT一起進步吧!!!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/66152.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/66152.shtml
英文地址,請注明出處:http://en.pswp.cn/web/66152.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

系統架構設計師考點—項目管理

一、備考指南 項目管理主要考查的是進度管理、軟件配置管理、質量管理、風險管理等相關知識,近幾年都沒有考查過,但是有可能在案例分析中考查關鍵路徑的技術問題,考生了解為主。 二、重點考點 1、項目的十大管理(速記&#xff1…

iOS - Objective-C 底層實現中的哈希表

1. 關聯對象存儲&#xff08;AssociationsHashMap&#xff09; // 關聯對象的哈希表實現 typedef DenseMap<const void *, ObjcAssociation> ObjectAssociationMap; typedef DenseMap<DisguisedPtr<objc_object>, ObjectAssociationMap> AssociationsHashMa…

兩分鐘解決 :![rejected] master -> master (fetch first) , 無法正常push到遠端庫

目錄 分析問題的原因解決 分析問題的原因 在git push的時候莫名遇到這種情況 若你在git上修改了如README.md的文件。由于本地是沒有README.md文件的&#xff0c;所以導致 遠端倉庫git和本地不同步。 將遠端、本地進行合并就可以很好的解決這個問題 注意&#xff1a;直接git pu…

Ubuntu Server 24.04 配置靜態IP

Ubuntu Server 24.04 配置靜態IP 提示&#xff1a;基于Ubuntu Server 24.04進行配置 文章目錄 Ubuntu Server 24.04 配置靜態IP一、查看網卡信息二、修改網卡信息三、使網卡配置生效四、測試 一、查看網卡信息 使用命令 ip a lo 為本地回環地址 ens33 真實網卡地址 shanfengubu…

微服務之松耦合

參考&#xff1a;https://microservices.io/post/architecture/2023/03/28/microservice-architecture-essentials-loose-coupling.html There’s actually two different types of coupling: runtime coupling - influences availability design-time coupling - influences…

Django 和 Vue3 前后端分離開發筆記

Django 和 Vue3 前后端分離開發筆記 1. Django Ninja API Django Ninja 是一個用于使用 Django 和 Python 3.6 類型提示構建 API 的網絡框架。它具有以下主要特點&#xff1a; 簡單易懂&#xff1a;設計為易于使用和符合直覺&#xff0c;適合快速上手。快速執行&#xff1a;…

44_Lua迭代器

在Lua中,迭代器是一種用于遍歷集合元素的重要工具。掌握迭代器的使用方法,對于提高Lua編程的效率和代碼的可讀性具有重要意義。 1.迭代器概述 1.1 迭代器介紹 迭代器是一種設計模式,它提供了一種訪問集合元素的方法,而不需要暴露其底層結構。在Lua中,迭代器通常以一個函…

hot100_240. 搜索二維矩陣 II

hot100_240. 搜索二維矩陣 II 直接遍歷列減行增 編寫一個高效的算法來搜索 m x n 矩陣 matrix 中的一個目標值 target 。該矩陣具有以下特性&#xff1a; 每行的元素從左到右升序排列。 每列的元素從上到下升序排列。 示例 1&#xff1a; 輸入&#xff1a;matrix [[1,4,7,1…

一步到位Python Django部署,淺談Python Django框架

Django是一個使用Python開發的Web應用程序框架&#xff0c;它遵循MVC&#xff08;Model-View-Controller&#xff09;設計模式&#xff0c;旨在幫助開發人員更快、更輕松地構建和維護高質量的Web應用程序。Django提供了強大的基礎設施和工具&#xff0c;以便于處理復雜的業務邏…

Apache PAIMON 學習

參考&#xff1a;Apache PAIMON&#xff1a;實時數據湖技術框架及其實踐 數據湖不僅僅是一個存儲不同類數據的技術手段&#xff0c;更是提高數據分析效率、支持數據驅動決策、加速AI發展的基礎設施。 新一代實時數據湖技術&#xff0c;Apache PAIMON兼容Apache Flink、Spark等…

《計算機網絡》課后探研題書面報告_了解PPPoE協議

PPPoE協議的工作原理與應用分析 摘 要 PPPoE&#xff08;Point-to-Point Protocol over Ethernet&#xff09;是一種廣泛應用于寬帶接入的網絡協議&#xff0c;特別是在DSL&#xff08;數字用戶線路&#xff09;和光纖網絡中具有重要的應用價值。PPPoE結合了PPP協議的認證、加…

【MySQL學習筆記】MySQL存儲過程

存儲過程 1、基礎語法2、變量2.1 系統變量2.2 用戶自定義變量2.3 局部變量 3、if 流程控制4、參數5、case 流程控制6、循環結構6.1 while 循環6.2 repeat 循環6.3 loop 循環 7、游標8、存儲函數 存儲過程是事先經過編譯并存儲在數據庫中的一段 SQL 語句的集合&#xff0c;調用存…

MAC上安裝Octave

1. 當前最新版Octave是9.3版本&#xff0c;需要把mac os系統升級到14版本&#xff08;本人之前的版本是10版本&#xff09; https://wiki.octave.org/Octave_for_macOS octave的歷史版本參考此文檔&#xff1a;Octave for macOS (outdated) - Octavehttps://wiki.octave.org/Oc…

mysql-5.7.18保姆級詳細安裝教程

本文主要講解如何安裝mysql-5.7.18數據庫&#xff1a; 將綠色版安裝包mysql-5.7.18-winx64解壓后目錄中內容如下圖&#xff0c;該例是安裝在D盤根目錄。 在mysql安裝目錄中新建my.ini文件&#xff0c;文件內容及各配置項內容如下圖&#xff0c;需要先將配置項【skip-grant-tab…

VSCode連接Github的重重困難及解決方案!

一、背景&#xff1a; 我首先在github創建了一個新的項目&#xff0c;并自動創建了readme文件其次在vscode創建項目并寫了兩個文件在我想將vscode的項目上傳到對應的github上時&#xff0c;錯誤出現了 二、報錯及解決方案&#xff1a; 1.解決方案&#xff1a; 需要在git上配置用…

YOLOV8漲點技巧之混合注意力與特征金字塔網絡融合

YOLO發展歷程 自2015年YOLOv1問世以來,這一革命性的目標檢測算法經歷了一系列重大升級。以下是YOLO各版本的主要發展里程碑: 版本 發布時間 主要開發者 YOLOv1 2015年6月 Joseph Redmon YOLOv2(YOLO9000) 2016年12月 Joseph Redmon YOLOv3 2018年4月 Joseph Redmon

數據分析:非度量多維排列 NMDS (Non-metric multidimensional scaling)ANOSIM檢驗分析

禁止商業或二改轉載,僅供自學使用,侵權必究,如需截取部分內容請后臺聯系作者! 文章目錄 介紹原理步驟加載R包數據下載導入數據數據預處理計算距離矩陣ANOSIM檢驗非度量多維排列NMDS應力值(stress value)畫圖輸出系統信息介紹 非度量多維排列(Non-metric Multidimensiona…

Open FPV VTX開源之ardupilot配置

Open FPV VTX開源之ardupilot配置 1. 源由2. 配置3. 總結4. 參考資料5. 補充5.1 飛控固件版本5.2 配置Ardupilot的BF OSD5.3 OSD偏左問題 1. 源由 飛控嵌入式OSD - ardupilot配置使用ardupliot配套OSD圖片。 Choose correct font depending on Flight Controller SW. ──>…

硬件實用技巧:TPS54331DR橫杠標識識別1引腳

若該文為原創文章&#xff0c;轉載請注明原文出處 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/145116969 長沙紅胖子Qt&#xff08;長沙創微智科&#xff09;博文大全&#xff1a;開發技術集合&#xff08;包含Qt實用技術、樹莓派、三維、OpenCV…

Python庫之PyAutoGUI安裝以及使用方法

Date: 2025.01.15 20:54:01 author: lijianzhan PyAutoGUI是一個功能強大的Python庫&#xff0c;它允許我們用于通過編程控制鼠標和鍵盤&#xff0c;實現自動化任務。它可以模擬用戶的輸入操作&#xff0c;例如點擊、拖動、輸入文本等&#xff0c;適用于 GUI 自動化、測試腳本、…