redis系列之——數據持久化(RDB和AOF)

在數據庫(如mysql)和緩存(如redis)的發展中,都會相互借鑑對方的長處來彌補自身的不足。好比mysql做爲持久化數據庫,爲了提升數據的訪問速度,會使用緩存技術,當一條sql查詢完成後,mysql會使用sql生成一個key,並將這個sql查詢的結果緩存到這個key上,若是運行相同的sql,服務器直接從緩存中去獲取結果,就不須要再去解析、優化、執行sql了。同時,redis做爲緩存,爲了解決宕機帶了的數據丟失問題,也增長了持久化機制。mysql

Redis支持RDB和AOF兩種持久化機制,持久化功能有效地避免因進程退出形成的數據丟失問題,當下次重啓時利用以前持久化的文件便可實現數據恢復,理解掌握持久化機制對於Redis運維很是重要。linux

今天咱們就聊一聊redis的持久化問題。本期也是面試高頻問題,同時也是實際生產必須考慮的問題。面試

1、RDB(Redis DataBase)

默認狀況下,只開啓RDB。RDB是二進制文件。redis

原理

RDB方式也叫快照方式,這種方式會在必定的觸發時機下,將當前redis的內存快照保存到磁盤上的dump.rdb文件中。這個過程當中,主要執行一個命令bgsavesql

bgsave過程

  1. 在必定的條件下觸發bgsave執行數據庫

  2. Redis父進程判斷當前是否存在正在執行的子進程,如RDB/AOF子進程,若是存在bgsave命令直接返回。vim

  3. 父進程執行fork操做建立子進程,fork操做過程當中父進程會阻塞,不能響應其餘客戶端請求。經過info stats命令查看latest_fork_usec選項,能夠獲取最近一個fork操做的耗時,單位爲微秒。Fork的做用是複製一個與當前進程同樣的進程。新進程的全部數據(變量、環境變量、程序計數器等)數值都和原進程一致,可是是一個全新的進程,並做爲原進程的子進程。緩存

  4. 父進程fork完成後,bgsave命令返回「Background saving started」信息並再也不阻塞父進程,能夠繼續響應其餘客戶端命令。安全

  5. 子進程建立RDB文件dump.rdb,根據父進程內存生成臨時快RDB文件。bash

  6. 使用臨時RDB文件對原有RDB文件的原子替換。執行lastsave命令能夠獲取最後一次生成RDB的時間,對應info統計的rdb_last_save_time選項

  7. 子進程退出。

配置

################################ SNAPSHOTTING ################################
#900s內,若是至少有一個1key進行了修改,就進行持久化操做
save 900 1
#300s內,若是至少有一個10key進行了修改,就進行持久化操做
save 300 10
#60s內,若是至少有一個10000key進行了修改,就進行持久化操做
save 60 10000
#持久化若是出錯,是否還須要繼續工做
stop-writes-on-bgsave-error yes
#是否壓縮rdb文件,須要消耗一些cpu資源
rdbcompression yes
#保存rdb文件的時候,進行錯誤的檢查校驗
rdbchecksum yes
#持久化的文件名字
dbfilename dump.rdb
#rdb文件保存的目錄
dir ./
複製代碼

觸發機制

觸發RDB持久化過程分爲手動觸發自動觸發

手動觸發

經過redis-cli登陸redis後,可使用savebgsave兩個命令觸發RDB持久化。

  • save命令:阻塞當前Redis服務器,直到RDB過程完成爲止,對於內存比較大的實例會形成長時間阻塞,線上環境不建議使用。

  • bgsave命令:Redis進程執行fork操做建立子進程,RDB持久化過程由子進程負責,完成後自動結束。阻塞只發生在fork階段,通常時間很短。

顯然bgsave命令是針對save阻塞問題作的優化。所以Redis內部全部的涉及RDB的操做都採用bgsave的方式,而save命令已經廢棄。

自動觸發

除了執行命令手動觸發以外,Redis內部還存在自動觸發RDB的持久化機制。

  • 知足上面配置文件中save m n的觸發條件時,redis會自動執行bgsave
  • slave全量複製master時,會發信息給master,這是master會執行bgsave,執行完成以後會將rdb文件發送給slave。
  • 執行shutdownflushall命令時,redis會自動執行bgsave

能夠在redis-cli的命令行執行config set save " "關閉RDB的持久化機制。

數據恢復

rdb文件會自動恢復。在redis客戶端命令行經過config get dir獲取 redis 的安裝目錄,將備份文件 (dump.rdb) 移動到 安裝目錄並啓動服務便可,redis就會自動加載文件數據至內存了。

Redis啓動後會讀取RDB快照文件,將數據從硬盤載入到內存。根據數據量大小與結構和服務器性能不一樣,這個時間也不一樣。RDB自己是二進制文件,恢復很是快。一般將一個記錄一千萬個字符串類型鍵、大小爲1GB的快照文件載入到內存中須要花費20~30秒鐘。

127.0.0.1:6379> config get dir #獲取redis的目錄
1) "dir"
2) "/usr/local/bin" # 將dump.rdb文件放在這個目錄下,從新啓動redis,就能夠自動將數據恢復
複製代碼

優缺點

優勢

表明Redis在某個時間點上的數據快照。很是適用於備份,全量複製等場景。好比每6小時執行bgsave備份,並把RDB文件拷貝到遠程機器或者文件系統中(如hdfs),用於災難恢復(對數據完整性和一致性要求不高)

RDB是二進制保存,Redis加載RDB恢復數據遠遠快於AOF的方式(適合大規模的數據恢復)

缺點

RDB方式沒辦法作到實時持久化/秒級持久化。由於bgsave每次運行都要執行fork操做建立子進程,屬於重量級操做(內存中的數據被克隆了一份,大體2倍的膨脹性須要考慮),頻繁執行成本太高(影響性能)

RDB文件使用特定二進制格式保存,Redis版本演進過程當中有多個格式的RDB版本,存在老版本Redis服務沒法兼容新版RDB格式的問題(版本不兼容)

在必定間隔時間作一次備份,因此若是redis意外down掉的話,就會丟失最後一次快照後的全部修改。

2、AOF(Append Only File)

默認狀況下,aof是關閉的。AOF命令寫入的內容直接是文本協議格式,能夠經過vim查看文件內容。

原理

以獨立日誌的方式記錄每次寫命令,重啓時再從新執行AOF文件中的命令達到恢復數據的目的。AOF的主要做用是解決了數據持久化的實時性,目前已是Redis持久化的主流方式。掌握AOF持久化機制,對兼顧數據安全性和性能很是有幫助。通俗一點的理解就是以日誌的形式來記錄每一個寫操做,將Redis執行過的全部寫指令記錄下來(讀操做不記錄),只許追加文件但不能夠改寫文件,redis啓動之初會讀取該文件從新構建數據,換言之,redis重啓的話就根據日誌文件的內容將寫指令從前到後執行一次以完成數據的恢復工做。

aof的持久化有三步:命令寫入(append)、文件同步(sync)、文件重寫(rewrite)。

image-20200718174309133

  1. 全部的寫入命令會追加到aof_buf(緩衝區)中。
  2. AOF緩衝區根據對應的策略向硬盤作同步操做。
  3. 隨着AOF文件愈來愈大,須要按期對AOF文件進行重寫,達到壓縮的目的。

Rewrite原理 : AOF文件持續增加而過大時,會fork出一條新進程來將文件重寫(也是先寫臨時文件最後再rename)。遍歷新進程的內存中數據,每條記錄有一條的Set語句。重寫aof文件的操做,並無讀取舊的aof文件,而是將整個內存中的數據庫內容用命令的方式重寫了一個新的aof文件,這點和快照有點相似。

配置

############################## APPEND ONLY MODE ###############################
# 默認不開啓aop持久化機制,由於RDB對於通常的業務已經夠用了
appendonly no

# aof持久化文件名稱
appendfilename "appendonly.aof"

# 不執行sync, 徹底依賴操做系統的刷寫,通常30秒一次。性能最好,可是持久化沒有保障,不推薦
# appendfsync no
# 每次有寫命令執行,就會執行一次sync,將命令追加到aof日誌文件。保證徹底持久化,不會丟數據,性能也是最差的,不推薦
# appendfsync always
# 每秒鐘執行一次sync,將命令追加到aof日誌文件。在性能和持久化之間作了折中,推薦。也是默認配置
appendfsync everysec

# 默認不會對aof文件使用BGREWRITEAOF命令進行重寫(重寫會合並命令,減少aof文件佔用的空間)
no-appendfsync-on-rewrite no
# 當aof文件佔用的空間超過上一次記錄的100%時,而且aof文件每增長64M,就會執行重寫(兩個條件同時知足)
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# 加載aof文件時,若是文件自己有問題(如文件結尾),是否繼續加載。yes:繼續加載,no:加載出現錯誤,中止加載,須要修復aof文件後才能加載,這是不能重啓redis
aof-load-truncated yes
複製代碼

這裏須要注意的是觸發sync的配置和rewrite的配置。

觸發機制

AOF的appendfsync觸發機制是上面配置的三個參數決定的:no、always、everysec。能夠根據對性能和持久化的實時性要求,具體配置。若是不知道哪一種合適,就使用默認的everysec,可能會有1s的數據丟失。

aof文件的重寫過程的觸發,由上面配置的rewrite參數決定。能夠手動觸發和自動觸發。

手動觸發rewrite

經過redis-cli登陸redis後,可使用bgrewriteaof命令觸發aof的重寫機制。

自動動觸發rewrite

根據auto-aof-rewrite-min-size和auto-aof-rewrite-percentage參數肯定自動觸發時機,當兩個條件同時知足時,就會觸發重寫。

數據恢復

image-20200718180244360

redis啓動時,首先判斷aof功能是否開啓,若是開啓而且存在aof持久化文件,則只會使用aof文件進行數據恢復,而不會使用rdb文件進行數據恢復。

使用aof文件恢復時,AOF文件可能存在結尾不完整的狀況,好比機器忽然掉電致使AOF尾部文件命令寫入不全。Redis爲咱們提供了aof-load-truncated配置來兼容這種狀況,默認開啓。加載AOF時,當遇到此問題時會忽略並繼續啓動。

若是關閉aof-load-truncated配置,當aof文件不完整時,則redis會啓動失敗,這時使用客戶端鏈接也是失敗的:

[root@redis ~]# redis-cli -p 6379
Could not connect to Redis at 127.0.0.1:6379: Connection refused
not connected> exit
[root@redis ~]#
複製代碼

對於錯誤格式的AOF文件,能夠先進行備份,而後採用redis安裝目錄下的redis-check-aof命令修復aof文件,修復後使用linux的命令diff -u對比數據的差別,找出丟失的數據,有些能夠人工修改補全。

[root@redis ~]# redis-check-aof --fix appendonly.aof
0x             a4: Expected \n\r, got:6461
AOF analyzed: size=185, ok_up_to=139, diff=46
This will shrink the AOF form 185 bytes, with 46 bytes, to 139 bytes
Continue? [y/N]: y # 輸入y,贊成修改
Successfully truncated AOF
[root@redis ~]#
複製代碼

優缺點

優勢

  1. 每一次修改都同步,文件完整性更高。
  2. 能夠根據具體業務,選擇同步的參數,能夠兼顧性能和同步的實時性。每一秒同步一次,可只會丟失1秒鐘的數據。

缺點

  1. AOF文件遠大於RDB文件,數據恢復速度比rdb慢。

3、總結

一、RDB持久化方式可以在指定的時間間隔內對數據進行快照存儲,默認開啓。

二、AOF持久化方式記錄每次對服務器寫操做,當服務器重啓的時候會從新執行這些命令來恢復原始的數據。AOF持久化會追加保存每次寫的操做到文件末尾, Redis還能對AOF文件進行後臺重寫(rewiter),使得AOF文件的體積不至於過大。默認不開啓。

三、若是每次重啓機器,都有單獨的服務將mysql中的數據加載到redis中,也能夠不使用任何持久化。

四、同時開啓兩種持久化方式

  • 在這種狀況下,當 redis重啓的時候,會優先載入aof文件恢復原始數據。由於在一般狀況下AOF文件保存的數據集要比RDB文件保存的數據集完整。
  • RDB文件的完整性沒有AOF高,同時使用二者時,服務器重啓也只會使用AOF文件,那要不要只使用AOF呢?建議不要,由於RDB更適合用於備份數據庫(AOF在不斷變化很差備份),是二進制存儲恢復快,並且不會有AOF可能潛在的Bug,留着做爲一個萬一的手段。

五、性能建議

  • 由於RDB文件只用做數據備份,建議只在Slave上持久化RDB文件,並且只要15分鐘備份一次就夠了,只保留save 900 1這條規則。
  • 若是開啓aof,好處是在最惡劣狀況下也只會丟失不超過兩秒數據,啓動腳本較簡單,只load本身的AOF文件就能夠了,代價一是帶來了持續的IO;二是 AOF rewrite的最後將 rewrite過程當中產生的新數據寫到新文件形成的阻塞幾乎是不可避免的。應該儘可能減小 AOF rewrite的頻率,AOF重寫的基礎大小默認值64M(auto-aof-rewrite-min-size 64mb)過小了,能夠設到5G以上;默認超過原大小100%大小重寫能夠改到適當的數值。
  • 若是不開啓aof,僅靠 Master-Slave Replication實現高可用性也能夠,能省掉一大筆IO,也減小了rewrite時帶來的系統波動。代價是若是 Master/Slave同時宕機,會丟失十幾分鐘的數據,啓動腳本也要比較兩個Master/Slave中的RDB文件,載入較新的那個。

完成,收工!

傳播知識,共享價值】,感謝小夥伴們的關注和支持,我是【諸葛小猿】,一個彷徨中奮鬥的互聯網民工!!!

相關文章
相關標籤/搜索