天天看點

redis的AOF和RDB持久化方式

AOF

AOF是寫後日志,mysql在寫資料前會先寫redo log,而redis會先寫資料,再寫AOF日志。AOF的寫入是在主程序當中完成的。

為什麼先寫入指令,再寫AOF緩沖呢?原因是redis在寫日志時不會進行文法檢查,是以要先等待寫資料的執行結果,如果寫資料的執行結果正确,再将日志寫入AOF中。

AOF存在的風險:

如果寫完資料,還沒來得及寫日志伺服器就挂掉了,此時這個指令的AOF日志就丢失了,使用AOF恢複資料就會丢失。

AOF的三種寫入政策:

同步寫回:每一個更新資料的指令執行完,立刻将日志寫入磁盤。

每秒寫回:更新資料的指令執行完後,先将日志寫入到緩沖區中,每隔一秒将資料刷入磁盤。

系統控制:不可控,由作業系統決定何時将AOF緩沖區的資訊刷入磁盤。

同步寫回基本可以做到資料不丢失,但是對性能的影響非常大,會減慢業務的執行。

每秒寫回是折中方案,也是最适合的方案,既減輕了redis寫日志的壓力,也能保證資料的安全性。一秒内的資料可能發生丢失。

系統控制就是将控制權完全交給了作業系統,會丢失多少資料,我們完全是不可控的。

AOF存在的問題,不斷的寫AOF日志,會造成AOF檔案特别大。檔案大了之後,繼續寫AOF的效率會變低,同時作業系統裡的檔案系統對檔案的大小也有限制,可能無法儲存很大的檔案。而且如果AOF檔案特别大,使用AOF恢複資料時也會非常慢,這該怎麼辦呢?

為了解決這個問題,redis有AOF重寫機制!

簡單來說,AOF的重寫機制,就是讓記錄的指令從多變一。

因為AOF會記錄每一條對資料修改的指令,例如 set k1 zhangsan set k1 lisi set k1 wangwu,是以AOF檔案中會記錄三條這樣的指令。在重寫後,AOF隻會記錄對資料最後一次的更改!也就是根據鍵值對最新的狀态,生成寫入的指令。

AOF的重寫過程是由背景的子程序來完成的,主要是為了避免主程序的堵塞,fork出來的子程序,和父程序映射的記憶體是同一塊,背景子程序就可以在不影響主程序的情況下,将redis中的資料記錄成寫操作,寫入新的AOF檔案中。

redis會建立一個新的AOF檔案,讀取資料庫目前的鍵值對,根據鍵值對資訊生成每一個鍵值對對應的寫入指令。

由于主程序并沒有被堵塞,是以主程序任然會執行新的指令,這些新的操作也會記錄到重寫日志中。

AOF重寫的觸發條件:

通過配置檔案設定AOF的最大大小,當寫入的資料大于了這個設定的大小,就會觸發重寫機制。

RDB

AOF檔案記錄的是對所有key的修改操作,使用AOF恢複資料時,需要将這些指令全部執行一遍,如果AOF日志檔案過大,會造成指令的執行非常漫長,嚴重影響目前redis的使用。

是以Redis還有另外一種資料恢複的方式,RDB

RDB相當于是給記憶體建立了一張快照,記錄了記憶體某一個時間點的所有資訊,将這些資訊寫入到磁盤,是以,RDB是基于二進制資料直接進行的恢複,不需要執行指令,恢複速度很快(直接将這個檔案的資訊讀入記憶體,當然快了)這個快照檔案,就稱為RDB檔案

RDB的寫入提供了兩種方式。

1、使用save,在主程序中執行,會堵塞目前指令的執行。

2、使用bgsave,建立一個子程序,專門用來寫入RDB檔案,這是預設的執行方式。

如果使用的是bgsave,那麼在子程序寫入RDB檔案的過程中,如果redis中的key已經發生了更改,會怎麼樣呢?

這就利用了作業系統的讀時共享、寫時複制技術,父程序可以正常的執行寫指令,父程序會重新找一塊實體記憶體進行映射,将要更改的資料重新映射到一塊新的實體記憶體區域。此時子程序不受任何影響,任然可以對之前的資料進行寫入,隻不過寫入的是更改之前的資料。

做全量快照的政策是什麼呢?

肯定不能頻繁的去做全量快照,因為fork必然會導緻子程序拷貝父程序的頁目錄項和頁表資訊,如果父程序占用的記憶體非常大,拷貝頁表資訊是非常耗時的,會造成一定時間的堵塞。

同時,如果頻繁的進行全量快照,會對磁盤帶寬的壓力非常大,可能上一次fork的子程序還沒有完成RDB檔案的生成,下一個子程序又開始進行資料快照的操作了。

redis采用的方式是,使用增量快照的方法。

增量快照:在執行一次全量快照後,後續的快照隻需要對修改的資料進行快照記錄。

redis的快照寫入政策,當一定的時間内發生了多少個key的修改,對這些修改的key進行快照。

redis在進行RDB持久化時,會建立一個臨時檔案寫入更改的鍵值對。

建立臨時檔案的原因有兩個方面

1、如果操作的是一個檔案,會造成競争冒險的問題,必然要引入程序之間的互斥操作,嚴重影響性能。

2、如果操作的是原RDB檔案,如果在寫入的過程中redis崩潰了,那整個RDB檔案就被污染了。