......
持久化存儲
What is persistence
將RAM(內存)中的的數據存儲到能永久保存的ROM(如disk)中。
How to persist
- 快照(snapshot),指在某個時刻對數據進行備份持久化,如Mysql的Dump方式、Redis的RDB方式。
- 寫日誌,將用戶所有的寫指令(增刪改)保存到日誌文件中,當需恢復數據時重新執行一遍這些指令,如Mysql的Binlog、Redis的AOF、Hbase的HLog。
1 持久化存儲方式
2 持久化存儲原理
2.1 RDB
2.1.1 原理結構
- RDB是Redis默認的持久化方案,默認開啓
- 可以在指定的時間間隔內,執行指定次數的寫操作,將內存中的數據寫入到磁盤中
- 可以在指定目錄下自動生成dump.rdb文件,當Redis重啓時會加載該文件以恢復數據
- 自動備份和手動備份
2.1.2 工作執行流程——三種主要觸發機制
2.1.2.1 手動觸發之save命令
原理圖
指令
127.0.0.1:6379> save
OK
說明
- save命令執行的是同步操作,以RDB文件的方式保存所有數據的快照
- 佔用主進程,執行速度非常慢,會阻塞所有的client請求,故很少在生產環境中使用save指令
2.1.2.2 手動觸發之bgsave命令
原理圖1
指令
127.0.0.1:6379> bgsave
Background saving started
簡要說明
- bgsave命令執行的是異步操作,以RDB文件的方式保存所有數據的快照
- Redis調用Linux系統中fork()創建一個子進程將數據保存到磁盤中,主進程繼續服務客戶端的調用
- 若操作成功,可以通過客戶端命令LASTSAVE來檢查操作結果;若子進程發生錯誤,用 SAVE命令保存最新的數據
原理圖2
說明
- 執行bgsave命令,Redis父進程判斷當前是否存在正在執行的子進程,如果存在則直接返回
- 父進程fork一個子進程(fork的過程中會造成阻塞的情況),這個過程可以使用info stats命令查看latest_fork_usec選項,查看最近一次fork操作小號的時間,單位是微秒μs
- 父進程fork完之後,則會返回Background saving started信息提示,此時fork阻塞解除
- fork出的子進程開始根據父進程內存數據生成臨時的快照文件,然後替換原文件.使用lastsave命令可以查看最後一次生成rdb的時間,對應info的rdb_last_savetime選項
- 當備份完畢之後向父進程發送完成信息,具體可以見info Persistence下的rbd*選項
save
與 bgsave
對比
命令 | save | bgsave |
---|---|---|
IO類型 | 同步 | 異步 |
阻塞 | 是 | 是(阻塞發生在fock(),通常非常快) |
複雜度 | O(n) | O(n) |
優點 | 不會消耗額外的內存 | 不阻塞客戶端請求命令 |
缺點 | 阻塞客戶端請求命令 | 需要fock子進程,消耗內存 |
2.1.2.3 自動觸發
描述:通過redis.conf配置文件對 Redis 進行設置, 讓它在“ N 秒內數據集至少有 M 個改動”這一條件被滿足時, 自動進行數據集保存操作。
自動觸發過程:
- 修改配置項 save m n即表示在 m 秒內執行了 n 次命令則進行備份
- 當Redis 從服務器項主服務器發送複製請求時,主服務器則會使用 bgsave命令生成 rbd 文件,然後傳輸給從服務器
- 當執行 debug reload 命令時也會使用 save 命令生成rdb文件
- 當使用 shutdown 命令關掉服務時,如果沒有啓用 aof方式實現持久化則會採用bgsave的方式做持久化。同時shutdown後面可以加備份參數[nosave|save]。
指令:
save <指定時間間隔> <執行指定次數更新操作>
舉例:
- 以下設置會讓 Redis 在滿足“ 60 秒內有至少有 1000 個鍵被改動”這一條件時, 自動生成rdb文進行數據集保存
save 60 1000
2.1.2.4 自動觸發的相關配置
1. redis.cnf配置文件(部分)
# Save the DB on disk:
#
# save <seconds> <changes>
#
# Will save the DB if both the given number of seconds and the given
# number of write operations against the DB occurred.
#
# In the example below the behaviour will be to save:
# after 900 sec (15 min) if at least 1 key changed
# after 300 sec (5 min) if at least 10 keys changed
# after 60 sec if at least 10000 keys changed
#
# Note: you can disable saving at all commenting all the "save" lines.
#
# It is also possible to remove all the previously configured save
# points by adding a save directive with a single empty string argument
# like in the following example:
#
# save ""
save 900 1
save 300 10
save 60 10000
說明:
- save <指定時間間隔> <執行指定次數更新操作>,滿足條件就將內存中的數據同步到硬盤中
- 官方出廠配置默認是 900秒內有1個更改,300秒內有10個更改以及60秒內有10000個更改,則將內存中的數據快照寫入磁盤
- 若不想用RDB方案,可以把 save "" 的註釋打開,下面三個註釋
2. vim redis.cfg
# RDB自動持久化規則
# 當 900 秒內有至少有 1 個鍵被改動時,自動進行數據集保存操作
save 900 1
# 當 300 秒內有至少有 10 個鍵被改動時,自動進行數據集保存操作
save 300 10
# 當 60 秒內有至少有 10000 個鍵被改動時,自動進行數據集保存操作
save 60 10000
# RDB持久化文件名
dbfilename dump-<port>.rdb
# 數據持久化文件存儲目錄
dir /var/lib/redis
# bgsave發生錯誤時是否停止寫入,通常爲yes
stop-writes-on-bgsave-error yes
# rdb文件是否使用壓縮格式
rdbcompression yes
# 是否對rdb文件進行校驗和檢驗,通常爲yes
rdbchecksum yes
另:
# 1. 將自動生成rdb文件註釋掉
# save 900 1
# save 300 10
# save 60 10000
# The filename where to dump the DB
# 2. rdb的文件名,改爲dump+ 端口.rbd
dbfilename dump-${port}.rdb
# Note that you must specify a directory here, not a file name.
# 3. 文件持久化目錄,日誌目錄,改到分佈式存儲中或者放到較大的硬盤目錄中。
dir /yourbigdata/
# 4. 在bgsave發生錯誤時停止寫入
stop-writes-on-bgsave-error yes
# 5.採用壓縮方式,不然生成的rdb文件可能巨大無比。壓縮後主從複製拷貝文件小,速度也快。
rdbcompression yes
# 6.採用校驗和
rdbchecksum yes
RDB優缺點
優點
- 非常適用數據集備份、rdb文件拷貝進行文件傳輸
- 如果業務對數據完整性和一致性要求不高,RDB是很好的選擇
- RDB文件採用壓縮的二進制文件,當重啓服務時加載數據文件,比aof方式更快
缺點
- 不可控,容易丟失數據,導致數據的完整性和一致性不高,因爲RDB可能在最後一次備份時宕機了
如果你希望在redis意外停止工作(例如電源中斷)的情況下丟失的數據最少的話,那麼RDB不適合你。雖然你可以配置不同的save時間點(例如每隔5分鐘並且對數據集有100個寫的操作),是Redis要完整的保存整個數據集是一個比較繁重的工作,你通常會每隔5分鐘或者更久做一次完整的保存,萬一在Redis意外宕機,你可能會丟失幾分鐘的數據(轉:https://segmentfault.com/a/1190000016021217)
- 耗時、耗性能:備份時佔用內存,因爲Redis 在備份時會獨立創建一個子進程,將數據寫入到一個臨時文件(此時內存中的數據是原來的兩倍),最後再將臨時文件替換之前的備份文件。Redis 的持久化和數據的恢復要選擇在夜深人靜的時候執行。
RDB 需要經常fork子進程來保存數據集到硬盤上,當數據集比較大的時候,fork的過程是非常耗時的,可能會導致Redis在一些毫秒級內不能響應客戶端的請求。如果數據集巨大並且CPU性能不是很好的情況下,這種情況會持續1秒,AOF也需要fork,但是你可以調節重寫日誌文件的頻率來提高數據集的耐久度。(轉:https://segmentfault.com/a/1190000016021217)
- rbd採用加密的二進制格式存儲文件,由於Redis各個版本之間的兼容性問題也導致rdb由版本兼容問題導致無法再其他的Redis版本中使用。
2.1.2.5 RDB文件常見的處理方式
- 當遇到磁盤寫滿情況,可以使用如下命令來切換存儲磁盤
# dirName則是新的存儲目錄名(該方式同樣適用於aof格式)
config set dir dirName
- 文件壓縮處理,雖然對CPU具有消耗,但是減少體積的暫用,同時做文件傳輸(主從複製)也減少消耗
# 修改壓縮開啓或關閉
config set rdbcompression yes|no
- rbd備份文件損壞檢測.可以使用redis-check-rdb工具檢測rdb文件,該工具默認在/usr/local/bin/目錄下面
[root@root redis-data]# /usr/local/bin/redis-check-rdb ./6379-rdb.rdb
[offset 0] Checking RDB file ./6379-rdb.rdb
[offset 26] AUX FIELD redis-ver = '5.0.3'
[offset 40] AUX FIELD redis-bits = '64'
[offset 52] AUX FIELD ctime = '1552061947'
[offset 67] AUX FIELD used-mem = '852984'
[offset 83] AUX FIELD aof-preamble = '0'
[offset 85] Selecting DB ID 0
[offset 105] Checksum OK
[offset 105] \o/ RDB looks OK! \o/
[info] 1 keys read
[info] 0 expires
[info] 0 already expired
2.2 AOF
update...