redis学习笔记-持久化
redis學習筆記-持久化
前言
redis持久化有兩種方式:RDB和AOF。分別對應著全量復制和增量復制。深刻理解各自的實現方式及適用場景對redis的使用和運維十分重要。下面就分別介紹。
RDB持久化
RDB持久化即將當前Redis實例中的數據快照全部保存的磁盤的過程??墒謩佑|發,也可根據配置自動觸發。
手動觸發
手動觸發有兩個命令可以選擇: save和bgsave。兩者區別在于save是阻塞的,復制完成前會阻塞客戶端命令執行,目前已經廢棄。bgsave是非阻塞的。執行過程中redis進程會fork出一個子進程負責復制任務,而主進程依然響應客戶端請求命令。對應bgsave命令,阻塞只存在于fork過程中。大大減小了阻塞的時間。
如圖,上次rdb同步時間在17:20
執行命令bgsave后, 返回 Background saving started ,
查看rdb文件更新時間,已變為當前時間。
自動觸發
若使用自動觸發,需配置save參數。格式 save m n。查看redis配置文件可看到相關配置。
save 900 1save 300 10save 60 10000復制代碼配置 save m n 含義為當數據在m秒內發生n次修改,自動執行bgsave命令進行RDB持久化。如save 900 1 表示在900秒(15分鐘內)數據有至少1次修改,則觸發RDB。多個配置情況下,只要符合任一條件即可。
具體在實現上,redis服務器會記錄自上次RDB備份后,有多少次修改。每100ms檢查一次,看是否有符合條件的save配置,有則再次執行DRB.
另外,當在客戶端執行關閉服務器命令shutdown,若redis沒有開啟AOF,則自動執行bgsave進行備份。
RDB流程
由于save的持久化命令會發送阻塞,所以目前基本是用bgsave命令觸發的RDB,關于bgsave的流程如下圖所示。
簡要流程如下
簡要來說是父進程fork出了一個子進程用于持久化任務,父進程仍響應客戶端請求,耗時的RDB讓子進程來做。這樣的確可以大大減少阻塞時間,可有一個問題是,主進程還在接受請求,子進程怎樣進行復制?難道子進程再復制一份主進程的內存用于復制,這樣內存豈不是要翻倍?肯定不能這樣。要是子進程共享父進程的內存,那怎樣保證邊接受請求邊復制呢?
事實上,fork操作使用寫時復制(copy-on-write)技術實現。創建的子進程共享父進程地址空間,當只有需要寫入時才會復制地址空間。也就是說,redis的子進程使用共享的內存快照完成RDB備份,而主進程當收到寫請求后,會將涉及到的內存頁復制出一份副本,在此副本進行修改。當子進程RDB完成后,通知主進程更換副本,RDB就此完成。
RDB參數設置及注意點
以下是redis配置文件有關rdb的默認配置
## 是否開啟rdb文件壓縮 rdbcompression yes## rdb文件效驗 rdbchecksum yes## rdb文件名 dbfilename redis-dump-127.0.0.1-6379.rdb## 備份文件儲存目錄 dir /usr/local/var/db/redis/復制代碼AOF持久化
AOF主要用于解決redis實時持久化的問題。方式為實時將redis所有寫命令記錄下來,用于以后恢復及備份。
開啟AOF
aof默認是關閉的,使用appendonly yes開啟。用appendfilename設置aof文件名。同rdb一樣,dir表示aof儲存目錄。
在配置文件設好后重啟redis,即開啟了aof功能。可使用info persistence可查看redis持久化的參數,如下
aof_enabled:1
表示已開啟aof功能。
AOF流程
AOF寫入日志的直接就是文本格式。如set hello world這個命令,在appendonly.aof文件中儲存的就是
*3 $3 SET $5 hello $5 world 復制代碼這就是Redis客戶端與服務器通信的的序列化協議(RESP),每行用\r\n分割,*n表示參數個數,$n表示字節數,十分簡單明了。AOF直接使用協議格式可讓redis直接識別。無需特殊處理,避免二次處理的開銷,也方便修改。
AOF的流程如下
用流程圖表示就是
為什么不直接將命令寫入磁盤很容易理解,這里需關注的是以什么策略從緩沖區寫到磁盤。redis提供了3種策略。
| always | 每次命令寫入緩沖區后都同步刷新到硬盤(使用fsync命令刷新磁盤),此方式最安全,但也是最慢的,因為每次寫數據都要同步硬盤 |
| everysec | 每次寫命令調用系統命令write操作,write只會將數據寫入系統緩沖區,然后由專門的線程每秒同步刷盤 |
| no | 每次寫命令調用系統命令write操作寫入系統緩沖區,具體刷盤時間由操作系統決定,性能是最高的,但數據安全性不能保證 |
通常,我們選擇everysec作為刷盤策略,也是redis默認配置,可以兼顧性能和數據安全。
AOF追加阻塞
一般我們使用everysec的同步刷盤策略。此時會有一個專門的線程每秒執行一次刷盤操作。為保證數據安全性,redis主進程會比對上次刷盤時間與當前時間的差值,如果大于2秒,則阻塞以等待刷盤完成。
也就是說,如果硬盤性能很差,fsync執行太慢,會造成redis阻塞。以保證硬盤的數據不被真實內存數據落的太遠(最大2秒的數據差)。
AOF重寫機制
剛才提到,AOF直接使用redis的序列化協議進行備份,一段時間后,aof文件會很大。為解決此問題,可配置aof重寫機制對原aof文件進行瘦身。
AOF重寫的實質即把redis進程的內存數據轉為寫命令重新生成一份aof文件,以替代原aof文件。
重寫后比原aof體積小的原因有以下幾點
觸發方式
AOF可有手動觸發和自動觸發。
手動觸發使用bgrewriteaof命令觸發。
自動觸發有關參數及含義如下
## aof重寫時此時aof文件與上次aof文件大小百分比 auto-aof-rewrite-percentage 100## aof重寫時文件最小大小,默認64M auto-aof-rewrite-min-size 64mb復制代碼如按默認配置,則發生重寫的條件為aof文件大于64M且此時aof文件比上次重寫時大100%,即是上次的2倍。
重寫流程
aof重寫雖然比較復雜,但對比圖,也能很容易明白其中流程。這這里有個疑問是為什么主進程在子進程重寫時為什么要維護兩個緩沖區?只維護一個不行嗎?畢竟原有aof文件等到新aof文件生成后也是要替換的。
仔細想想就可知,有必要維護兩個緩沖區。主要是需要維護原有aof邏輯不變,以防aof重寫失敗導致數據丟失。另一點兩個緩沖區目的也不同,不宜混淆。
注意:
為防止資源過于競爭,同一時刻只能進行一個AOF重寫任務,當進行重寫時發現有RDB任務時,也會等RDB完成后進行。
RDB與AOF
加載順序
在重啟時,redis會首先判斷是否開啟aof,若開啟aof且aof文件存在,則加載aof文件進行數據恢復以啟動。否則判斷rdb文件存在并加載rdb以啟動。
性能開銷
在進行RDB備份或是AOF重寫時,都需要fork出子進程運行任務。此期間會大量消耗CPU,通常子進程對單核CPU的利用率達到90%,因此在有RDB或需AOF重寫任務的redis,不要做綁定單核CPU操作,這會導致父子進程對CPU產生競爭。
RDB與AOF比較
參考文章
總結
以上是生活随笔為你收集整理的redis学习笔记-持久化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从0到1学C++ 第3篇 从结构到类的演
- 下一篇: MySQL学习(十五)