很簡單,由於 Redis
是基於內存的。數據若是不進行持久化,當服務器重啓或者宕機的時候數據是沒法恢復的,因此爲了保證數據的安全性,咱們須要將內存中的數據持久化到磁盤中。安全
Redis
提供了兩種持久化的方式,分別是 RDB
和 AOF
。服務器
Redis
的默認持久化方式,是基於 快照 來實現的,當符合必定條件的時候 Redis
會自動將內存中的數據進行快照而後持久化到磁盤中。Redis
默認沒有開啓 AOF
持久化,須要在配置文件中設置 appendonly true
開啓。它存儲的是 Redis
的 順序指令序列 。在 Redis
中有一個命令能夠觸發 RDB
持久化,可是這個操做會阻塞 Redis
。數據結構
這個命令是 save
,咱們都知道 Redis
是單線程的,若是持久化進行 特殊的處理 的話,那麼就會阻塞其餘命令致使 Redis
短期內不可用,若是 RDB
文件很大,那麼刷盤操做將會數十秒,嚴重影響可用性,因此咱們通常都不會使用 save
命令。app
bgsave
顧名思義,就是 後臺進行保存 。當執行這條命令的時候 Redis
就會進行一些 特殊處理 。函數
什麼特殊處理呢?post
首先 Redis
的主進程會調用 glibc
的函數 fork
產生一個子進程,此時會將文件 持久化所有交給子進程去處理,那麼這時父進程就能夠繼續處理用戶的請求了(bgsave
執行以後直接會返回)。固然,在主進程進行 fork
操做的時候可能也會對用戶請求命令 產生短暫的阻塞 。性能
凡事有利必有弊,你看 bgsave
這麼好,難道沒有缺點麼? 答案是有的,在哪呢?咱們先來了解一下 COW 機制吧。spa
COW (copy on write),也就是 寫時複製 。咱們知道 RDB
持久化須要遍歷內存中的數據,就像下面那張圖同樣。 操作系統
由於咱們須要的是在子進程產生的那一瞬間的數據(快照),若是此時由於用戶請求在主進程修改了內存中的數據,那麼子進程遍歷的內存就會被更改,這個時候就不是快照數據了。 線程
因此這裏就使用了產生快照的一種機制—— COW 。咱們知道上面的數據段其實由不少操做系統的頁組合而成的。COW 其實就是在主進程須要修改內存中的數據的時候,首先將須要修改的數據所在的頁進行復制,而後再複製的頁面上進行修改。當進行頁的複製的時候就會佔用額外的內存,這也是 bgsave
佔用內存比 save
多的緣由,可是不用過度擔憂,由於再保存期間不會出現大量的用戶請求來修改數據,額外使用的內存也不會不少。
在 Redis
中會有幾種狀況下進行 RDB
的持久化,因此即便你在配置文件中關閉了 RDB
,Redis
仍是會進行 RDB
的持久化。
知足條件時
在 Redis
的配置文件中有這麼三條配置。
save 900 1
save 300 10
save 60 10000
複製代碼
這其實就是 RDB
中默認開啓的緣由,它的格式是這樣的 save seconds changeTimes
,save
後面的第一個數字是時間,第二個數字是修改次數,這三條配置的意思就是 在900秒內進行了1次修改或者在300秒內進行了10次修改或者在60秒內進行了10000次修改 會進行 RDB
的自動持久化。
shutdown
當 Redis
正常關閉的時候會進行 RDB
持久化。
flushall
會產生一個空的 RDB
文件
主從複製進行全量複製的時候(目前作了解就行,我在後面的文章會講到 Redis 集羣)
RDB
文件,其中作了些壓縮,存儲的是數據,能夠快速的進行災難恢復。RDB
須要遍歷整個內存中的全部數據,因此進行一次 RDB
操做是一個費事費力的操做,爲了保證 Redis
的高性能,你須要儘可能減小 RDB
的持久化,因此你可能會丟失一段時間的數據。默認狀況下 Redis
是沒有開啓 AOF
持久化的,你須要在配置文件中進行相應的配置。
appendonly yes # 默認爲no這裏設置yes開啓
dir ./ # aof文件目錄
appendfilename "appendonly-6379.aof" #aof文件名
複製代碼
開啓 AOF
持久化以後,Redis
會根據 AOF
持久化策略 來進行相應的持久化操做,具體配置是在 appendfsync
配置。
# appendfsync always 每次進行修改操做就進行寫盤
appendfsync everysec 每秒進行一些寫盤
# appendfsync no 從不
複製代碼
Redis
一共提供了三個參數,通常考慮設置 everysec
每秒寫盤,這樣既能少影響效率也能減小數據丟失量。
AOF
日誌中存放的是對於 Redis
的操做指令,有了 AOF
日誌咱們就可使用它進行對 Redis
的重放。
好比此時咱們 AOF
日誌中記錄了 set hello world
和 sadd userset FancisQ
這兩條命令,咱們就能夠對一個空的 Redis
實例進行此 AOF
文件的重放,最終這個空的 Redis
就有了上面兩條記錄。
你可能會發現 Redis
中的這兩個持久化方式很像 MySQL
中的 bin log
和 redo log
,可是你須要注意的是 Redis
中的 AOF
是先執行命令再存日誌的。這和 MySQL
中的 WAL 機制截然相反。
爲何呢? 我以爲有兩點。
Redis
是弱事務的,咱們不須要保證數據的強一致。在 MySQL
中咱們使用了 redo log
兩階段提交 來保證了 save-crash
能力,而在 Redis
中咱們顯然不須要這麼作,假設這條命令執行完以後還沒來得及寫日誌就宕機了,那就沒了,由於弱事務,咱們大可沒必要保證數據必須存在。AOF
文件是須要 瘦身 的,這些錯誤指令會給 AOF
瘦身帶來不少麻煩。上面提到的 瘦身 其實就是 AOF重寫 ,咱們知道 AOF
文件中存儲的是指令順序,當 Redis
長時間運行時會產生不少指令。
好比
set a b
,set a c
,set a d
.....
其實上面三條就是對 key
爲 a 的數據進行操做了,在 RDB
中它可能只存了 a = d
,可是由於 AOF
的指令機制,它必須存在三條,但前面的是無心義的,這樣會浪費不少空間而且給 AOF
重放帶來麻煩。
因此 Redis
會在 AOF
文件過大(符合某種條件)的時候進行自動的 AOF
重寫。對應的在配置文件中有這樣兩條配置。
# 下面兩條須要同時知足
# 表示當前 aof 文件超過上次 aof文件大小的百分之多少時會進行重寫,若是沒有重寫過則以啓動時的大小爲標準
auto-aof-rewrite-percentage 100
# 文件大於多少的時候進行重寫
auto-aof-rewrite-min-size 64mb
複製代碼
那麼,AOF
是如何重寫的呢?
這是一條 AOF
重寫命令(上述的重寫過程其實就是 bgrewriteaof
),和 bgsave
同樣,Redis
也是會 fork
一個子進程,讓子進程去負責 AOF
文件的重寫。大體流程以下:
AOF
文件的大小要比 RDB
文件大得多,若是使用它進行內存狀態恢復須要花費很長時間。everysec
的狀況下最多隻會丟失秒級的數據。在 Redis
4.0以前,咱們通常會開啓 AOF
而後再須要恢復內存狀態的時候棄用 AOF日誌重放 ( 若是使用RDB的話會丟失大量數據 )。但若是 Redis
實例很大,AOF
文件也很大的時候會致使 Redis
重啓很是慢。
爲了解決這個問題,在 Redis
4.0以後咱們能夠將 RDB
文件和 AOF
增量日誌存儲在一塊兒。若是這個時候咱們進行內存狀態恢復能夠先使用前面的 RDB
部分,而後再使用 RDB
持久化以後產生的增量AOF日誌 來進行內存狀態恢復以減小時間。
RDB
。AOF
儘可能使用 everysec
配置,既能保證數據安全又能保證性能效率。RDB
下關閉 save seconds changeTimes
這個自動持久化機制,或者合理使用參數。感謝閱讀。 給大家分享一下思惟導圖 (#^.^#)