聊一聊Redis是如何作到「持久化」的

 什麼是持久化?

對於持久化某度某科的解釋是:程序員

持久化是將程序數據在持久狀態和瞬時狀態間轉換的機制。通俗的講,就是瞬時數據(好比內存中的數據,是不能永久保存的)持久化爲持久數據(好比持久化至數據庫中,可以長久保存)面試

因此對於持久化狹義的理解就是: 「持久化」僅僅指把域對象永久保存到數據庫中;能夠廣義的理解爲:「持久化」包括和數據庫相關的各類操做(持久化就是將有用的數據以某種技術保存起來,未來能夠再次取出來應用,數據庫技術,將內存數據一文件的形式保存在永久介質中(磁盤等)都是持久化的例子)。redis

數據持久化對象的基本操做有:保存、更新、刪除、加載、查詢等。數據庫

保存:把域對象永久保存到數據庫。緩存

更新:更新數據庫中域對象的狀態。安全

刪除:從數據庫中刪除一個域對象。服務器

加載:根據特定的OID,把一個域對象從數據庫加載到內存。併發

查詢:根據特定的查詢條件,把符合查詢條件的一個或多個域對象從數據庫加載內在存中。app

爲何須要持久化

經過前面的介紹咱們知道Redis的數據所有在內存裏,因此萬一出現忽然出現故障發生宕機,那麼保存在內存中的數據就會所有丟失,所以必須有一種機制來保證Redis的數據不會由於故障而丟失,這種機制就是Redis的持久化機制。異步

除此以外使用數據持久化還有如下好處:

一、持久化技術封裝了數據訪問細節,爲大部分業務邏輯提供面向對象的API。

二、程序代碼重用性強,即便更換數據庫,只須要更改配置文件,沒必要重寫程序代碼。

三、業務邏輯代碼可讀性強,在代碼中不會有大量的SQL語言,提升程序的可讀性。

四、持久化技術能夠自動優化,以減小對數據庫的訪問量,提升程序運行效率。

五、鬆散耦合,使持久化不依賴於底層數據庫和上層業務邏輯實現,更換數據庫時只需修改配置文件而不用修改代碼。

如何持久化

對於數據的持久化主要有如下的五個過程:

一、客戶端向服務端發送寫操做(數據在客戶端的內存中)。

二、數據庫服務端接收到寫請求的數據(數據在服務端的內存中)。

三、服務端調用write這個系統調用,將數據往磁盤上寫(數據在系統內存的緩衝區中)。

四、操做系統將緩衝區中的數據轉移到磁盤控制器上(數據在磁盤緩存中)。

五、磁盤控制器將數據寫到磁盤的物理介質中(數據真正落到磁盤上)。

這5個過程是在理想條件下一個正常的保存流程,可是在大多數狀況下,咱們的機器等等都會有各類各樣的故障,這裏劃分了兩種狀況:

(1)Redis數據庫發生故障,只要在上面的第三步執行完畢,那麼就能夠持久化保存,剩下的兩步由操做系統替咱們完成。

(2)操做系統發生故障,必須上面5步都完成才能夠。

在這裏只考慮了保存的過程可能發生的故障,其實保存的數據也有可能發生損壞,須要必定的恢復機制,篇幅有限這裏不進行展開。

Redis對於數據的持久化一樣須要經過以上五個步驟,在Redis4.x中對於數據的持久化方案主要有三種策略機制:

一、RDB(Redis DataBase)

二、AOF(Append Only File)

三、混合型方案

RDB機制

RDB機制是Redis裏面默認提供的一套持久化技術方案,專門用於保證內存中的數據被寫入到磁盤裏面去,是指在指定的時間間隔內將內存中的數據集快照寫入磁盤。快照是數據存儲的某一時刻的狀態記錄,能夠理解爲把當前時刻的數據保存下來,因爲是某一時刻的快照,那麼快照中的值要早於或者等於內存中的值。這種方式是經過修改相應的redis.conf來實現的,默認的文件名爲dump.rdb。在咱們安裝了redis以後,全部的配置都是在redis.conf文件中,裏面保存了RDB和AOF兩種持久化機制的各類配置。

好比:

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

redis.config中的語句主要是用於將數據持久化在redis的dump.rdb文件裏面,而後每一次開啓redis的時候都會將裏面的數據從新加載,進行數據恢復。dump.rdb的存放位置由下邊的dir來標識。

前面說了RDB機制是經過把某個時刻的全部數據生成一個快照來保存,既然是快照那麼就應該有一種觸發機制,來觸發快照的功能。對於RDB來講,提供了三種機制來觸發快照,分別是:save、bgsave、自動觸發機制。

rdb裏面並非單純將數據直接存儲起來,而是經過一種特定的lzf壓縮方式來實現的:

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

這個配置開關最好打開,默認是開啓的,不然會致使rdb文件過大,佔用磁盤空間。

觸發rdb存儲機制的條件有兩種:

一、手動觸發:

一、執行save指令:這是一種阻塞式指令,阻塞當前redis服務器,直RDB過程完成爲止。若是內存比較大會形成redis長時間阻塞,因此線上禁止使用。具體流程能夠總結以下:

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

二、執行bgsave命令:執行該命令時,Redis會在後臺異步進行快照操做,快照同時還能夠響應客戶端請求。具體操做是redis進程執行fork操做建立子進程,RDB持久化過程由子進程負責,完成後自動結束。阻塞只發生在fork階段,時間通常很短,具體和實例數據大小有關係。具體流程能夠總結以下:

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

二、自動觸發:

除了執行上面的兩種命令手動觸發以外,redis還存在如下4種方式自動觸發RDB的持久化機制。

一、使用save相關配置,如「save m n」 表示m秒內數據集存在n次修改時,自動觸發bgsave。也能夠同時配置多個條件,只要其中一個達標就觸發。

config文件中save機制的配置以下:

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

save <指定時間間隔> <執行指定次數更新操做> (默認是save 900 1)

能夠理解爲指定的秒內若是進行了指定次數的更新操做,就會將數據存儲到dump.rdb文件中去。

二、主從複製時,從節點執行全量複製操做,主節點自動執行bgsave生成RDB文件併發送給從節點;

三、執行debug reload命令時從新加載redis

四、默認狀況下執行shutdown命令時,若是沒有開啓aof持久化則自動執行bgsave

每項技術都會有必定的優勢和缺點,RDB的優缺點能夠總結以下:

優勢:

一、RDB適合大規模的數據恢復。

二、RDB是一個緊湊壓縮的二進制文件,佔用的內存比較小,表明數據在某一個時間點的快照。很是適合備份,全景複製。好比每三個小時執行bgsave備份,並把RDB文件上傳到備份服務器中,用於防止Redis服務器不可恢復性問題。

三、RDB恢復數據速度快於AOF的方式。

四、RDB 能夠最大化 redis 的性能。父進程在保存 RDB 文件時惟一要作的就是 fork 出一個子進程,而後這個子進程就會處理接下來的全部保存工做,父進程無須執行任何磁盤 I/O 操做。

五、RDB 很是適用於災難恢復(disaster recovery),由於它只有一個文件,而且內容都很是緊湊,能夠(在加密後)將它傳送到別的數據中心。

缺點:

一、RDB 在服務器故障時容易形成數據的丟失。RDB容許經過修改配置來控制持久化的頻率。可是,由於RDB文件須要保存整個數據集的狀態,因此它是一個比較繁重的操做,若是頻率太頻繁,會對Redis性能產生必定的影響。因此通常能夠設置至少5分鐘才保存一次快照,這時若是 Redis 出現宕機等狀況,也就意味着最多可能丟失5分鐘數據。因此數據的完整性和一致性不高。

二、備份時會佔用內存。由於Redis 在備份時會獨立建立一個子進程而且採用的是 copy-on-write 的方式,在 Redis 執行 RDB 持久化期間,若是 client 寫入數據很頻繁,那麼將增長 Redis 佔用的內存,最壞狀況下,內存的佔用將達到原先的2倍。剛 fork 時,主進程和子進程共享內存,可是隨着主進程須要處理寫操做,主進程須要將修改的頁面拷貝一份出來,而後進行修改。極端狀況下,若是全部的頁面都被修改,則此時的內存佔用是原先的2倍。

三、若是數據比較大時,備份的時候會比較耗時RDB 保存時使用 fork 子進程進行數據的持久化時,若是數據比較大的話,fork 可能會很是耗時,形成 Redis 中止處理服務N毫秒。若是數據集很大且 CPU 比較繁忙的時候,中止服務的時間甚至會到一秒。

四、同上由於bgsave每次運行都要執行fork操做建立子進程,屬於重量級操做,頻繁執行成本太高,因此RDB方式數據沒辦法作到實時持久化/秒級持久化。

五、由於RDB文件使用特定二進制格式保存,Redis版本演進過程當中有多個格式的RDB版本,因此存在老版本Redis服務沒法兼容新版RDB格式的問題。

AOF機制

前面說了雖然RDB可以做爲redis的持久化進行數據的備份,可是也存在一些不足。因此爲了彌補RDB的缺點,aof機制應勢而出。aof的全稱是append only file,它是以獨立日誌的形式來將每一次寫操做都進行記錄,追加到相應的文件中去。Redis重啓的時候會根據日誌文件的內容從前到後執行一次達到數據恢復的目的。前面說到RDB有個缺點就是數據備份的實時性比較低,因此AOF的主要做用是解決了數據持久化的實時性,目前AOF已是Redis持久化的主流。

在conf文件中一樣有對於aof的配置:

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

appendonly:默認值爲no,由於r前面說過Redis 默認使用的是rdbd的持久化方式,若是想要開啓 AOF 持久化方式,須要將 appendonly 修改成 yes。

appendfilename :指的是aof文件名,默認是"appendonly.aof"

appendfsync:aof持久化策略的配置,可取的值有三種:always、everysec和no。

設置爲always時,會極大消弱Redis的性能,由於這種模式下每次write後都會調用fsync立馬將數據寫入磁盤進行持久化(Linux爲調用fdatasync)。雖然性能差,可是安全性是最高的。

設置爲no時,則write後不會有fsync調用,由操做系統自動調度刷磁盤,直接寫入aof的內存緩衝區,性能是最好的。

設置爲everysec時,最多每秒調用一次fsync,這種模式性能並非很糟糕,通常也不會產生毛刺,這歸功於Redis引入了BIO線程,全部fsync操做都異步交給了BIO線程。這也是推薦的策略模式,就如同配置說明上說的:If unsure, use "everysec"(若是不肯定就是使用everysec)。

它們三個能夠總結爲:

策略 寫回時機 優勢 缺點
Always 同步寫回 數據基本不會丟失,可靠性好 每一個命令都要寫入磁盤,性能較差
No 系統控制 性能好 安全性差,宕機時丟失數據較多
Everysec 每秒寫回 性能中等 宕機時丟失一秒內的數據

AOF裏觸發該機制的條件能夠在conf文件裏面進行配置:

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

當AOF文件的大小超過所設定的閾值時,Redis就會啓動AOF文件的內容壓縮,只保留能夠恢復數據的最小指令集。

配置參數:

auto-aof-rewrite-min-size 64mb 

表示aof文件要達到必定體積纔會進行重寫

auto-aof-rewrite-percentage 100 

表示當aof文件大小增加了100%纔會觸發重寫

重寫的原理

aof在進行重寫處理的時候,會額外開闢一個bgrewriteaof線程,將原先的aof文件數據拷貝到一個臨時文件進行處理,最後再覆蓋原先文件。AOF文件重寫過程與RDB快照bgsave工做過程有點類似,都是經過fork子進程,由子進程完成相應的操做,一樣的在fork子進程簡短的時間內,redis是阻塞的。具體過程以下圖所示:

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

相比於rdb而言,aof的數據備份效率更高,可是在數據恢復的時候其性能卻遠遠不如rdb高效。

混合型策略

重啓 Redis 時,若是採用rdb來恢復內存狀態,會丟失大量數據。

若是使用 aof,性能相對rdb來講要慢不少,這樣在Redis數據很大的狀況下,啓動的時候時間消耗比較大。

混合型策略是Redis4.0開始添加的新的混合型持久化方案。混合型方案就是將前面的RDB持久化方案以及AOF持久化方案結合。

混合持久化一樣也是經過bgrewriteaof完成的,不一樣的是當開啓混合持久化時,fork出的子進程先將共享的內存副本全量的以RDB方式寫入aof文件,而後在將aof_rewrite_buf重寫緩衝區的增量命令以AOF方式寫入到文件,寫入完成後通知主進程更新統計信息,並將新的含有RDB格式和AOF格式的AOF文件替換舊的的AOF文件。能夠簡單的理解爲:新的AOF文件前半段是RDB格式的全量數據後半段是AOF格式的增量數據,能夠理解爲:

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

這樣作的好處是能夠結合 rdb 和 aof 的優勢, 快速加載同時避免丟失過多的數據,而缺點是 aof 裏面的 rdb 部分就是壓縮格式再也不是 aof 格式,可讀性差。

混合持久化默認關閉的,能夠經過aof-use-rdb-preamble配置參數控制,yes則表示開啓,no表示禁用,默認是禁用的。

aof-use-rdb-preamble yes  # yes:開啓,no:關閉

若是開啓了混合策略,那麼在啓動redis時依然優先加載aof文件進行數據恢復,而aof文件加載可能有兩種狀況以下:

一、若是aof文件開頭是rdb的格式, 先加載 rdb內容再加載剩餘的 aof。

二、若是aof文件開頭不是rdb的格式,直接以aof格式加載整個文件。

雖然混合策略是rdb和aof結合的,可是它有優勢一樣也還有必定的缺點:

優勢:

混合持久化結合了RDB持久化 和 AOF 持久化的優勢, 因爲絕大部分都是RDB格式,加載速度快,同時結合AOF,增量的數據以AOF方式保存了,數據更少的丟失。

缺點:

兼容性差,一旦開啓了混合持久化,在4.0以前版本都不識別該aof文件。

同時因爲前部分是RDB格式,閱讀性較差。

總結

以上主要介紹了redis對數據進行持久化的三種策略,分別是:RDB、AOF以及基於其兩種方案的混合型持久策略。這三種策略都有本身的優勢和缺點,實際使用中能夠根據實際的場景和需求進行合理的選擇。

最後

最近我整理了整套《JAVA核心知識點總結》,說實話 ,做爲一名Java程序員,不論你需不須要面試都應該好好看下這份資料。拿到手老是不虧的~個人很多粉絲也所以拿到騰訊字節快手等公司的Offer

Java進階之路羣,找管理員獲取哦-!

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

相關文章
相關標籤/搜索