前面咱們說過,Redis 相對於 Memcache 等其餘的緩存產品,有一個比較明顯的優點就是 Redis 不只僅支持簡單的key-value類型的數據,同時還提供list,set,zset,hash等數據結構的存儲。這幾種豐富的數據類型咱們花了兩篇文章進行了詳細的介紹,接下來咱們要介紹 Redis 的另一大優點——持久化。html
因爲 Redis 是一個內存數據庫,所謂內存數據庫,就是將數據庫中的內容保存在內存中,這與傳統的MySQL,Oracle等關係型數據庫直接將內容保存到硬盤中相比,內存數據庫的讀寫效率比傳統數據庫要快的多(內存的讀寫效率遠遠大於硬盤的讀寫效率)。可是保存在內存中也隨之帶來了一個缺點,一旦斷電或者宕機,那麼內存數據庫中的數據將會所有丟失。redis
爲了解決這個缺點,Redis提供了將內存數據持久化到硬盤,以及用持久化文件來恢復數據庫數據的功能。Redis 支持兩種形式的持久化,一種是RDB快照(snapshotting),另一種是AOF(append-only-file)。本篇博客先對 RDB 快照進行介紹。算法
RDB是Redis用來進行持久化的一種方式,是把當前內存中的數據集快照寫入磁盤,也就是 Snapshot 快照(數據庫中全部鍵值對數據)。恢復時是將快照文件直接讀到內存裏。數據庫
RDB 有兩種觸發方式,分別是自動觸發和手動觸發。數組
在 redis.conf 配置文件中的 SNAPSHOTTING 下,在這篇文章中咱們介紹過。緩存
①、save:這裏是用來配置觸發 Redis的 RDB 持久化條件,也就是何時將內存中的數據保存到硬盤。好比「save m n」。表示m秒內數據集存在n次修改時,自動觸發bgsave(這個命令下面會介紹,手動觸發RDB持久化的命令)服務器
默認以下配置:數據結構
save 900 1:表示900 秒內若是至少有 1 個 key 的值變化,則保存 save 300 10:表示300 秒內若是至少有 10 個 key 的值變化,則保存 save 60 10000:表示60 秒內若是至少有 10000 個 key 的值變化,則保存
固然若是你只是用Redis的緩存功能,不須要持久化,那麼你能夠註釋掉全部的 save 行來停用保存功能。能夠直接一個空字符串來實現停用:save ""app
②、stop-writes-on-bgsave-error :默認值爲yes。當啓用了RDB且最後一次後臺保存數據失敗,Redis是否中止接收數據。這會讓用戶意識到數據沒有正確持久化到磁盤上,不然沒有人會注意到災難(disaster)發生了。若是Redis重啓了,那麼又能夠從新開始接收數據了異步
③、rdbcompression ;默認值是yes。對於存儲到磁盤中的快照,能夠設置是否進行壓縮存儲。若是是的話,redis會採用LZF算法進行壓縮。若是你不想消耗CPU來進行壓縮的話,能夠設置爲關閉此功能,可是存儲在磁盤上的快照會比較大。
④、rdbchecksum :默認值是yes。在存儲快照後,咱們還可讓redis使用CRC64算法來進行數據校驗,可是這樣作會增長大約10%的性能消耗,若是但願獲取到最大的性能提高,能夠關閉此功能。
⑤、dbfilename :設置快照的文件名,默認是 dump.rdb
⑥、dir:設置快照文件的存放路徑,這個配置項必定是個目錄,而不能是文件名。默認是和當前配置文件保存在同一目錄。
也就是說經過在配置文件中配置的 save 方式,當實際操做知足該配置形式時就會進行 RDB 持久化,將當前的內存快照保存在 dir 配置的目錄中,文件名由配置的 dbfilename 決定。
手動觸發Redis進行RDB持久化的命令有兩種:
一、save
該命令會阻塞當前Redis服務器,執行save命令期間,Redis不能處理其餘命令,直到RDB過程完成爲止。
顯然該命令對於內存比較大的實例會形成長時間阻塞,這是致命的缺陷,爲了解決此問題,Redis提供了第二種方式。
二、bgsave
執行該命令時,Redis會在後臺異步進行快照操做,快照同時還能夠響應客戶端請求。具體操做是Redis進程執行fork操做建立子進程,RDB持久化過程由子進程負責,完成後自動結束。阻塞只發生在fork階段,通常時間很短。
基本上 Redis 內部全部的RDB操做都是採用 bgsave 命令。
ps:執行執行 flushall 命令,也會產生dump.rdb文件,但裏面是空的,無心義
將備份文件 (dump.rdb) 移動到 redis 安裝目錄並啓動服務便可,redis就會自動加載文件數據至內存了。Redis 服務器在載入 RDB 文件期間,會一直處於阻塞狀態,直到載入工做完成爲止。
獲取 redis 的安裝目錄可使用 config get dir 命令
有些狀況下,咱們只想利用Redis的緩存功能,並不像使用 Redis 的持久化功能,那麼這時候咱們最好停掉 RDB 持久化。能夠經過上面講的在配置文件 redis.conf 中,能夠註釋掉全部的 save 行來停用保存功能或者直接一個空字符串來實現停用:save ""
也能夠經過命令:
redis-cli config set save " "
①、優點
1.RDB是一個很是緊湊(compact)的文件,它保存了redis 在某個時間點上的數據集。這種文件很是適合用於進行備份和災難恢復。
2.生成RDB文件的時候,redis主進程會fork()一個子進程來處理全部保存工做,主進程不須要進行任何磁盤IO操做。
3.RDB 在恢復大數據集時的速度比 AOF 的恢復速度要快。
②、劣勢
一、RDB方式數據沒辦法作到實時持久化/秒級持久化。由於bgsave每次運行都要執行fork操做建立子進程,屬於重量級操做(內存中的數據被克隆了一份,大體2倍的膨脹性須要考慮),頻繁執行成本太高(影響性能)
二、RDB文件使用特定二進制格式保存,Redis版本演進過程當中有多個格式的RDB版本,存在老版本Redis服務沒法兼容新版RDB格式的問題(版本不兼容)
三、在必定間隔時間作一次備份,因此若是redis意外down掉的話,就會丟失最後一次快照後的全部修改(數據有丟失)
Redis有個服務器狀態結構:
struct redisService{ //一、記錄保存save條件的數組 struct saveparam *saveparams; //二、修改計數器 long long dirty; //三、上一次執行保存的時間 time_t lastsave; }
①、首先看記錄保存save條件的數組 saveparam,裏面每一個元素都是一個 saveparams 結構:
struct saveparam{ //秒數 time_t seconds; //修改數 int changes; };
前面咱們在 redis.conf 配置文件中進行了關於save 的配置:
save 900 1:表示900 秒內若是至少有 1 個 key 的值變化,則保存 save 300 10:表示300 秒內若是至少有 10 個 key 的值變化,則保存 save 60 10000:表示60 秒內若是至少有 10000 個 key 的值變化,則保存
那麼服務器狀態中的saveparam 數組將會是以下的樣子:
②、dirty 計數器和lastsave 屬性
dirty 計數器記錄距離上一次成功執行 save 命令或者 bgsave 命令以後,Redis服務器進行了多少次修改(包括寫入、刪除、更新等操做)。
lastsave 屬性是一個時間戳,記錄上一次成功執行 save 命令或者 bgsave 命令的時間。
經過這兩個命令,當服務器成功執行一次修改操做,那麼dirty 計數器就會加 1,而lastsave 屬性記錄上一次執行save或bgsave的時間,Redis 服務器還有一個週期性操做函數 severCron ,默認每隔 100 毫秒就會執行一次,該函數會遍歷並檢查 saveparams 數組中的全部保存條件,只要有一個條件被知足,那麼就會執行 bgsave 命令。
執行完成以後,dirty 計數器更新爲 0 ,lastsave 也更新爲執行命令的完成時間。