redis持久化

內存(兔子):高效、斷電數據就會消失

硬盤(烏龜):讀寫速度慢於內存的,斷電數據依舊存在

 redis是內存數據庫,它把數據存儲在內存中,這樣在加快讀取速度的同時也對數據安全性產生了新的問題,即當redis所在服務器發生宕機後,redis數據庫裏的所有數據將會全部丟失。
 爲了解決這個問題,redis提供了持久化功能——RDB和AOF。通俗的講就是將內存中的數據寫入硬盤中。

 即:redis持久化    --->    把數據保存在硬盤上



關係型數據庫MySQL-持久化:

  任何增刪改語句,都是在硬盤上做的操作

  斷電以後,硬盤上的數據還是存在。

 

非關係型數據庫redis:

  默認情況下,所有的增刪改,數據都是在內存中進行操作。

  斷電以後,內存中的數據不存在的。

  斷電以後,redis的部分數據會丟失,丟失的數據是保存在內存中的數據。


Redis有兩種持久化策略:

  1. RDB (Redis DataBase)
  2. AOF (Append Only File)

RDB相關知識

  1. RDB是在指定的時間間隔內將內存中的數據集快照寫入磁盤, 也就是行話將的Snapshot快照, 它恢復時是將快照文件直接讀到內存裏。
  2. Redis會單獨創(fork)一個子進程進行持久化, 會先將數據寫入到一個臨時文件中, 待持久化過程結束了, 再用這個臨時文件替換上次持久化好的文件。整個過程中, 主進程是不進行任何IO操作的, 這就確保了極高的性能如果需要進行大規模數據的恢復, 且對於數據恢復的完整性不是非常敏感, 那RDB方式要比AOF方式更加高效 RDB的缺點是最後一次持久化後的數據可能丟失。
  3. 保存的是dump.rdb文件, 在redis.conf中有一個SNAPSHOTTING行列塊中的save可進行配置,save seconds changes 表示在指定時間內修改次數達到多少save一次,save “”爲不備份。如果某數據非常重要, 需要備份但沒有達到修改次數保存的條件, 那麼直接使用save命令進行保存。
  4. 優勢:適合大規模的數據恢復, 對數據完整性和一致性要求不高。
  5. 劣勢:在一定間隔時間做一次備份,如果在redis意外宕機,就會丟失最後一次快照後的所有修改;Fork的時候,內存中的數據被克隆了一份,大致兩倍的膨脹性需要考慮
  6. 如何停止:動態停止所有RDB保存規則的方法:redis-cli config set save “”

那麼問題來了!
RDB可以成功恢復數據,爲什麼還會出現AOF?引用德國哲學家黑格爾一句名言吧——凡是存在即是合理的。它的存在肯定是爲了彌補老技術(RDB)的不足。

AOF相關知識

  1. AOF是以日誌的形式來記錄每個寫操作,將Redis執行過的所有寫指令記錄下來(讀操作不記錄),只許追加文件但不可以改寫文件,redis啓動之初會讀取該文件重新構建數據,也就是說redis重啓的話就根據日誌文件的內容將寫指令從前到後執行一次以完成數據的恢復工作,在redis.conf配置文件中的APPEND ONLY MODE列塊中可配置。

  2. aof文件與rdb文件共存,redis啓動加載的是aof文件,redis.conf配置文件裏也有說明
    # AOF and RDB persistence can be enabled at the same time without problems.
    If the AOF is enabled on startup Redis will load the AOF, that is the file
    with the better durability guarantees.

  3. AOF啓動/修復/恢復:①正常恢復:I、啓動:設置成YES(修改默認配置appendonly no改成appendonly yes)。II、將有數據的aof文件複製一份備份保存到相應目錄(可通過redis-cli客戶端使用命令config get dir查看)。III、恢復:重啓redis然後重新加載。②異常恢復:I、啓動:設置YES。II、備份被寫壞的AOF文件。III、修復: 使用redis-check-aof –fix [需要被修復的aof文件的全路徑]進行修復。IV、恢復:重啓redis然後重新加載。

  4. Rewrite重寫:①、是什麼? AOF採用文件追加方式導致文件會越來越大。爲避免此種情況,新增了重寫機制,當AOF文件的大小超過所設定的閾值時,Redis就會啓動AOF文件的內容壓縮,只保留可以恢復數據的最小指令集,可以使用命令bgrewriteaof。②、重寫原理:AOF文件持續 增長而過大時,會fork出一條新進程來將文件重寫(也是先寫臨時文件最後再rename),遍歷新進程的內存中數據,每條記錄有一條set語句。重寫aof文件的操作,並沒有讀取舊的aof文件,而是將整個內存中的數據庫內容用命令的方式重寫了一個新的aof文件,這點和快照有點類似。III、觸發機制:Redis會記錄上次重寫時的AOF大小,默認配置是當AOF文件大小是上次rewrite後大小的一倍且文件大於64MB時觸發(該數值可在redis.conf配置文件中找到,該數值需按實際生產上所需配置)。

  5. ①優勢:I、每秒同步: appendfsync always 同步持久化 每秒發生數據變更會被立即記錄到磁盤,性能較差但數據完整性較好。II、每修改同步:appendfsync everysec 異步操作,每秒記錄 如果一秒內宕機,有數據丟失。III、不同步:appendfsync no 從不同步。②、劣勢:針對數據而言aof文件要遠大於rdb文件,恢復速度慢於rdb。II、Aof運行效率要慢於rdb,每秒同步策略效率較好,不同步效率和rdb相同。
    簡單小總結一下AOF,見下圖
    簡單AOF總結圖

    總結一下RDB和AOF
    ①、 如果非常在意數據,又希望快速的恢復數據,可以簡單的使用RDB。
    ②、RDB持久化方式能夠在指定的時間間隔內對你的數據進行快照存儲。
    ③、AOF持久化方式記錄每次對服務器寫的操作,當服務器重啓的時候回重新執行這些命令來恢復原始的數據,AOF命令以redis協議追加保存每次寫的操作到文件末尾。Redis還能對AOF文件進行後臺重寫,使得AOF文件的體積不至於過大。
    ④、只做緩存:如果只希望你的數據在服務器運行的時候存在,你也可以不適用任何持久化方式。
    ⑤、同時開啓兩種持久化方式:I、同時開啓優先載入AOF文件來恢復原始的數據,因爲通常情況下AOF文件保存的數據集要比RDB文件保存的數據集要完整。II、RDB的數據不實時,同時使用兩者時服務器重啓也只會找AOF文件。那要不要只使用AOF呢?建議不要,因爲RDB更適合用於備份數據庫(AOF在不斷變化不好備份),快速重啓,而且不會有AOF可能潛在的bug,留着作爲一個萬一的手段。

     一、持久化之全量寫入:RDB

[redis@6381]$ more /usr/local/redis/conf/redis.conf 
save 900 1
save 300 10
save 60 10000
dbfilename "dump.rdb"          #持久化文件名稱
dir "/data/dbs/redis/6381"    #持久化數據文件存放的路徑

上面是redis配置文件裏默認的RDB持久化設置,前三行都是對觸發RDB的一個條件,例如第一行的意思是每900秒鐘裏redis數據庫有一條數據被修改則觸發RDB,依次類推;只要有一條滿足就會調用BGSAVE進行RDB持久化。第四行dbfilename指定了把內存裏的數據庫寫入本地文件的名稱,該文件是進行壓縮後的二進制文件,通過該文件可以把數據庫還原到生成該文件時數據庫的狀態。第五行dir指定了RDB文件存放的目錄。

      配置文件修改需要重啓redis服務,我們還可以在命令行裏進行配置,即時生效,服務器重啓後需重新配置

[redis@iZ254r8s3m6Z redis]$ bin/redis-cli
127.0.0.1:6379> CONFIG GET save         #查看redis持久化配置
1) "save"
2) "900 1 300 10 60 10000"

127.0.0.1:6379> CONFIG SET save "21600 1000" #修改redis持久化配置
OK

      而RDB持久化也分兩種:SAVE和BGSAVE

      SAVE是阻塞式的RDB持久化,當執行這個命令時redis的主進程把內存裏的數據庫狀態寫入到RDB文件(即上面的dump.rdb)中,直到該文件創建完畢的這段時間內redis將不能處理任何命令請求。

      BGSAVE屬於非阻塞式的持久化,它會創建一個子進程專門去把內存中的數據庫狀態寫入RDB文件裏,同時主進程還可以處理來自客戶端的命令請求。但子進程基本是複製的父進程,這等於兩個相同大小的redis進程在系統上運行,會造成內存使用率的大幅增加。

(本人在生產中就碰到過這問題,redis本身內存使用率就60%,總的內存使用率在百分之七八十左右,持久化的時候立馬飆到百分之一百三十多,告警郵件是每天幾十封/(ㄒoㄒ)/~~ 最後根據需求選擇了AOF持久化)

 

       二、持久化之增量寫入:AOF

       與RDB的保存整個redis數據庫狀態不同,AOF是通過保存對redis服務端的寫命令(如set、sadd、rpush)來記錄數據庫狀態的,即保存你對redis數據庫的寫操作,以下就是AOF文件的內容

 [redis@iZ]$ more appendonly.aof 
 *2
 $6
 SELECT
 $1
 0
 *3
 $3
 SET
 $47
 DEV_USER_LEGAL_F9683BE0E27F1A06C0CB869CEC7E3B22
 $11
 ¬
 *3
 $3
 SET
 $47

       先讓我們看看如何配置AOF

 [redis@iZ]$ more ~/redis/conf/redis.conf
 dir "/data/dbs/redis/6381"           #AOF文件存放目錄
 appendonly yes                       #開啓AOF持久化,默認關閉
 appendfilename "appendonly.aof"      #AOF文件名稱(默認)
 appendfsync no                       #AOF持久化策略
 auto-aof-rewrite-percentage 100      #觸發AOF文件重寫的條件(默認)
 auto-aof-rewrite-min-size 64mb       #觸發AOF文件重寫的條件(默認)

      要弄明白上面幾個配置就得從AOF的實現去理解,AOF的持久化是通過命令追加、文件寫入和文件同步三個步驟實現的。當reids開啓AOF後,服務端每執行一次寫操作(如set、sadd、rpush)就會把該條命令追加到一個單獨的AOF緩衝區的末尾,這就是命令追加;然後把AOF緩衝區的內容寫入AOF文件裏。看上去第二步就已經完成AOF持久化了那第三步是幹什麼的呢?這就需要從系統的文件寫入機制說起:一般我們現在所使用的操作系統,爲了提高文件的寫入效率,都會有一個寫入策略,即當你往硬盤寫入數據時,操作系統不是實時的將數據寫入硬盤,而是先把數據暫時的保存在一個內存緩衝區裏,等到這個內存緩衝區的空間被填滿或者是超過了設定的時限後纔會真正的把緩衝區內的數據寫入硬盤中。也就是說當redis進行到第二步文件寫入的時候,從用戶的角度看是已經把AOF緩衝區裏的數據寫入到AOF文件了,但對系統而言只不過是把AOF緩衝區的內容放到了另一個內存緩衝區裏而已,之後redis還需要進行文件同步把該內存緩衝區裏的數據真正寫入硬盤上纔算是完成了一次持久化。而何時進行文件同步則是根據配置的appendfsync來進行:

      appendfsync有三個選項:always、everysec和no:

1、選擇always的時候服務器會在每執行一個事件就把AOF緩衝區的內容強制性的寫入硬盤上的AOF文件裏,可以看成你每執行一個redis寫入命令就往AOF文件裏記錄這條命令,這保證了數據持久化的完整性,但效率是最慢的,卻也是最安全的;

2、配置成everysec的話服務端每執行一次寫操作(如set、sadd、rpush)也會把該條命令追加到一個單獨的AOF緩衝區的末尾,並將AOF緩衝區寫入AOF文件,然後每隔一秒纔會進行一次文件同步把內存緩衝區裏的AOF緩存數據真正寫入AOF文件裏,這個模式兼顧了效率的同時也保證了數據的完整性,即使在服務器宕機也只會丟失一秒內對redis數據庫做的修改;

3、將appendfsync配置成no則意味redis數據庫裏的數據就算丟失你也可以接受,它也會把每條寫命令追加到AOF緩衝區的末尾,然後寫入文件,但什麼時候進行文件同步真正把數據寫入AOF文件裏則由系統自身決定,即當內存緩衝區的空間被填滿或者是超過了設定的時限後系統自動同步。這種模式下效率是最快的,但對數據來說也是最不安全的,如果redis裏的數據都是從後臺數據庫如mysql中取出來的,屬於隨時可以找回或者不重要的數據,那麼可以考慮設置成這種模式。

     

      相比RDB每次持久化都會內存翻倍,AOF持久化除了在第一次啓用時會新開一個子進程創建AOF文件會大幅度消耗內存外,之後的每次持久化對內存使用都很小。但AOF也有一個不可忽視的問題:AOF文件過大。你對redis數據庫的每一次寫操作都會讓AOF文件裏增加一條數據,久而久之這個文件會形成一個龐然大物。還好的是redis提出了AOF重寫的機制,即我們上面配置的auto-aof-rewrite-percentage和auto-aof-rewrite-min-size。AOF重寫機制這裏暫不細述,之後本人會另開博文對此解釋,有興趣的同學可以看看。我們只要知道AOF重寫既是重新創建一個精簡化的AOF文件,裏面去掉了多餘的冗餘命令,並對原AOF文件進行覆蓋。這保證了AOF文件大小處於讓人可以接受的地步。而上面的auto-aof-rewrite-percentage和auto-aof-rewrite-min-size配置觸發AOF重寫的條件。       

      Redis 會記錄上次重寫後AOF文件的文件大小,而當前AOF文件大小跟上次重寫後AOF文件大小的百分比超過auto-aof-rewrite-percentage設置的值,同時當前AOF文件大小也超過auto-aof-rewrite-min-size設置的最小值,則會觸發AOF文件重寫。以上面的配置爲例,當現在的AOF文件大於64mb同時也大於上次重寫AOF後的文件大小,則該文件就會被AOF重寫。

 

      最後需要注意的是,如果redis開啓了AOF持久化功能,那麼當redis服務重啓時會優先使用AOF文件來還原數據庫。








發佈了14 篇原創文章 · 獲贊 7 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章