1. 程式人生 > >redis學習筆記七之持久化

redis學習筆記七之持久化

redis是一個支援持久化的記憶體資料庫,也就是說redis需要經常將記憶體中的資料同步到磁碟來保證持久化。redis支援兩種持久化方式,一種是 Snapshotting(快照)也是預設方式,另一種是Append-only file(縮寫aof)的方式。下面分別介紹

Snapshotting
       快照是預設的持久化方式。這種方式是就是將記憶體中資料以快照的方式寫入到二進位制檔案中,預設的檔名為dump.rdb。可以通過配置設定自動做快照持久 化的方式。我們可以配置redis在n秒內如果超過m個key被修改就自動做快照,下面是預設的快照儲存配置

save 900 1  #900秒內如果超過1個key被修改,則發起快照儲存


save 300 10 #300秒內容如超過10個key被修改,則發起快照儲存
save 60 10000

下面介紹詳細的快照儲存過程

1.redis呼叫fork,現在有了子程序和父程序。

2. 父程序繼續處理client請求,子程序負責將記憶體內容寫入到臨時檔案。由於os的寫時複製機制(copy on write)父子程序會共享相同的物理頁面,當父程序處理寫請求時os會為父程序要修改的頁面建立副本,而不是寫共享的頁面。所以子程序的地址空間內的數 據是fork時刻整個資料庫的一個快照。

3.當子程序將快照寫入臨時檔案完畢後,用臨時檔案替換原來的快照檔案,然後子程序退出。

client 也可以使用save或者bgsave命令通知redis做一次快照持久化。save操作是在主執行緒中儲存快照的,由於redis是用一個主執行緒來處理所有 client的請求,這種方式會阻塞所有client請求。所以不推薦使用。另一點需要注意的是,每次快照持久化都是將記憶體資料完整寫入到磁碟一次,並不 是增量的只同步髒資料。如果資料量大的話,而且寫操作比較多,必然會引起大量的磁碟io操作,可能會嚴重影響效能。


另外由於快照方式是在一定間隔時間做一次的,所以如果redis意外down掉的話,就會丟失最後一次快照後的所有修改。如果應用要求不能丟失任何修改的話,可以採用aof持久化方式。下面介紹

Append-only file

aof 比快照方式有更好的持久化性,是由於在使用aof持久化方式時,redis會將每一個收到的寫命令都通過write函式追加到檔案中(預設是 appendonly.aof)。當redis重啟時會通過重新執行檔案中儲存的寫命令來在記憶體中重建整個資料庫的內容。當然由於os會在核心中快取 write做的修改,所以可能不是立即寫到磁碟上。這樣aof方式的持久化也還是有可能會丟失部分修改。不過我們可以通過配置檔案告訴redis我們想要 通過fsync函式強制os寫入到磁碟的時機。有三種方式如下(預設是:每秒fsync一次)


appendonly yes              //啟用aof持久化方式
# appendfsync always      //每次收到寫命令就立即強制寫入磁碟,最慢的,但是保證完全的持久化,不推薦使用
appendfsync everysec     //每秒鐘強制寫入磁碟一次,在效能和持久化方面做了很好的折中,推薦
# appendfsync no    //完全依賴os,效能最好,持久化沒保證

aof 的方式也同時帶來了另一個問題。持久化檔案會變的越來越大。例如我們呼叫incr test命令100次,檔案中必須儲存全部的100條命令,其實有99條都是多餘的。因為要恢復資料庫的狀態其實檔案中儲存一條set test 100就夠了。為了壓縮aof的持久化檔案。redis提供了bgrewriteaof命令。收到此命令redis將使用與快照類似的方式將記憶體中的資料 以命令的方式儲存到臨時檔案中,最後替換原來的檔案。具體過程如下

1. redis呼叫fork ,現在有父子兩個程序
2. 子程序根據記憶體中的資料庫快照,往臨時檔案中寫入重建資料庫狀態的命令
3.父程序繼續處理client請求,除了把寫命令寫入到原來的aof檔案中。同時把收到的寫命令快取起來。這樣就能保證如果子程序重寫失敗的話並不會出問題。
4.當子程序把快照內容寫入已命令方式寫到臨時檔案中後,子程序發訊號通知父程序。然後父程序把快取的寫命令也寫入到臨時檔案。
5.現在父程序可以使用臨時檔案替換老的aof檔案,並重命名,後面收到的寫命令也開始往新的aof檔案中追加。

需要注意到是重寫aof檔案的操作,並沒有讀取舊的aof檔案,而是將整個記憶體中的資料庫內容用命令的方式重寫了一個新的aof檔案,這點和快照有點類似。