redis的aof持久化深入解析

來源:互聯網
上載者:User
Redis提供兩種持久化方式,RDB和AOF;與RDB不同,AOF可以完整的記錄整個資料庫,而不像RDB只是資料庫某一時刻的快照; 

那麼AOF模式為什麼可以完整的記錄整個資料庫呢。  

原理 :在AOF模式下,Redis會把執行過的每一條更新命令記錄下來,儲存到AOF檔案中;當Redis需要恢複資料庫資料時,只需要從之前儲存的AOF檔案中依次讀取命令,執行即可 eg. 

Shell代碼   我們執行了以下命令:   redis 127.0.0.1:6379> set name diaocow   OK   redis 127.0.0.1:6379> lpush country china usa   (integer) 4      這時候在AOF檔案中的類容類似下面:   *3\r\n$3\r\nset\r\n$4\r\nname\r\n$7\r\ndiaocow\r\n   *4\r\n$5\r\nlpush\r\n$7\r\ncountry\r\n$5\r\nchina\r\n$3\r\nusa\r\n  
看了上面的內容,我想不用我過多解釋,你也能大致猜出AOF協議格式,因為它實在太簡單明了了 

Redis把更新命令記錄到AOF檔案,分為兩個階段:  

階段1:把更新命令寫入aof緩衝 





Python代碼   def processCommand(cmd, argc, argv):       # 執行命令       call(cmd, argc, argv)       # 該命令變更了鍵空間並且AOF模式開啟       if redisServer.update_key_space and redisServer.aof_state & REDIS_AOF_ON:           feedAppendOnlyFile(cmd, argc, argv)       def feedAppendOnlyFile(cmd, argc, argv):       # 把命令轉換成AOF協議格式       aofCmdStr = getAofProtocolStr(cmd, argc, argv)       redisServer.aof_buf.append(aofCmdStr )          # 存在一個子進程進行中AOF_REWRITE(關於AOF_REWRITE,稍後詳說)       if redisServer.aof_child_pid != -1:           redisServer.aof_rewrite_buf_blocks.append(aofCmdStr )  
階段2: 把aof緩衝寫入檔案 

當我們開始下一次 事件迴圈 之前,redis會把AOF緩衝中的內容寫入到檔案: 
Python代碼   def flushAppendOnlyFile(force):         if len(redisServer.aof_buf) == 0:           return       # 把快取資料寫入檔案         if writeByPolicy(force, redisServer.aof_fsync):              write(redisServer.aof_fd, redisServer.aof_buf, len(redisServer.aof_buf))          # 同步資料到硬碟         if fsyncByPolicy(force, redisServer.aof_fsync):             fsync(redisServer.aof_fd)   
更多細節請看: aof.c/flushAppendOnlyFile函數 (ps: 這個函數代碼看起來比較晦澀) 

看到這裡,你也許會有兩個疑問:  
1. 為什麼要調用fsync函數,不是已經調用write把資料寫入到檔案了嗎。 
2. 虛擬碼中aof_fsync是什麼,它有幾種類型。 

首先回答問題1,為什麼寫入檔案後,還要調用fsync函數: 
大多數unix系統為了減少磁碟IO,採用了“延遲寫”技術,也就是說當我們執行完write調用後,資料並不一定立馬被寫入磁碟(可能還是保留在系統的buffer cache或者page cache中),這樣當主機突然斷電,這些我們本以為已經寫入到磁碟檔案的資料可能就會丟失;所以當我們需要確保資料被完整正確的寫入磁碟(譬如資料庫的持久化),則需要調用同步函數fsync,它會一直阻塞直到資料全部被寫入到硬碟 

問題2,aof_fysnc是什麼: 
aof_fsync用來指定flush策略,也就是調用fsync函數的策略,它一共有三種: 
a. AOF_FSYNC_NO :每次都會把aof_buf中的內容寫入到磁碟,但是不會調用fsync函數; 
b. AOF_FSYNC_ALWAYS :每次都會把aof_buf中的內容寫入到磁碟,同時調用fsync函數; 
c. AOF_FSYNC_EVERYSEC 

由於AOF_FSYNC_ALWAYS每次都寫入檔案都會調用fsync,所以這種flush策略可以保證資料的完整性,缺點就是效能太差(因為fysnc是個同步調用,會阻塞主進程對用戶端請求的處理),而AOF_FSYNC_NO由於依賴於作業系統自動sync,因此不能保證資料的完整性; 

那有沒有一種折中的方式:既能不過分降低系統的效能,又能最大程度上的保證資料的完整性,答案就是:AOF_FSYNC_EVERYSEC,AOF_FSYNC_EVERYSEC的flush策略是:定期(至少1s)去調用fsync,並且該操作是放到一個非同步隊列中(線程)去執行,因此不會阻塞主進程 


AOF 後台執行的方式和 RDB 有類似的地方,fork 一個子進程,主進程仍進行服務,子進程執行 AOF 持久化,資料被 dump 到磁碟上。與 RDB 不同的是,後檯子進程持久化過程中,主進程會記錄期間的所有資料變更(主進程還在服務),並儲存在 server.aof_rewrite_buf_blocks 中;後檯子進程結束後,redis 更新緩衝追加到 AOF 檔案中,是 RDB 持久化所不具備的.


AOF模式至此我們已經基本說完,但是隨著Redis運行,AOF檔案會變得越來越大(在業務高分期增長的更快),原因有兩個 : 
a. AOF協議本身是文本協議,比較占空間; 
b. Redis需要記錄從開始到現在的所有更新命令; 

這兩個原因導致了AOF檔案容易變得很大,那有什麼方式可以最佳化嗎。譬如使用者執行了三個命令:lpush name diaocow; lpush name jack; lpush name jobs 
AOF檔案會記錄以下資料: 
Aof_file代碼   *3\r\n$5\r\nlpush\r\n$4\r\nname\r\n$7\r\ndiaocow   *3\r\n$5\r\nlpush\r\n$4\r\nname\r\n$4\r\njack   *3\r\n$5\r\nlpush\r\n$4\r\nname\r\n$4\r\njobs  
但其實只需要記錄一條:lpush name diaocow jack jbos 命令即可: 
Aof_file代碼   *5\r\n$5\r\nlpush\r\n$4\r\nname\r\n$7\r\ndiaocow\r\n$4\r\njack\r\n$4\r\njobs  
所以當AOF檔案達到 REDIS_AOF_REWRITE_MIN_SIZE(1M)時,Redis就會執行AOF_REWRITE來最佳化AOF檔案; 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.