Redis持久化存儲詳解(一)
> 為什麼要做持久化存儲?
持久化存儲是将 Redis 存儲在記憶體中的資料存儲在硬碟中,實作資料的永久儲存。我們都知道 Redis 是一個基于記憶體的 nosql 資料庫,記憶體存儲很容易造成資料的丢失,因為當伺服器關機等一些異常情況都會導緻存儲在記憶體中的資料丢失。
> 持久化存儲分類
在 Redis 中,持久化存儲分為兩種。一種是 aof 日志追加的方式,另外一種是 rdb 資料快照的方式。
> RDB持久化存儲
什麼是RDB持久化存儲
RDB持久化存儲即是将redis存在記憶體中的資料以快照的形式儲存在本地磁盤中。
.RDB持久化存儲分為自動備份和手動備份
1.手動備份通過 save 指令和 bgsave 指令。save是同步阻塞,而 bgsave 是非阻塞(阻塞實際發生在 fork 的子程序中)。是以,在我們實際過程中大多是使用bgsave指令實作備份.
```shell
redis> SAVE
OK
```
redis> BGSAVE
Background saving started
2.自動備份
a.修改配置項 save m n即表示在 m 秒内執行了 n 次指令則進行備份.
b.當Redis 從伺服器項主伺服器發送複制請求時,主伺服器則會使用 bgsave指令生成 rbd 檔案,然後傳輸給從伺服器.
c.當執行 debug reload 指令時也會使用 save 指令生成rdb檔案.
d.當使用 shutdown 指令關掉服務時,如果沒有啟用 aof方式實作持久化則會采用bgsave的方式做持久化.同時shutdown後面可以加備份參數[nosave|save].
bgsave持久化存儲實作原理

1.執行bgsave指令,Redis父程序判斷目前是否存在正在執行的子程序,如果存在則直接傳回.
2.父程序fork一個子程序(fork的過程中會造成阻塞的情況),這個過程可以使用info stats指令檢視latest_fork_usec選項,檢視最近一次fork操作小号的時間,機關是微妙.
3.父程序fork完之後,則會傳回Background saving started資訊提示,此時fork阻塞解除.
4.fork出的子程序開始根據父程序記憶體資料生成臨時的快照檔案,然後替換原檔案.使用lastsave指令可以檢視最後一次生成rdb的時間,對應info的rdb_last_save_time選項.
5.當備份完畢之後向父程序發送完成資訊,具體可以見info Persistence下的rbd_*選項.
RDB持久化的優勢與劣勢
優勢:
1.檔案實作的資料快照,全量備份,便于資料的傳輸.比如我們需要把A伺服器上的備份檔案傳輸到B伺服器上面,直接将rdb檔案拷貝即可.
2.檔案采用壓縮的二進制檔案,當重新開機服務時加載資料檔案,比aof方式更快.
劣勢:
1.rbd采用加密的二進制格式存儲檔案,由于Redis各個版本之間的相容性問題也導緻rdb由版本相容問題導緻無法再其他的Redis版本中使用.
2.時效性差,容易造成資料的不完整性.因為rdb并不是實時備份,當某個時間段Redis服務出現異常,記憶體資料丢失,這段時間的資料是無法恢複的,是以易導緻資料的丢失.
RDB檔案常見的處理方式
1.當遇到磁盤寫滿情況,可以使用如下指令來切換存儲磁盤
// dirName則是新的存儲目錄名(該方式同樣适用于aof格式)
config set dir dirName
2.檔案壓縮處理,雖然對CPU具有消耗,但是減少體積的暫用,同時做檔案傳輸(主從複制)也減少消耗.
// 修改壓縮開啟或關閉
config set rdbcompression yes|no
3.rbd備份檔案損壞檢測.可以使用redis-check-rdb工具檢測rdb檔案,該工具預設在/usr/local/bin/目錄下面.
[root@syncd 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
> AOF持久化存儲
AOF持久化存儲是什麼
AOF持久化存儲便是以日志的形式将redis存儲在aof_buf緩沖區中的資料寫入到磁盤中。簡而言之,就是記錄redis的記錄檔,将redis執行過的指令記錄下載下傳,當我們需要資料恢複時,redis去重新執行一次日志檔案中的指令.
如何配置持久化存儲
// 将no改為yes,控制aof開啟與否
appendonly no
// 控制aof檔案名稱,存儲的目錄便是dir配置項
appendfilename "appendonly.aof"
// 三種備份政策(三者隻需要開啟以一個即可)
# appendfsync always // 指令寫入立即寫入磁盤
appendfsync everysec // 每秒實作檔案的同步,寫入磁盤
# appendfsync no // 随機進行檔案的同步,同步操作則交給作業系統來負責,通常時間是最長30s
AOF持久化存儲實作原理
aof日志追加方式實作持久化存儲,需要經曆如下四個過程.指令寫入->檔案同步->檔案重寫->檔案重載

1.redis指令寫入,此時會将redis指令寫入aof_buf換從區.
2.緩沖區中資料根據備份政策實作寫入日志檔案.
3.當aof的檔案越來越龐大,會根據我們的配置政策來實作aof的重寫,實作檔案的壓縮,減少體積.
4.當redis重新啟動時,在去重寫加載aof檔案,達到資料恢複的目的.
指令寫入
指令寫入主要是将檔案執行過的指令寫入到日志檔案中.并且日志檔案尊徐文本協定格式,下面示例代碼便是aof日志檔案中存儲的内容格式.
*3\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n
aof采用的是文本協定格式。主要是原因根據資料提示,可以能使由于如下原因.
1.文本協定的相容性好.前面我們提及到了rdb檔案是進行二進制加密,可能不同版本之間會出現不相容的情況,采用文本協定可以加避免該問題。同時文本協定也可以減少跨平台使用所帶來的諸多問題.
2.可讀性強.由于aof是将指令寫入檔案中,我們可以直接檢視指令内容,同時也可以修改日志檔案内容.
3.開啟aof後,所有的檔案檔案都包含追加操作,直接采用文本協定,減少二次開銷(這一點,個人不是很了解.因為我們的aof是儲存的是指令,當我們再次去加載的時候,會去執行一次裡面的指令,當檔案大的時候應該是比較耗時的吧。如果沒有做好檔案重寫政策,大量重複無效的指令執行,對于二進制加密的rdb格式,不需要再去轉換,這一點确實可以減少二次開銷).
檔案寫入
檔案寫入是将aof_buf緩沖區的指令寫入到檔案中.檔案寫入的政策有如下三種方式
|配置項 | 配置說明 |
|:---: | :---: |
|always | 指令寫入到aof_buf緩沖區中之後立即調用系統的<font color='red'>fsync操作</font>同步到aof檔案中,fsync完成後線程傳回. |
|everysec | 指令寫入到aof_buf緩沖區後<font color='red'>每隔一秒</font>調用系統的<font color='red'>write操作</font>,write完成後線程傳回. |
|no | 指令寫入aof_bug緩沖區後調用系統write操作,不對aof檔案做fsync同步,同步硬碟操作由<font color='red'>系統操作</font>完成,時間一般最長為30s. |
系統調用write和fsync說明:
·write操作會觸發延遲寫( delayed write) 機制。 Linux在核心提供頁緩沖區用來提高硬碟IO性能。 write操作在寫入系統緩沖區後直接傳回。 同步硬碟操作依賴于系統排程機制, 例如: 緩沖區頁空間寫滿或達到特定時間周期。 同步檔案之前, 如果此時系統故障當機, 緩沖區内資料将丢失.
·fsync針對單個檔案操作( 比如AOF檔案) , 做強制硬碟同步, fsync将阻塞直到寫入硬碟完成後傳回, 保證了資料持久化.
檔案寫入政策分析
配置為always時, 每次寫入都要同步AOF檔案, 在一般的SATA硬碟上, Redis隻能支援大約幾百TPS寫入, 顯然跟Redis高性能特性背道而馳,
不建議配置.
配置為no。由于作業系統每次同步AOF檔案的周期不可控, 而且會加大每次同步硬碟的資料量, 雖然提升了性能, 但資料安全性無法保證.
配置為everysec。是建議的同步政策, 也是預設配置, 做到兼顧性能和資料安全性。 理論上隻有在系統突然當機的情況下丢失1秒的資料.
檔案重載
1.為什麼要檔案做檔案重載操作?
由于aof采用的是日志追加,我們redis指令不斷的寫入,aof檔案的體積也也會不斷的增加.是以redis引入了aof重寫機制達到減小aof檔案體積.<font color="blue">aof檔案重寫是把redis程序内的資料轉換為寫指令同步到新的aof檔案的過程(這一點其實不是特别明白,檔案重寫不是針對aof檔案檔案做操作的嗎?為什麼這裡是将redis程序内的資料轉換為指令寫入檔案,這裡的程序内的資料不是太明白,還有待深入研究.個人了解的就是将舊的aof檔案内容根據重寫政策,進行優化生成新的aof檔案。).</font>
2.檔案重載有什麼好處?
檔案重載主要優化的地方有如下三點。使用檔案重載既可以減少檔案的體積,同時去掉了一些無效的操作,可以加快檔案重載效率.
a.将一些在程序内無效的資料不在寫入新的檔案.如過期的鍵.
b.去掉一些無效的指令.如del key1.
c.簡化操作.如lpush list a,lpush list b.直接可以簡化為lpush list a b.
3.檔案重載由那些方式?
檔案重載有自動觸發機制和手動觸發機制.
手動觸發機制:直接使用bgrewriteaof指令即可.該指令在fork子程序的時候會發生阻塞.
自動觸發機制:
auto-aof-rewrite-min-size:aof重寫時檔案最小的體積,預設的是64M.
auto-aof-rewrite-percentage:代表目前AOF檔案空間( aof_current_size) 和上一次重寫後AOF檔案空間( aof_base_size) 的比值.
```php
自動觸發時機=aof_current_size>auto-aof-rewrite-minsize&&( aof_current_size-aof_base_size) /aof_base_size>=auto-aof-rewritepercentage
其中aof_current_size和aof_base_size可以在info Persistence統計資訊中檢視.
4.檔案重載實作的原理是怎樣的?

1.執行重寫指令,判斷是否存在子程序。
如果已經有子程序在進行aof重寫,則會提示如下資訊.
ERR Background append only file rewriting already in progress
如果已經存在子程序在進行bgsave操作,重寫指令會延遲到bgsave指令完成之後進行,會傳回如下資訊.
Background append only file rewriting scheduled
2.父程序會fork一個子程序,在fork子程序的過程中會造成阻塞.
3.fork子程序結束阻塞解除,進行其他新的指令操作.新的指令依舊根據檔案寫入政策同步資料,保證aof機制正确進行(圖中3.1).
4.子程序在進行寫的過程中,由于fork操作運用的是寫時複制技術,子程序隻能共享fork操作時記憶體保留的資料,新的資料是無法操作的.父程序在這過程中仍然在響應其他的指令,于是Redis會使用aof重寫緩存區來儲存這部分新的資料(圖中3.2).
5.子程序進行根據重寫規則将資料寫入到新的aof檔案中,并且每次寫入有大小限制,通過aof-rewrite-incremental-fsync配置項來控制,預設是32M,這樣可以見減少單次刷盤(I/O寫)造成硬碟阻塞.
6.子程序在完成重寫之後,會向父程序發送資訊,父程序更新統計資訊.可參看info persistence下的aof_*相關統計。
7.父程序會把新寫入存在aof重寫緩沖區的資料寫入到aof檔案中(圖5.2).
8.将新的aof檔案替換掉舊的aof檔案.
<font color='blue'>在第3和4中,其實不是特别了解.不了解的是為什麼父程序在響應新的指令會寫入舊的aof檔案,還要aof重寫緩存區.個人了解的是,父程序在進行新指令寫入處理的政策是,按照正常的備份政策寫入舊的aof的同時也把新的指令寫入重寫緩沖區,在第5.2中将這部分新的資料寫入到新的aof檔案中,這樣保證資料的完整性.</font>
檔案重載就是将檔案重新加入到redis服務中.比如redis服務重新開機用于資料恢複.redis的重載機制非常完善,具體流程如下.
AOF檔案常見的問題處理
1.檔案損壞
我們在加載損壞的檔案是可能提示如下資訊.
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指令進行修複(記得對檔案做個備份).修複後使用diff-u進行資料對比,找出部分丢失的資料.
2.檔案加載不完整
這可能是資料在備份的時候,redis服務異常,導緻備份不完整.可以使用redis的aof-load-truncated相容該異常
AOF的優缺點
優點:
多種檔案寫入(fsync)政策.
資料實時儲存,資料完整性強.即使丢失某些資料,制定好政策最多也是一秒内的資料丢失.
可讀性強,由于使用的是文本協定格式來存儲的資料,可有直接檢視操作的指令,同時也可以手動改寫指令.
缺點:
檔案體積過大,加載速度比rbd慢.由于aof記錄的是redis操作的日志,一些無效的,可簡化的操作也會被記錄下來,造成aof檔案過大.但該方式可以通過檔案重寫政策進行優化.
選擇AOF還是RDB進行資料的持久化
1.針對不同的情況來選擇,建議使用兩種方式相結合.
2.針對資料安全性、完整性要求高的采用aof方式.
3.針對不太重要的資料可以使用rdb方式.
4.對于資料進行全量備份,便于資料備份的可以采用rdb方式.
原文轉自微信公衆号:浪子程式設計走四方