何為AOF?
在Redis設定檔中有一個叫appendonly的選項,可以寫yes或no.這個選項就是負責是否開啟AOF日誌的開關.AOF日誌,你可以簡單理解為MySQL binlog一樣的東西,作用就是記錄每次的寫操作,在遇到斷電等問題時可以用它來恢複資料庫狀態.但是他不是bin的,而是text的.一行一行,寫得很規範.如果你是一台redis,那你也能人肉通過它恢複資料.
擴充知識:
Redis有三種類型的落地檔案: 資料檔案-在配置中可設定其位置及檔案名稱,預設檔案名稱dump.rdb 記錄檔-在配置中也可以配置.當然,在你是以daemon方式啟動並執行時候,這個值就不要設定為stdout了,這麼設定會自動被換成/dev/null AOF檔案-也就是我們這篇文章的主角,他的作用是用於資料恢複.他除了設定是否開啟外,還可以設定開啟後以何種方式寫日誌.這個何種一共是三種,1是每次寫操作都保證將fsync()來完成的,2是每秒調用一次fsync(),3是從不調用,讓作業系統自己來同步.當然,設定為不同,效率會不同,你的資料損失風險也不同.
運行流程
既然是log檔案,而且是要用於恢複的,那麼我們動動腳趾都能想到,這玩意肯定會越來越大,不管你的應用是大是小,如果AOF檔案只增不減的話,那檔案將會無限長大,這個問題是所有binlog都會遇到的.而通常遇到這種問題都會有一個rotate方案.就是當日誌達到一定大小或者每隔一段時間將日誌寫到新的一個檔案中,舊記錄檔可以用來備份或其它.
而Redis的AOF還和rotate略有不同,他用了一種比較簡單的方法,就是先給當前的所有資料做一個快照.然後再在這個快照的基礎上寫接下來的日誌.
照快照的好處是,你之前可能用了10w次操作共改變了100條資料(比如在一條資料上進行了多次操作).那這時你AOF中的10w條寫操作記錄就變成了100條記錄.相當於將前面的執行全部合并了.原本很大AOF變小了.
執行這個操作的命令是:BGREWRITEAOF (background rewrite append only file)
這個快照長什麼樣呢?基本和一般的寫日誌沒什麼兩樣,也是一條一條的寫記錄..比如現在Redis中總共存了3條string類型的資料a=>1,b=>2,c=>3.那這個快照的基本內容就是寫入a=>1,寫入b=>2,寫入c=>3.
這時候要用AOF進行恢複的時候,只要先執行了前面幾條,就能夠恢複目前狀態,然後再執行之後來的寫操作,就能完全重現資料了.
內部實現
我們大概知道了執行BGREWRITEAOF時都發生了什麼,下面來說一下Redis是如何?的.分下面幾步: fork! Redis通過fork產生子進程. 子進程對當前資料執行遍曆操作,將當前所有資料都產生一條寫入日誌,將這些日誌寫入一個臨時檔案.(其實是子進程寫了一個臨時檔案,又再rename成了另一個臨時檔案) 父子進程是並存執行的,在子進程遍曆並寫臨時檔案的時候,父進程在照常接收請求,處理請求,寫AOF,不過這時他是把新來的AOF寫在一個緩衝區中. 當子進程完成遍曆操作,寫完臨時檔案後,就會退出.這時父進程的wait3函數會接收到子進程退出的訊息,他會把自己現在收集在緩衝區中的所有AOF追加在臨時檔案中. 最後一步,把臨時檔案rename一下,改名為appendonly.aof,這時原來的aof檔案被覆蓋.整個過程完成.
如果你的AOF檔案稍微大點,你可以在一個終端執行BGREWRITEAOF,然後立刻ls 連著查看幾次redis的data目錄,就可以看到,先產生了一個臨時檔案,臨時檔案比原來的appendonly.aof小一些,然後臨時檔案消失,而原來的appendonly.aof變小了,其實就是臨時檔案rename成了appendonly.aof..覆蓋了原來的大檔案.看起來像是臨時檔案消失了.