天天看點

Redis實戰(11)進階特性(3)持久化

redis 是一個支援持久化的記憶體資料庫,也就是說redis 需要經常将記憶體中的資料同步到磁盤

來保證持久化。redis 支援兩種持久化方式,一種是Snapshotting(快照)也是預設方式,另

一種是Append-only file(縮寫aof)的方式。下面分别介紹:

一、snapshotting 方式

快照是預設的持久化方式。這種方式是就是将記憶體中資料以快照的方式寫入到二進制檔案中,

預設的檔案名為dump.rdb。可以通過配置設定自動做快照持久化的方式。

我們可以配置redis在n 秒内如果超過m 個key 被修改就自動做快照,

下面是預設的快照儲存配置

1

2

3

<code>save 900 1 </code><code>#900 秒内如果超過1 個key 被修改,則發起快照儲存</code>

<code>save 300 10 </code><code>#300 秒内容如超過10 個key 被修改,則發起快照儲存</code>

<code>save 60 10000</code>

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

1、redis 調用fork,現在有了子程序和父程序。

2.、父程序繼續處理client 請求,子程序負責将記憶體内容寫入到臨時檔案。由于os 的實時複

制機制(copy on write)父子程序會共享相同的實體頁面,當父程序處理寫請求時os 會為父

程序要修改的頁面建立副本,而不是寫共享的頁面。是以子程序位址空間内的資料是fork

時刻整個資料庫的一個快照。

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

client 也可以使用save 或者bgsave 指令通知redis 做一次快照持久化。save 操作是在主線程

中儲存快照的,由于redis 是用一個主線程來處理所有client 的請求,這種方式會阻塞所有

client 請求。是以不推薦使用。另一點需要注意的是,每次快照持久化都是将記憶體資料完整

寫入到磁盤一次,并不是增量的隻同步變更資料。如果資料量大的話,而且寫操作比較多,

必然會引起大量的磁盤io 操作,可能會嚴重影響性能。

下面将示範各種場景的資料庫持久化情況

首先在redis.conf配置檔案中配置log日志

<a href="http://blog.51cto.com/attachment/201312/204253940.png" target="_blank"></a>

然後我們進行如下操作:

<a href="http://blog.51cto.com/attachment/201312/203032247.png" target="_blank"></a>

檢視日志檔案

<a href="http://blog.51cto.com/attachment/201312/204220110.png" target="_blank"></a>

 從日志可以看出,資料庫做了一個存盤的操作,将記憶體的資料寫入磁盤了。正常的話,磁盤

上會産生一個dump 檔案,用于儲存資料庫快照,我們來驗證一下:

 硬碟上已經産生了一個資料庫快照了。這時侯我們再将redis 啟動,看鍵值還是否真的持久

化到硬碟了。

<a href="http://blog.51cto.com/attachment/201312/204449573.png" target="_blank"></a>

二、aof方式

另外由于快照方式是在一定間隔時間做一次的,是以如果redis 意外down 掉的話,就會丢

失最後一次快照後的所有修改。如果應用要求不能丢失任何修改的話,可以采用aof 持久化

方式。

下面介紹Append-only file:

aof 比快照方式有更好的持久化性,是由于在使用aof 持久化方式時,redis 會将每一個收到

的寫指令都通過write 函數追加到檔案中(預設是appendonly.aof)。當redis 重新開機時會通過重

新執行檔案中儲存的寫指令來在記憶體中重建整個資料庫的内容。

當然由于os 會在核心中緩存 write 做的修改,是以可能不是立即寫到磁盤上。這樣aof 方式的持久化也還是有可能會丢失部分修改。

不過我們可以通過配置檔案告訴redis 我們想要通過fsync 函數強制os 寫入

到磁盤的時機。有三種方式如下(預設是:每秒fsync 一次)

4

<code>appendonly </code><code>yes</code> <code>#啟用aof 持久化方式</code>

<code>appendfsync always </code><code>#收到寫指令就立即寫入磁盤,最慢,但是保證完全的持久化</code>

<code>appendfsync everysec </code><code>#每秒鐘寫入磁盤一次,在性能和持久化方面做了很好的折中</code>

<code>appendfsync no </code><code>#完全依賴os,性能最好,持久化沒保證</code>

接下來我們以執行個體說明用法:

修改配置檔案:

<a href="http://blog.51cto.com/attachment/201312/205352695.png" target="_blank"></a>

進行一下操作:

<a href="http://blog.51cto.com/attachment/201312/205201138.png" target="_blank"></a>

我們先設定2 個鍵值對,然後我們看一下系統中有沒有産生appendonly.aof 檔案

<a href="http://blog.51cto.com/attachment/201312/205455156.png" target="_blank"></a>

結果證明産生了,接着我們将redis 再次啟動後來看一下資料是否還在

<a href="http://blog.51cto.com/attachment/201312/205537863.png" target="_blank"></a>

資料還存在系統中,說明系統是在啟動時執行了一下從磁盤到記憶體的load 資料的過程。

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 檔案,這點和快照有點類似。接來我們看一下實際的例

子:

我們先調用5 次incr age 指令:

<a href="http://blog.51cto.com/attachment/201312/210429407.png" target="_blank"></a>

接下來我們看一下日志檔案的大小

<a href="http://blog.51cto.com/attachment/201312/210537573.png" target="_blank"></a>

大小為533 個位元組,接下來我們調用一下bgrewriteaof 指令将記憶體中的資料重新刷到磁盤的

日志檔案中

<a href="http://blog.51cto.com/attachment/201312/210706678.png" target="_blank"></a>

再看一下磁盤上的日志檔案大小

<a href="http://blog.51cto.com/attachment/201312/210751278.png" target="_blank"></a>

日志檔案大小變為84 個位元組了,說明原來日志中的重複記錄已被重新整理掉了。

本文轉自shayang8851CTO部落格,原文連結:http://blog.51cto.com/janephp/1340039,如需轉載請自行聯系原作者