您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關Redis中持久化RDB和AOF的原理是什么,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
RDB基礎知識
RDB文件存在是以一個壓縮后的二進制文件,這個RDB文件一般是保存在Redis安裝目錄下,通過啟動Redis服務器執行rdbLoad函數加載RDB文件,執行rdbSave函數保存RDB文件。
RDB保存
rdbSave函數負責將內存中的數據庫數據以RDB格式保存到磁盤中,如果RDB文件已存在,那么新的RDB文件將替換已有的RDB文件,SAVE和BGSAVE兩個命令都會調用rdbSave函數。
SAVE直接調用rdbSave,阻塞Redis主進程,直到保存完成為止。在主進程阻塞期間,服務器不能處理客戶端的任何請求。
BGSAVE則開啟一個子進程,子進程負責調用rdbSave,Redis服務器在BGSAVE執行期間仍然可以繼續處理客戶端的請求,并在保存完成之后向主進程發送信號,通知保存已完成。
注意:執行保存命令時Redis不會再次執行save、bgsave、bgrewriteaof等命令,因為如果執行這些命令會存在資源搶占使備份出現意想不到的bug。
自動隔離保存
此時我們的小伙伴意識到,我們不能每次都執行命令手動保存或者執行定時器執行命令,這樣會導致可用性降低,那么Redis提供自動保存的配置
####100秒內對Redis進行10次以上的修改save 100 10####一小時內對Redis進行至少1000次的修改save 3600 1000###只要滿足上面任何一個要求則執行bgsave命令
那么Redis源代碼中保存這個配置的是在redisServer中的一個saveparam的結構,代碼如下:
struct saveparam { teme_t seconds; //秒 int changes; //修改數}
save我們這里就不分析了,因為它直接阻塞主線程把Redis數據直接寫入磁盤文件,所以我們這對bgsave進行講解,前面說了bgsave是開啟一個子進程進行文件的操作,那么此時的Redis主進程還在響應客戶端的命令,那么我們的Redis如何保證數據完整性和性能呢?
Redis在持久化的時候會fork產生一個子進程,持久化過程完全交給子進程,而父進程則響應客戶端的命令,子進程創建時不會立即保存文件因為這會與父進程產生資源搶占,它的指針指向父進程的內存空間與父進程共享內存,這樣為了更加節約資源。
此時父進程是會讀寫內存中的數據,子進程只是讀取資源并不會寫,此時Redis使用操作系統的多進程COW(Copy On Write)機制進行數據段頁面的分離,每頁數據不會超過4K,我們把這個數據稱之為冷數據,父進程進行修改的時候我們只需要把共享的頁數據復制出來對其進行修改,而不在原數據上進行修改,冷數據沒有任何的變化。子進程現在可以安心的對冷數據進行持久化,此時我們持久化的內容就像是被拍了照一樣固定下來,這就是快照的整個過程。
這里值得注意的是隨著時間的推移,父進程修改的頁也會越來越多,理論上這個復制出來的內存能達到之前數據內存,所以我們在設計緩存的時候盡可能的少改數據。
Redis還有一個持久化操作那就是AOF(Append Only File),AOF是將客戶端的修改指令保存下來追加到服務器狀態的aof_buf緩沖區尾部,最后保存到AOF日志文件。舉個例子。
首先,前面我們講過Redis的通訊協議RESP,我們這里把客戶端的指令轉換成這種協議
>set name mango####保存到aof_buf緩沖區*3\r\n$3\r\nset\r\n$4\r\name\r\n$5\r\mango\r\n
然后我們將協議文本追加到aof_buf末尾
最后我們把這些指令信息保存至AOF日志文件中
AOF保存模式
每當服務器常規任務函數被執行、或者事件處理器被執行時,aof.c/flushAppendOnlyFile函數都會被調用,這個函數執行以下兩個工作:
WRITE:根據條件,將aof_buf中的緩存寫入到AOF文件。
SAVE:根據條件,調用fsync或fdatasync函數,將AOF文件保存到磁盤中。
Redis目前支持三種AOF保存模式:
1. AOF_FSYNC_NO:不保存,操作系統來決定什么時候保存保存。
2. AOF_FSYNC_EVERYSEC:每一秒鐘保存一次。
3. AOF_FSYNC_ALWAYS:總是保存,每執行一個命令保存一次。
這三種模式從上到下執行速度越來越慢,安全性越來越高,如果使用no模式,那么恢復數據會恢復到上次備份,如果是everysec最多會丟失一秒,而always只會丟失一個指令。所以我們考慮使用哪種AOF模式取決于我們的業務需求綜合考慮。
關于fsync
AOF日志是以文件的形式存在的,當我們的AOF從緩沖區寫入AOF文件中時服務器突然宕機,此時我們的文件還沒有完全寫入磁盤,這時我們該如何處理呢?
fsync函數可以將指定文件的內容強制從內核緩存刷到磁盤。只要Redis進程實時調用fsync函數就可以保證AOF日志不失。但是fsync是一個磁盤IO操作,so它很慢。如果Redis執行一條指令就要fsync一次,那么可想而知Redis的性能就會拉下一大截 。
所以在生產環境的服務器中,Redis通常是每隔1s左右執行一次fsync操作,這個1s的周期是可以配置的。這是在數據安全性和性能之間做的一個折中,在保持高性能的同時,盡可能使數據少丟失。
Redis同樣也提供了另外兩種策略,一個是永不調用fsync讓操作系統來決定何時同步碰盤,這樣做很不安全,另一個是來一個指令就調用fsync一次——結果導致非常慢。這兩種策略在生產環境中基本不會使用。
AOF重寫
我們的AOF一直累加進行持久化,隨著時間的推移備份文件會越來越大,甚至影響我們對Redis的恢復和操作,Redis也提供重寫機制,下面我們來看看
>set name zhangsan>set name mango>set name lisi...>set name mango####優化后>set name mango
我們可以看到經常會對一個key進行多次修改,那么我們可以把這個key的最后一次操作保存起來這樣我們就輕易的給AOF"瘦身"。當然我們還有一種方式,就是遍歷整個Redis,set每個key和它的值,也跟RDB全備一樣我們需要一個子進程讀取當前的Redis庫。
這里會出現一個問題,我們如果是遍歷整個Redis需要考慮此時的客戶端必定會有指令更改里面的值,此時我們怎么保證AOF重寫后不丟下重寫后的指令呢?
操作步驟:
AOF創建一個子進程進行AOF重寫,其指定內存跟主進程一致
客戶端執行寫命令,主線程處理指令,指令追加到AOF緩沖區,并且追加到AOF重寫緩沖區
AOF重寫完成后替換現有的AOF文件
那么為什么會把這個指令同時追加到AOF緩沖區和AOF重寫區呢?原因是如果我們在重寫的時候突然服務器掛了,那么我們AOF文件中會保存這個指令。追加到AOF緩沖區是為了保證操作指令能及時同步到AOF重寫區。AOF重寫操作也就是之前提到過的bgrewriteaof。
Redis4.0為了解決這個問題,帶來了一個新的持久化選項一一混合持久化。將RDB文件的內容和增量的AOF日志文件存在一起。這里的AOF日志不再是全量的曰志,而是自持久化開始到持久化結束的這段時間發生的增量AOF日志,通常這部分AOF日志很小。
在Redis重啟的時候,可以先加載RDB,然后再重放增量AOF日志,就可以完全替代之前的AOF全量文件重放,重啟效率因此得到大幅提升。
總結一下:
Redis持續化操作包括RDB和AOF
RDB保存的是一個壓縮二進制文件,AOF保存的是操作指令文件
Redis優先恢復AOF,因為它比較全,Redis4.0采用混合模式來恢復
RDB執行bgsave時和AOF重寫一樣,開啟一個子進程,他們的內存與父進程共享
AOF有三種保存模式,no不主動保存依賴操作系統調度;everysec一秒執行一次;always每次執行一個指令保存一次。
AOF保存模式主要是fsync函數,保證AOF日志不會丟失
看完上述內容,你們對Redis中持久化RDB和AOF的原理是什么有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。