程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> 第十章 Redis持久化--RDB+AOF,redis--rdb

第十章 Redis持久化--RDB+AOF,redis--rdb

編輯:JAVA綜合教程

第十章 Redis持久化--RDB+AOF,redis--rdb


注:本文主要參考自《Redis設計與實現》

1、Redis兩種持久化方式

  • RDB
    • 執行機制:快照,直接將databases中的key-value的二進制形式存儲在了rdb文件中
    • 優點:性能較高(因為是快照,且執行頻率比aof低,而且rdb文件中直接存儲的是key-values的二進制形式,對於恢復數據也快)
    • 缺點:在save配置條件之間若發生宕機,此間的數據會丟失
  • AOF
    • 執行機制:將對數據的每一條修改命令追加到aof文件
    • 優點:數據不容易丟失
    • 缺點:性能較低(每一條修改操作都要追加到aof文件,執行頻率較RDB要高,而且aof文件中存儲的是命令,對於恢復數據來講需要逐行執行命令,所以恢復慢)

 

2、RDB

實際中使用的配置(在redis.conf)

#發生以下三種的任何一種都會將數據庫的緩存內容寫入到rdb文件中去(寫入的方式是bgsave)
#若將下述的三條命令都注釋掉,則禁止使用rdb
save 900 1      #900s後至少有一個key發生了變化
save 300 10      #300s後至少有10個key發生了變化
save 60 10000    #60s後至少有10000個key發生了變化

#當後台RDB進程導出快照(一部分的key-value)到rdb文件這個過程出錯時(即最後一次的後台保存失敗時),
#redis主進程是否還接受向數據庫寫數據
#該種方式會讓用戶知道在數據持久化到硬盤時出錯了(相當於一種監控);
#如果安裝了很好的redis持久化監控,可設置為"no"
stop-writes-on-bgsave-error yes

#使用LZF壓縮字符串,然後寫到rdb文件中去
#如果希望RDB進程節省一點CPU時間,設置為no,但是可能最後的rdb文件會很大
rdbcompression yes

#在redis重啟後,從rdb文件向內存寫數據之前,是否先檢測該rdb文件是否損壞(根據rdb文件中的校驗和check_sum)
rdbchecksum yes

#設置rdb文件名
dbfilename dump.rdb

#設置rdb文件的存儲目錄
dir ./

說明

  • 具體每一項配置的詳細說明看注釋

注意

  • 對於save命令而言,配置了該命令,後台是以bgsave來執行的
    • bgsave:Redis主進程進行數據讀寫操作,RDB子進程進行數據的持久化操作,在進行持久化操作時,不阻塞主進程的讀寫操作
  • 以上三條save命令只要發生任一條,bgsave命令都會發生,這就有兩個問題,假設60s內有10000個key發生了改變(寫入、刪除、更新),那麼是否會立即進行持久化呢?在這次持久化之後,假設又過了240s,而在此期間沒有任何的key的改變操作,此時是否要發生一次持久化(因為滿足300s發生了10個key的改變,這裡是改變了10000個key)?
    • 不會立即進行持久化:redis默認每隔100ms使用serverCron函數檢查一次save配置的條件是否滿足,滿足則進行bgsave,這樣的話,如果在100ms內,我已經滿足了bgsave的條件,那麼我真正執行bgsave的時候也要等到serverCron執行過來的時候
    • 不會再發生持久化:redis有兩個參數dirty(記錄上一次bgsave之後的key的修改數,上邊的在240s內例子就是0)和lastsave(上一次成功執行bgsave命令的時間),配置中的每一個save配置的修改數指的就是dirty,而每一個時間段就是以lastsave為起點計算的。
  • 注釋掉所有的save命令,RDB將不起作用
  • rdbcompression yes:配置成這樣是不是每一個字符串在存儲到rdb文件中時,都要進行一次壓縮操作?
    • 不是:設置為yes之後,只有當字符串的長度大於等於21個字節時,才會進行壓縮
  • rdbchecksum yes:這個校驗和存儲在哪裡?為什麼通過比對校驗和可以判斷文件是否損壞?
    • 校驗和(check_sum)存儲在RDB文件的最後八個字節中(詳細的RDB文件結構,查看《Redis這基於實現》"第10章 RDB持久化"),簡單的RDB文件結構如下:
      • RDB文件開頭的前五個字節"REDIS"是判斷一個文件是不是RDB文件的標准(類似於class文件中的"魔數")
      • 接下來的4個字節:RDB文件版本號(db_version)
      • databases(注意是復數):這裡存放各個庫redisDb中存儲的key-value信息(是整個數據持久化和恢復的核心)
      • EOF(1個字節):RDB文件正文的結束
      • check_sum(8個字節):檢驗和,該值是根據前邊四部分值算出來的,在持久化的時候將該值算出來並寫入rdb文件的末尾;在根據rdb文件恢復數據的時候,再根據rdb文件中的前邊四部分值計算出一個校驗和,然後與當前rdb文件中的check_sum(即後八個字節)的內容進行比對,如果一樣,說明沒損壞,如果不一樣,說明前四部分有數據損壞(即該文件損壞)
  • 在Redis服務器啟動時,redis會自動檢測是否有rdb文件(前提是沒有aof的時候),如果有,則根據rdb文件恢復數據,此時在恢復數據完成之前,會阻塞客戶端對redis的讀寫操作

 

3、AOF

實際中使用的配置(在redis.conf)

# 是否打開aof日志功能(appendonly yes)
appendonly no

# aof文件的存放路徑與文件名稱
# appendfilename appendonly.aof

#每一個命令,都立即同步到aof文件中去(很安全,但是速度慢,因為每一個命令都會進行一次磁盤操作)
# appendfsync always
#每秒將數據寫一次到aof文件
appendfsync everysec
#將寫入工作交給操作系統,由操作系統來判斷緩沖區大小,統一寫到aof文件(速度快,但是同步頻率低,容易丟數據) 
# appendfsync no

# 在RDB持久化數據的時候,此時的aof操作是否停止,若為yes則停止
# 在停止的這段時間內,執行的命令會寫入內存隊列,等RDB持久化完成後,統一將這些命令寫入aof文件
# 該參數的配置是考慮到RDB持久化執行的頻率低,但是執行的時間長,而AOF執行的頻率高,執行的時間短,
# 若同時執行兩個子進程(RDB子進程、AOF子進程)效率會低(兩個子進程都是磁盤讀寫)
# 但是若改為yes可能造成的後果是,由於RDB持久化執行時間長,在這段時間內有很多命令寫入了內存隊列,
# 最後導致隊列放不下,這樣AOF寫入到AOF文件中的命令可能就少了很多
# 在恢復數據的時候,根據aof文件恢復就會丟很多數據
# 所以,選擇no就好
no-appendfsync-on-rewrite no

# AOF重寫:把內存中的數據逆化成命令,然後將這些命令重新寫入aof文件
# 重寫的目的:假設在我們在內存中對同一個key進行了100次操作,最後該key的value是100,
# 那麼在aof中就會存在100條命令日志,這樣的話,有兩個缺點:
# 1)AOF文件過大,占據硬盤空間 2)根據AOF文件恢復數據極慢(需要執行100條命令)
# 如果我們將內存中的該key逆化成"set key 100",然後寫入aof文件,
# 那麼aof文件的大小會大幅度減少,而且根據aof文件恢復數據很快(只需要執行1條命令)
# 注意:下邊兩個約束都要滿足的條件下,才會發生aof重寫;
# 假設沒有第二個,那麼在aof的前期,只要稍微添加一些數據,就發生aof重寫
# 當aof的增長的百分比是原來的100%(即是原來大小的2倍,例如原來是100m,下一次重寫是當aof文件是200m的時候),AOF重寫
auto-aof-rewrite-percentage 100  
auto-aof-rewrite-min-size 64mb   #AOF重寫僅發生在當aof文件大於64m時

說明:

  • 具體每一項配置的詳細說明看注釋

注意:

  • 每一個客戶端命令在執行時都會直接將命令寫入AOF緩沖區
    • appendfsync always:每一個命令進入緩沖區後,都會立即再從緩沖區追加到AOF文件中
    • appendfsync everysec:每一秒後將緩沖區中的所有命令追加到AOF文件中
    • appendfsync no:每一個命令進入緩沖區後,由操作系統來判斷什麼時候(主要是緩沖區快滿的時候)將緩沖區中的所有命令追加到AOF文件中
  • aof重寫需要滿足配置文件中的兩個條件
  • aof重寫采用後台子進程執行
    • aof的重寫會進行大量的寫入操作,如果用單線程來做這個事兒,就會長時間阻塞主進程(redis是單線程),這個時候客戶端的讀寫就會失效
    • 采用aof後台重寫進程造成的問題:
      • 如果在後台進程重寫期間,有新的命令對數據庫進行了讀寫,新的aof文件就與數據庫的存儲內容不同了。(注意:在後台進程重寫期間,對數據庫的讀寫操作還會進入aof緩沖區,還是會執行aof文件的命令寫入,但需要注意的是,雖然這個期間所有的命令還是寫入aof文件了,但是這個aof文件會被重寫後的新的aof文件所替換,新的aof文件可沒有這些命令,那麼如果在下次重寫發生之前發生宕機,采用aof恢復數據庫的時候,那就丟失了很多命令了)
      • 解決方案:設置一個aof重寫緩沖區,僅僅用於在後台進程重寫期間,將發生的數據庫讀寫命令寫入到重寫緩沖區中(當然,此時的服務器進程除了將發生的數據庫讀寫命令寫入到重寫緩沖區中,還會寫入到aof緩沖區,來保證正常的aof操作),之後當重寫子進程完成重寫後,向服務器主進程發送一個信號,此時服務器主進程將aof重寫緩沖區中的命令追加到新的aof文件中去,用新的aof文件替換掉舊的aof文件。
    • 注意:
      • 在後台進程重寫期間,將發生的數據庫讀寫命令寫入到重寫緩沖區中時,為什麼還要將這些命令寫入到aof緩沖區(因為這些命令會寫入舊的aof文件)?
        • 如果能百分之百保證在最後的主進程用新的aof文件替換了舊的aof文件(就是在這之前不宕機),那麼寫入到aof緩沖區沒用(因為會被覆蓋),但是如果在這之前宕機,那麼我們的aof文件還是舊的aof文件,這時候命令寫入到aof緩沖區就可以保證該aof文件盡可能多的保存命令,將來用於恢復數據庫最多丟失的也就是1s的數據。(appendfsync everysec)
      • 在"服務器主進程將aof重寫緩沖區中的命令追加到新的aof文件中去"這段操作期間,如果有新的客戶端讀寫命令,都將被阻塞(因為是主進程在做上述操作)。這也是整個aof重寫過程中唯一被阻塞的部分。

總結:

  • 如果既配置了RDB,又配置了AOF,則在進行數據持久化的時候,都會進行,但是在根據文件恢復數據的時候,以AOF文件為准,RDB文件作廢
    • 需要注意:數據的恢復是阻塞操作(此間所到來的任何客戶端讀寫請求都失效)
  • bgsave和bgrewriteaof(後台aof重寫)這兩個命令不可以同時發生
    • 如果bgsave在執行,此間到來的bgrewriteaof在bgsave執行之後,再執行
    • 如果bgrewriteaof在執行,此間到來的bgsave丟棄
  • RDB和AOF可以同時配置,但是最後還原數據庫的時候是以aof文件來還原的

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved