天天看點

Redis(四):持久化之---AOF持久化的配置和原理

AOF持久化及AOF重寫的配置:

預設AOF方式是關閉的,如下圖:

<a href="http://s3.51cto.com/wyfs02/M02/83/FA/wKiom1eCXvyjrKL6AAFSGLyzA5Q846.jpg-wh_500x0-wm_3-wmp_4-s_509066519.jpg" target="_blank"></a>

如果要開啟的話,就是把no改寫成yes。如下圖:

<a href="http://s2.51cto.com/wyfs02/M00/83/F9/wKioL1eCXwSTC5H8AAAkOy29djo700.jpg-wh_500x0-wm_3-wmp_4-s_2584521239.jpg" target="_blank"></a>

預設檔案名稱appendonly.aof,你也可以修改檔案名。預設儲存目錄同樣也是配置檔案中dir配置項中的設定,它和RDB共用一個目錄。如下圖:

<a href="http://s1.51cto.com/wyfs02/M00/83/FA/wKiom1eCXwzzL43_AAAgurUvs48363.jpg-wh_500x0-wm_3-wmp_4-s_2526173145.jpg" target="_blank"></a>

預設同步政策是每秒,如下圖:

<a href="http://s5.51cto.com/wyfs02/M01/83/F9/wKioL1eCXx3BezMBAAAheXW2VM4565.jpg-wh_500x0-wm_3-wmp_4-s_3958770979.jpg" target="_blank"></a>

我們對資料庫做一些操作然後檢視一下appendonly.aof檔案内容

<a href="http://s5.51cto.com/wyfs02/M01/83/FA/wKiom1eCXyWjnzxMAAAtqM_jRwI519.jpg-wh_500x0-wm_3-wmp_4-s_5363823.jpg" target="_blank"></a>

它會記錄所有寫操作内容。

*2

表示2個參數

$6

表示第一個參數長度為6

SELECT

第一個參數

$1

第二個參數長度為1

第二個參數

AOF重寫政策

<a href="http://s1.51cto.com/wyfs02/M01/83/F9/wKioL1eCX-mD8Dx5AAFihO2iDMI666.jpg-wh_500x0-wm_3-wmp_4-s_768535899.jpg" target="_blank"></a>

AOF持久化實作原理:

當AOF持久化開啟後,當對資料庫進行一次更新操作後,更新指令就會被追加到aof_buf緩沖區的末尾,然後由緩沖區寫入到AOF檔案。

AOF檔案中記錄的内容就是對資料更新操作的指令。這個檔案本身就是以文本來記錄的,如下圖:

<a href="http://s5.51cto.com/wyfs02/M01/83/FA/wKiom1eCYBnzWFM3AAAtqM_jRwI354.jpg-wh_500x0-wm_3-wmp_4-s_628753289.jpg" target="_blank"></a>

當需要恢複資料的時候,通過執行AOF檔案中記錄的更新指令,就可以完成。人為的看裡面的指令,然後手動敲指令也可以完成。

AOF重寫實作原理:

因為AOF持久化是通過記錄指令的方式來儲存資料庫狀态的,随着時間的推移AOF檔案肯定會逐漸增大,如果不加以控制會對AOF持久化性能以及資料恢複造成影響。下面舉例來更加形象的說明重寫的必要:

我們以一個壓縮清單為例

<a href="http://s5.51cto.com/wyfs02/M02/83/FA/wKiom1eCYFfg-vTCAAB-iEt0rmQ375.jpg-wh_500x0-wm_3-wmp_4-s_3591693912.jpg" target="_blank"></a>

根據AOF的原理,那麼上面紅色方框中的5條指令都要追加到AOF檔案中,其實我們看到最後list的狀态就是BCDEF值。也就是說為例實作最後的狀态,需要追加5條指令。是以在大量記憶體讀寫的業務裡AOF檔案增長的很快,為例解決這個問題,Redis提供了AOF重寫功能。

AOF重寫就是建立一個新的AOF檔案來替換現有的AOF檔案,實際上AOF重寫并不對現有的舊AOF檔案進行操作。

以上面例子來說,當進行重寫的時候直接從資料庫裡去擷取list的最新狀态,然後在新的AOF檔案中直接寫一條rpushlist B C D E F指令,進而避免寫5條的操作,這樣AOF檔案的增長速度就會降低,同時容量也不會特别大。

AOF重寫程式aof_rewrite函數去完成建立新的AOF檔案的任務,但是該函數并不會由Redis主程序去直接調用,而是使用子程序背景去執行(BGREWRITEAOF,該指令其實就是執行aof_rewrite,隻不過是由子程序去調用的),這時主程序就會不被阻塞,那麼就可以在執行重寫的過程中父程序可以繼續對外提供響應。整個過程如下:

當重寫被觸發時父程序調用一個函數,該函數建立一個子程序用于執行BGREWRITEAOF,該子程序建立一個臨時檔案,然後父程序繼續對外提供讀寫服務

子程序周遊資料庫,将每個鍵值的最新狀态輸出到臨時檔案中,在BGREWRITEAOF過程中,父程序把所有對資料庫的更新指令同時寫入到AOF緩沖區和AOF重寫緩沖區(aof_rewrite_buf_blocks),AOF緩沖區(aof_buf)會繼續同步到現有AOF檔案中(一般情況下在AOF重寫期間不建議把AOF緩沖區的内容同步到現有的AOF檔案中,這會降低性能,預設為NO)

AOF重寫完成後子程序通知父程序,父程序調用信号處理函數

信号處理函數會阻塞父程序對外提供讀寫操作(時間很短,不阻塞就又會出現資料不一緻的情況),然後将AOF重寫緩沖區的内容寫入到新的AOF檔案中,最後用新的AOF檔案替換現有AOF檔案(更名操作)

APPENDFSYNC選項說明:

參數

說明

always

将aof_buf緩沖區中的所有内容寫入并同步到AOF檔案中,立即執行write()和fsync()系統調用。對于資料的安全性最高,但是執行最慢,如果出現故障隻會丢失一個事件循環的内容。

everysec

将aof_buf緩沖區的所有内容寫入到AOF檔案,如果上次同步AOF的時間距離本次超過1秒,則執行同步,每隔一秒執行一次write()和fsync()系統調用。資料安全性居中,執行快,僅會丢失1秒的資料。

no

将aof_buf緩沖區的所有内容寫入到AOF檔案,但是何時同步由作業系統決定,僅執行write()系統調用。寫入動作效率高,但是不執行同步,但是單次同步消耗時間最長,資料安全性最低,會丢失上一次同步之後的所有資料。

這裡要特别說明一下Linux系統的檔案寫入和同步原理,為什麼要說這個,因為不解釋一下這個過程,你就很難了解APPENDFSYNC選項中的no參數,如果把Always了解為總是、一直或者實時;而把everysec了解為每秒的話,那no的含義難道是不執行AOF檔案同步嗎?如果不同步檔案,那開啟AOF持久化幹嘛呢?

在Redis調用appendfsync函數的時候,其實是先調用一個write()函數,然後再調用sync()或者fsync()函數(對于任何程式來說隻要想把資料寫入磁盤其過程都一樣,有些也有例外)。

使用者空間:正常程序所在區域,使用者發起的,此區域的代碼不能直接通路硬體

核心空間:作業系統所在區域,能和裝置控制器通訊

當調用了write()函數時,該函數一旦傳回正常值,我們可能就認為資料已經寫入到了磁盤,但實際上,作業系統在實作磁盤檔案的IO時,為了保證IO的效率,會在記憶體中使用一段專門的位址空間,該空間叫做核心空間,而核心空間之内又會有一段是用作IO的資料緩沖區(這個緩沖區和之前說的aof_buf緩沖區不是一個概念,雖然都在記憶體中),write()函數的作用就是把資料寫入到核心空間的IO緩沖區中。

<a href="http://s1.51cto.com/wyfs02/M00/83/F9/wKioL1eCYaiDhKUNAABora4npp4231.jpg" target="_blank"></a>

核心空間的IO緩沖區也有一定大小,當該緩沖區沒有寫滿時或者沒有到一個同步周期時,會持續的把write()函數傳遞的資料寫入到該緩沖區中,而當該緩沖區寫滿或者到了一個同步周期,則會把該緩沖區的内容送出到輸出隊列,當需要資料到達隊列隊首的時候,開始執行真正的磁盤IO操作,把資料寫入磁盤(這裡雖然用來寫入磁盤,但是真正的動作不是移動而是複制,複制完成之後,核心空間的IO緩沖區才會釋放該資料占用的空間)。這種方式叫做延遲寫入。

是以這就會出現一個問題,當調用了write()函數後并不等于資料真的儲存到了磁盤,但是這裡又會有一個錯覺,就是你再次請求該檔案的時候,可以顯示你最後一次更新的内容,其實這個内容并不是從磁盤上讀取過來的,而是從使用者空間的緩沖區讀取的。接着剛才提到的問題,如果資料在核心空間的IO緩沖區内,而此時作業系統出現故障、斷電等異常情況就會造成資料丢失。

為了解決資料丢失問題,Unix系統提供了sync、fsync和fdatasync三個函數。

函數

功能

sync

函數傳回0表示成功,該函數負責把所有核心空間中IO緩沖區内修改過的内容推送到輸入隊列,然後就傳回,它并不等待所有磁盤IO操作完成。是以即使調用了sync函數,也不等于成功儲存到磁盤了。

fsync

函數傳回0表示成功,與sync不同,它隻會對指定檔案描述符的單一檔案生效,強制與該檔案相連的所有修改過的資料傳送到磁盤上,并且等待磁盤IO完畢,然後傳回。當該函數傳回0時,才真正表示成功儲存到磁盤。資料庫會在調用了write()之後調用fsync()。

fdatasync

它與fsync類似,它隻影響檔案資料部分,不涉及資料屬性,比如inode資訊。是以相對于fsync它需要較少的寫磁盤操作。

是以看了上面的内容,你就知道APPENDFSYNC中no參數的含義.

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