眾所周知,redis是內存數據庫,它把數據存儲在內存中,這樣在加快讀取速度的同時也對數據安全性產生了新的問題,即當redis所在服務器發生宕機后,redis數據庫里的所有數據將會全部丟失。
為了解決這個問題,redis提供了持久化功能——RDB和AOF。通俗的講就是將內存中的數據寫入硬盤中。
一、持久化之全量寫入:RDB
[redis@6381]$ more /usr/local/redis/conf/redis.conf save 900 1 save 300 10 save 60 10000 dbfilename "dump.rdb" #持久化文件名稱 dir "/data/dbs/redis/6381" #持久化數據文件存放的路徑
上面是redis配置文件里默認的RDB持久化設置,前三行都是對觸發RDB的一個條件,例如第一行的意思是每900秒鍾里redis數據庫有一條數據被修改則觸發RDB,依次類推;只要有一條滿足就會調用BGSAVE進行RDB持久化。第四行dbfilename指定了把內存里的數據庫寫入本地文件的名稱,該文件是進行壓縮后的二進制文件,通過該文件可以把數據庫還原到生成該文件時數據庫的狀態。第五行dir指定了RDB文件存放的目錄。
配置文件修改需要重啟redis服務,我們還可以在命令行里進行配置,即時生效,服務器重啟后需重新配置
[redis@iZ254r8s3m6Z redis]$ bin/redis-cli 127.0.0.1:6379> CONFIG GET save #查看redis持久化配置 1) "save" 2) "900 1 300 10 60 10000" 127.0.0.1:6379> CONFIG SET save "21600 1000" #修改redis持久化配置 OK
而RDB持久化也分兩種:SAVE和BGSAVE
SAVE是阻塞式的RDB持久化,當執行這個命令時redis的主進程把內存里的數據庫狀態寫入到RDB文件(即上面的dump.rdb)中,直到該文件創建完畢的這段時間內redis將不能處理任何命令請求。
BGSAVE屬於非阻塞式的持久化,它會創建一個子進程專門去把內存中的數據庫狀態寫入RDB文件里,同時主進程還可以處理來自客戶端的命令請求。但子進程基本是復制的父進程,這等於兩個相同大小的redis進程在系統上運行,會造成內存使用率的大幅增加。
(本人在生產中就碰到過這問題,redis本身內存使用率就60%,總的內存使用率在百分之七八十左右,持久化的時候立馬飆到百分之一百三十多,告警郵件是每天幾十封/(ㄒoㄒ)/~~ 最后根據需求選擇了AOF持久化)
二、持久化之增量寫入:AOF
與RDB的保存整個redis數據庫狀態不同,AOF是通過保存對redis服務端的寫命令(如set、sadd、rpush)來記錄數據庫狀態的,即保存你對redis數據庫的寫操作,以下就是AOF文件的內容
1 [redis@iZ]$ more appendonly.aof 2 *2 3 $6 4 SELECT 5 $1 6 0 7 *3 8 $3 9 SET 10 $47 11 DEV_USER_LEGAL_F9683BE0E27F1A06C0CB869CEC7E3B22 12 $11 13 ¬ 14 *3 15 $3 16 SET 17 $47
先讓我們看看如何配置AOF
1 [redis@iZ]$ more ~/redis/conf/redis.conf 2 dir "/data/dbs/redis/6381" #AOF文件存放目錄 3 appendonly yes #開啟AOF持久化,默認關閉 4 appendfilename "appendonly.aof" #AOF文件名稱(默認) 5 appendfsync no #AOF持久化策略 6 auto-aof-rewrite-percentage 100 #觸發AOF文件重寫的條件(默認) 7 auto-aof-rewrite-min-size 64mb #觸發AOF文件重寫的條件(默認)
要弄明白上面幾個配置就得從AOF的實現去理解,AOF的持久化是通過命令追加、文件寫入和文件同步三個步驟實現的。當reids開啟AOF后,服務端每執行一次寫操作(如set、sadd、rpush)就會把該條命令追加到一個單獨的AOF緩沖區的末尾,這就是命令追加;然后把AOF緩沖區的內容寫入AOF文件里。看上去第二步就已經完成AOF持久化了那第三步是干什么的呢?這就需要從系統的文件寫入機制說起:一般我們現在所使用的操作系統,為了提高文件的寫入效率,都會有一個寫入策略,即當你往硬盤寫入數據時,操作系統不是實時的將數據寫入硬盤,而是先把數據暫時的保存在一個內存緩沖區里,等到這個內存緩沖區的空間被填滿或者是超過了設定的時限后才會真正的把緩沖區內的數據寫入硬盤中。也就是說當redis進行到第二步文件寫入的時候,從用戶的角度看是已經把AOF緩沖區里的數據寫入到AOF文件了,但對系統而言只不過是把AOF緩沖區的內容放到了另一個內存緩沖區里而已,之后redis還需要進行文件同步把該內存緩沖區里的數據真正寫入硬盤上才算是完成了一次持久化。而何時進行文件同步則是根據配置的appendfsync來進行:
appendfsync有三個選項:always、everysec和no:
1、選擇always的時候服務器會在每執行一個事件就把AOF緩沖區的內容強制性的寫入硬盤上的AOF文件里,可以看成你每執行一個redis寫入命令就往AOF文件里記錄這條命令,這保證了數據持久化的完整性,但效率是最慢的,卻也是最安全的;
2、配置成everysec的話服務端每執行一次寫操作(如set、sadd、rpush)也會把該條命令追加到一個單獨的AOF緩沖區的末尾,並將AOF緩沖區寫入AOF文件,然后每隔一秒才會進行一次文件同步把內存緩沖區里的AOF緩存數據真正寫入AOF文件里,這個模式兼顧了效率的同時也保證了數據的完整性,即使在服務器宕機也只會丟失一秒內對redis數據庫做的修改;
3、將appendfsync配置成no則意味redis數據庫里的數據就算丟失你也可以接受,它也會把每條寫命令追加到AOF緩沖區的末尾,然后寫入文件,但什么時候進行文件同步真正把數據寫入AOF文件里則由系統自身決定,即當內存緩沖區的空間被填滿或者是超過了設定的時限后系統自動同步。這種模式下效率是最快的,但對數據來說也是最不安全的,如果redis里的數據都是從后台數據庫如mysql中取出來的,屬於隨時可以找回或者不重要的數據,那么可以考慮設置成這種模式。
相比RDB每次持久化都會內存翻倍,AOF持久化除了在第一次啟用時會新開一個子進程創建AOF文件會大幅度消耗內存外,之后的每次持久化對內存使用都很小。但AOF也有一個不可忽視的問題:AOF文件過大。你對redis數據庫的每一次寫操作都會讓AOF文件里增加一條數據,久而久之這個文件會形成一個龐然大物。還好的是redis提出了AOF重寫的機制,即我們上面配置的auto-aof-rewrite-percentage和auto-aof-rewrite-min-size。AOF重寫機制這里暫不細述,之后本人會另開博文對此解釋,有興趣的同學可以看看。我們只要知道AOF重寫既是重新創建一個精簡化的AOF文件,里面去掉了多余的冗余命令,並對原AOF文件進行覆蓋。這保證了AOF文件大小處於讓人可以接受的地步。而上面的auto-aof-rewrite-percentage和auto-aof-rewrite-min-size配置觸發AOF重寫的條件。
Redis 會記錄上次重寫后AOF文件的文件大小,而當前AOF文件大小跟上次重寫后AOF文件大小的百分比超過auto-aof-rewrite-percentage設置的值,同時當前AOF文件大小也超過auto-aof-rewrite-min-size設置的最小值,則會觸發AOF文件重寫。以上面的配置為例,當現在的AOF文件大於64mb同時也大於上次重寫AOF后的文件大小,則該文件就會被AOF重寫。
最后需要注意的是,如果redis開啟了AOF持久化功能,那么當redis服務重啟時會優先使用AOF文件來還原數據庫。
