redis的持久化之RDB和AOF模式(三)


RDB模式

RDB是Redis默認開啓的持久化模式,持久化方式爲指定時間(默認5分鐘),定時同步內存中的數據到磁盤中做持久化存儲,也就是同步到指定目錄下的dump.rdb文件,Redis服務在重啓時候會重新加載該文件的數據到內存

RDB相關配置

save <時間(秒/s)> <更新次數>,在指定時間內達到更新次數,則持久化到rdb文件一次。如果想關閉RDB同步,則把save ""放開,其它幾個開頭加**#**屏蔽

# save ""
save 900 1		#900秒內執行1次set操作則持久化一次
save 300 10		#300秒內執行10次set操作則持久化一次
save 60 10000	#60秒內執行10000次set操作則持久化一次

指定持久化文件的名稱和文件位置

dbfilename dump.rdb  #文件名稱,可自定義
dir ./			# 文件所在目錄位置,可修改爲指定目錄

是否壓縮存儲到磁盤中的快照,默認開啓壓縮Yes。Redis會採用LZF算法進行壓縮。如果你不想消耗CPU來進行壓縮的話,可以設置爲關閉此功能,但是存儲在磁盤上的快照會比較大。

rdbcompression yes  

RDB優缺點

優點

  1. 保存了某個時間點上的數據,適合做冷備,定時同步到遠端服務器,線上掛了可以恢復
  2. 對redis性能影響小,通過fock了一個子進程做持久化,不會阻塞主進程,也不需要主進程做任何磁盤IO操作
  3. RDB在進行數據恢復的速度比AOF要快

缺點

  1. RDB生成快照的時候,fock的子進程會把數據寫入到臨時文件,最後再把臨時文件替換之前的備份rdb文件,這個過程內存中的數據被克隆了一份,大致2倍的膨脹性,可能幾毫秒或者幾秒,如果剛好是秒殺期間就gg
  2. 在指定時間內做一次備份,如果redis掛掉,意味着可能丟失這個時間間隔內的數據

RDB的手動觸發

save命令
該命令會阻塞當前redis服務進程,執行save命令期間,不能接收其它打到的命令,直到RDB持久化過程完成。如果線上這麼操作,可是很致命,相當於redis當前停止服務

bgsave命令
該命令會在後臺異步執行快照操作,此時redis服務正常接收其它打到的命令,服務正常提供。所以,redis內部或者手動觸發基本都是使用bgsave

RDB模式的演示

修改配置文件,120秒內set4次持久化一次,重啓redis服務
# cd /home/tool/redis-5.0.5
# vi redis.conf
save 120 4
# service redis stop
# service redis start

進入客戶端,set幾個值
# redis-cli
127.0.0.1:6379> set username toegg
OK
127.0.0.1:6379> set age 18
OK
127.0.0.1:6379> set sex 1
OK
127.0.0.1:6379> set user_id 1001
OK
等待一分鐘後,再set
127.0.0.1:6379> set work docter
OK

獲取所有keys,關閉redis服務
127.0.0.1:6379> keys *
1) "user_id"
2) "age"
3) "sex"
4) "username"
5) "work"
127.0.0.1:6379> SHUTDOWN
not connected> QUIT
# ps aux |grep rediss
root      18473  0.0  0.2 103300  2024 pts/0    S+   04:14   0:00 grep redis

查看 / 目錄下的dump.rdb文件
# cat /dump.rdb
REDIS0009▒      redis-ver5.0.5▒
▒edis-bits▒@▒ctime®/▒^used-mem▒P
aof-preamble▒▒▒user_id▒▒age▒sexusernametoeggworkdocker

重啓redis服務,進入客戶端,獲取所有元素,元素都還在
# service redis start
# redis-cli
127.0.0.1:6379> keys *
1) "user_id"
2) "work"
3) "username"
4) "sex"
5) "age"
127.0.0.1:6379> exit

複製 / 目錄下的rdb文件到 dump1.rdb 做儲備文件
# cp /dump.rdb /dump1.rdb

進入客戶端,清空所有元素,關閉服務
# redis-cli
127.0.0.1:6379> flushall
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> SHUTDOWN
not connected> QUIT

查看 / 目錄下的dump.rdb文件,發現已爲空
# cat /dump.rdb

重啓服務,進入客戶端,獲取所有元素,發現所有元素已經清空
# service redis stop
# service redis start
# redis-cli
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> SHUTDOWN
not connected> QUIT

複製剛纔的儲備文件,覆蓋掉/下的dump.rdb,再重啓服務
# cp /dump1.rdb /dump.rdb
cp: overwrite `dump.rdb'? y
# service redis start
# redis-cli
127.0.0.1:6379> keys *
1) "username"
2) "sex"
3) "age"
4) "user_id"
5) "work"

操作步驟如下:

  1. 修改配置文件,60秒內修改4次則持久化一次,重啓redis服務

  2. 進入客戶端,set幾個相關值,過1分鐘後,看指定RDB文件的 / 目錄下是否會生成一個dump.rdb文件。再set第五個work的元素,然後執行SHUTDOWN關閉redis服務,是爲了驗證通過SHUTDOWN關閉服務,SHUTDOWN會觸發RDB快照

  3. 查看 / 目錄下的dump.rdb文件,set的幾個值已在文件中,內容部分是亂碼是編碼問題,忽略

  4. 重啓redis服務,再進入客戶端,獲取所有元素,發現剛纔set的元素都在,即重啓,redis服務正常從dump.rdb加載數據到內存

  5. 複製當前的rdb文件做儲備,等下用

  6. 進入客戶端,執行flushall清空所有元素,關閉服務

  7. 查看 / 目錄下下的dump.rdb,發現已經爲空,得出flushall也會觸發RDB快照

  8. 重啓redis服務,再進入客戶端,獲取所有元素,發現都不在了

  9. 複製剛纔的儲備文件,覆蓋掉/下的dump.rdb,再重啓服務

  10. 進入客戶端,發現一開始set的值已經加載回內存


AOF模式

Redis默認不開啓,它是可以保證數據的高可用性,即最大限度的避免數據丟失。AOF是以日誌文件的形式,把每個寫指令以追加方式記錄到文件中。Redis重啓會根據日誌文件的指令內容都執行一遍,實現數據恢復

AOF相關配置

開啓AOF,把 no 改爲 yes

appendonly yes

指定文件名,可自定義修改

appendfilename "appendonly.aof"

數據同步到文件的觸發方式,默認是每1秒同步。
always:每次發生數據變化立刻寫入,這裏會影響性能但是數據完整
everysec:默認配置,每1秒寫入一次
no:不同步,相當於關閉了寫入

# appendfsync always
appendfsync everysec
# appendfsync no

重寫觸發機制,aof文件大小達到指定大小,就會觸發重寫,相當於移除冗餘指令。
第一個參數是當前AOF文件大小和最後一次重寫後的大小之間的比率等於100%,纔會觸發重寫

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

AOF的重寫機制

AOF 的運作方式是不斷地將命令追加到文件的末尾,隨着寫入命令的不斷增加, AOF 文件的體積也會變得越來越大,冗餘數據越來越多。比如set了同個key100次 , 那麼僅僅是爲了保存這個key的當前值,卻有100條指令記錄,冗餘了99條。爲了處理這種情況, Redis 支持不影響服務的情況下,執行 BGREWRITEAOF 命令,fock了子進程對AOF文件重寫,包含當前數據集所需最少命令。

重寫觸發條件

  1. 沒有bgsave命令,RDB / AOF持久化在執行
  2. 沒有其它BGREWRITEAOF在執行
  3. 當前AOF文件大小大於aof_rewrite_min_size,默認是64m(這個太小了,根據自身調整)
  4. AOF文件大小是上次重寫rewrite後大小的(auto-aof-rewrite-percentage),默認是100%,一倍

重寫步驟:

  1. Redis執行fock()子進程,父進程啓用重寫緩衝區
  2. 子進程開始直接從數據庫中讀取鍵現在的值,然後用一條命令去記錄鍵值對,寫入到臨時文件。對於所有其它新執行的寫入命令,父進程將它們寫到重寫緩衝區中,同時也寫入現有的舊的AOF文件,保證了Redis服務的正常進行和持久化
  3. 子進程完成AOF重寫之後,會向父進程發送一個完成信號,父進程會把重寫緩衝區,即是重寫過程新執行的寫入命令全部追加到新的AOF文件,這個時候就和服務器當前數據保持一致了。
  4. 最後,父進程對新的AOF文件進行改名,原子的覆蓋原有的AOF文件,完成新舊兩個AOF文件的替換

AOF文件格式修復

實際開發中,可能因爲某些原因導致 appendonly.aof 文件格式異常,這樣會導致Redis啓動數據還原失敗。
修復方式,執行以下命令

# cd /home/tool/redis-5.0.5/src
# redis-check-aof --fix appendonly.aof

AOF優缺點

優點

  1. AOF每1秒異步fsync記錄一次,丟失數據最多就1秒,數據的實時性高
  2. 對日誌文件進行操作的時候是以append-only的方式去追加寫,少了很多磁盤尋址的開銷

缺點

  1. 一樣的數據,AOF文件比RDB要大得多,數據恢復速度就會慢
  2. aof開啓後,redis的寫qps比rdb支持的低,因爲1秒fsync一次,當然,性能還是沒問題

AOF模式的演示

修改AOF啓用,重啓redis服務
# vi redis.conf
appendonly yes
# service redis start

設置值,然後關閉redis服務
127.0.0.1:6379> set username toegg
OK
127.0.0.1:6379> keys *
1) "username"
127.0.0.1:6379> SHUTDOWN
not connected> QUIT

查看appendonly.aof,文件是會在當前目錄下生成
# cat appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
set
$8
username
$5
toegg

重啓服務,進入客戶端,獲取所有元素,發現已加載回數據
# service redis start
# redis-cli
127.0.0.1:6379> keys *
1) "username"
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> exit

複製 appendonly.aof文件到 appendonly1.aof 做儲備文件
cp appendonly.aof appendonly1.aof

進入客戶端,清空所有元素,關閉服務
# redis-cli
127.0.0.1:6379> flushall
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> SHUTDOWN
not connected> QUIT

查看appendonly.aof,發現多了指令flushall
# cat appendonly.aof

重啓服務,進入客戶端,獲取所有元素,發現元素已被清空
# service redis start
# redis-cli
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> SHUTDOWN
not connected> QUIT

複製剛纔的儲備文件,覆蓋掉appendonly.aof,再重啓服務,數據恢復
# cp appendonly1.aof appendonly.aof
cp: overwrite `appendonly.aof'? y
# service redis start
# redis-cli
127.0.0.1:6379> keys *
1) "username"
127.0.0.1:6379> SHUTDOWN
not connected> QUIT

損壞appendonly.aof的格式,在文件末尾加上1111,啓動服務
# vi appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
set
$8
username
$5
toegg
1111
# service redis start
5349:M 24 May 2020 04:11:02.470 # Bad file format reading the append only file: make a backup of your AOF file, then use ./redis-check-aof --fix <filename>

修復文件格式,再重啓服務,已經能正常啓動。獲取所有元素,數據正常加載
# redis-check-aof --fix appendonly.aof
0x              66: Expected prefix '*', got: '1'
AOF analyzed: size=108, ok_up_to=102, diff=6
This will shrink the AOF from 108 bytes, with 6 bytes, to 102 bytes
Continue? [y/N]: y
Successfully truncated AOF
# service redis start
# redis-cli
127.0.0.1:6379> keys *
1) "username"

操作步驟如下:

  1. 修改配置文件,啓用AOF,重啓redis服務

  2. 進入客戶端,set一個值,關閉redis服務

  3. 查看當前目錄的appendonly.aof文件,set的值已在文件中

  4. 重啓redis服務,再進入客戶端,獲取所有元素,發現剛纔set的元素都在,即重啓,redis服務正常從appendonly.aof加載數據到內存

  5. 複製當前的aof文件做儲備,等下用

  6. 進入客戶端,執行flushall清空所有元素,關閉服務

  7. 查看appendonly.aof,發現文件最後有flushall指令,這裏得出flushall也會記錄到aof文件

  8. 重啓redis服務,再進入客戶端,獲取所有元素,發現都不在了

  9. 複製剛纔的儲備文件,覆蓋掉appendonly.aof,再重啓服務,數據已恢復

  10. 進入客戶端,發現一開始set的值已經加載回內存

  11. 故意在appendonly.aof末尾加上1111,造成文件格式異常,啓動服務,顯示讀取文件報錯

  12. 使用命令redis-check-aof --fix appendonly.aof修正,重新啓動,可以正常啓動,數據也正常加載


總結:

  1. Redis默認開啓RDB模式,指定間隔時間內,執行指定次數寫操作則持久化到磁盤。它的恢復速度快,但是數據的一致性和完整性較差
  2. AOF模式需要手動開啓,秒級持久化,保證數據完整性,但文件內容較大,恢復速度慢
  3. AOF針對文件大小不斷變大,提供了重寫機制
  4. 啓動加載流程,優先加載AOF,再加載RDB
  5. 注意不要用flushall,會寫入rdb或者appendonly,會清掉數據
  6. 最好的話,兩者都用,RDB做冷備,AOF做熱備,穩健服務器
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章