Redis AOF 持久化方式

除了 RDB 持久化之外,Redis 還提供了 AOF(Append Only File)持久化功能。與 RDB 持久化通過保存數(shù)據(jù)庫(kù)中鍵值對(duì)來保存數(shù)據(jù)庫(kù)的狀態(tài)不同,AOF 持久化是通過保存 Redis 服務(wù)器所執(zhí)行的寫命令來記錄數(shù)據(jù)庫(kù)的狀態(tài)

AOF 持久化的實(shí)現(xiàn)

AOF 持久化功能的實(shí)現(xiàn)可以分為:命令追加(append),文件寫入(write),文件同步(sync)三個(gè)步驟

命令追加

AOF 持久化需要將所有寫命令記錄在文件中來保存服務(wù)器狀態(tài),而文件寫入操作效率比較低,如果每執(zhí)行一條寫命令都要寫一次 AOF 文件無疑是低效的。為了提高效率,Redis 提供了一個(gè)中間層 – AOF 緩沖區(qū),也就是說當(dāng) Redis 執(zhí)行一條寫命令后,先將該命令追加到 AOF 緩沖區(qū)中,在以后的某個(gè)時(shí)刻再將 AOF 緩沖區(qū)中的內(nèi)容同步到文件中

當(dāng) AOF 持久化功能處于打開狀態(tài)時(shí),服務(wù)器在執(zhí)行完一個(gè)寫命令之后,會(huì)以協(xié)議格式將被執(zhí)行的寫命令追加到服務(wù)器狀態(tài)的 aof_buf 緩沖區(qū)的末尾

AOF 文件的寫入與同步

Redis 的服務(wù)器進(jìn)程就是一個(gè)事件循環(huán)(loop),這個(gè)循環(huán)中的文件事件負(fù)責(zé)接收客戶端的命令請(qǐng)求,以及向客戶端發(fā)送命令回復(fù),而時(shí)間事件則負(fù)責(zé)執(zhí)行像 serverCron 函數(shù)這樣需要定時(shí)運(yùn)行的函數(shù)

因?yàn)榉?wù)器在處理文件事件時(shí)可能會(huì)執(zhí)行寫命令,使得一些內(nèi)容被追加到 aof_buf 緩沖區(qū)里面,所以在服務(wù)器每次結(jié)束一個(gè)事件循環(huán)之前,它都會(huì)調(diào)用 flushAppendOnlyFile 函數(shù),考慮是否需要將 aof_buf 緩沖區(qū)中的內(nèi)容寫入和保存到 AOF 文件里面

def eventLoop():

    while True:
    
        # 處理文件事件,接收命令請(qǐng)求以及發(fā)送命令回復(fù)
        # 處理命令請(qǐng)求時(shí)可能會(huì)有新內(nèi)容被追加到 aof_buf 緩沖區(qū)中
        processFileEvents()

        # 處理時(shí)間事件
        processTimeEvents()

        # 考慮是否要將 aof_buf 中的內(nèi)容寫入和保存到 AOF 文件里面
        flushAppendOnlyFile()

flushAppendOnlyFile 函數(shù)的行為由服務(wù)器配置的 appendfsync 選項(xiàng)的值來決定:

  • AOF_FSYNC_NO
    在該模式下,Redis 服務(wù)器在每個(gè)事件循環(huán)都將 AOF 緩沖區(qū)中的數(shù)據(jù)寫入 AOF 文件中,但不執(zhí)行同步 fsync 方法,由操作系統(tǒng)決定何時(shí)同步。該模式速度最快(無需執(zhí)行同步操作)但也最不安全(如果機(jī)器崩潰將丟失上次同步后的所有數(shù)據(jù))

  • AOF_FSYNC_ALWAYS
    在該模式下,Redis 服務(wù)器在每個(gè)事件循環(huán)都將 AOF 緩沖區(qū)中的數(shù)據(jù)寫入 AOF 文件中,且執(zhí)行一次 AOF 文件同步操作。該模式速度最慢(每個(gè)事件循環(huán)都要執(zhí)行同步操作)但也最安全(如果機(jī)器崩潰只丟失當(dāng)前事件循環(huán)中處理的新數(shù)據(jù))

  • AOF_FSYNC_EVERYSEC
    在該模式下,Redis 服務(wù)器在每個(gè)事件循環(huán)都將 AOF 緩沖區(qū)中的數(shù)據(jù)寫入 AOF 文件中,且每秒執(zhí)行一次 AOF 文件同步操作。該模式效率和安全性(如果機(jī)器崩潰只丟失前一秒處理的新數(shù)據(jù))比較適中,是 Redis 的默認(rèn)同步策略

AOF 文件的載入與數(shù)據(jù)還原

因?yàn)?Redis 的命令只能在客戶端上下文中執(zhí)行,而載入 AOF 文件時(shí)所使用的命令直接來源于 AOF 文件而不是網(wǎng)絡(luò)連接,所以服務(wù)器使用了一個(gè)沒有網(wǎng)絡(luò)連接的偽客戶端來執(zhí)行 AOF 文件保存的寫命令,偽客戶端執(zhí)行命令的效果和帶網(wǎng)絡(luò)連接的客戶端執(zhí)行命令的效果完全一樣

AOF 重寫

AOF 持久化是通過保存被執(zhí)行的寫命令來記錄數(shù)據(jù)庫(kù)狀態(tài)的,所以 AOF 文件的大小隨著時(shí)間的流逝一定會(huì)越來越大;影響包括但不限于:對(duì)于 Redis 服務(wù)器,計(jì)算機(jī)的存儲(chǔ)壓力;AOF 還原出數(shù)據(jù)庫(kù)狀態(tài)的時(shí)間增加

為了解決 AOF 文件體積膨脹的問題,Redis 提供了 AOF 重寫功能:Redis 服務(wù)器可以創(chuàng)建一個(gè)新的 AOF 文件來替代現(xiàn)有的 AOF 文件,新舊兩個(gè)文件所保存的數(shù)據(jù)庫(kù)狀態(tài)是相同的,但是新的 AOF 文件不會(huì)包含任何浪費(fèi)空間的冗余命令,通常體積會(huì)較舊 AOF 文件小很多

AOF 文件重寫的實(shí)現(xiàn)

AOF 文件重寫并不需要對(duì)現(xiàn)有的 AOF 文件進(jìn)行任何讀取、分析或?qū)懭氩僮?,這個(gè)功能時(shí)通過讀取服務(wù)器當(dāng)前的數(shù)據(jù)狀態(tài)來實(shí)現(xiàn)的

實(shí)現(xiàn)原理:遍歷數(shù)據(jù)庫(kù)中的所有鍵(忽略已過期的鍵),讀取鍵現(xiàn)在的值,用一條命令去記錄鍵值對(duì),代替之前修改該鍵值對(duì)的多個(gè)命令

在實(shí)際中,為了避免執(zhí)行命令時(shí)造成客戶端輸入緩沖區(qū)溢出,重寫程序在處理列表、哈希、集合、有序集合這四種可能會(huì)帶有多個(gè)元素的鍵時(shí),會(huì)先檢查鍵所包含的元素?cái)?shù)量,如果超過某個(gè)限制,會(huì)使用多條命令來記錄鍵的值,而不單單使用一條命令

AOF 后臺(tái)重寫

aof_rewrite 函數(shù)可以創(chuàng)建新的 AOF 文件,但是這個(gè)函數(shù)會(huì)進(jìn)行大量的寫入操作,所以調(diào)用這個(gè)函數(shù)的線程將被長(zhǎng)時(shí)間的阻塞,因?yàn)?Redis 服務(wù)器使用單線程來處理命令請(qǐng)求;所以如果直接是服務(wù)器進(jìn)程調(diào)用 aof_rewrite 函數(shù)的話,那么重寫 AOF 期間,服務(wù)器將無法處理客戶端發(fā)送來的命令請(qǐng)求

Redis 不希望 AOF 重寫會(huì)造成服務(wù)器無法處理請(qǐng)求,所以 Redis 決定將 AOF 重寫程序放到子進(jìn)程(后臺(tái))里執(zhí)行。這樣處理的最大好處是:

  • 子進(jìn)程進(jìn)行 AOF 重寫期間,主進(jìn)程可以繼續(xù)處理命令請(qǐng)求;
  • 子進(jìn)程帶有主進(jìn)程的數(shù)據(jù)副本,使用子進(jìn)程而不是線程,可以避免在鎖的情況下,保證數(shù)據(jù)的安全性
使用子進(jìn)程進(jìn)行 AOF 重寫的問題

子進(jìn)程在進(jìn)行 AOF 重寫期間,服務(wù)器進(jìn)程還要繼續(xù)處理命令請(qǐng)求,而新的命令可能對(duì)現(xiàn)有的數(shù)據(jù)進(jìn)行修改,這會(huì)讓當(dāng)前數(shù)據(jù)庫(kù)的數(shù)據(jù)和重寫后的 AOF 文件中的數(shù)據(jù)不一致

如何修正

為了解決這種數(shù)據(jù)不一致的問題,Redis 增加了一個(gè)AOF 重寫緩沖區(qū),這個(gè)緩沖區(qū)在 fork 出子進(jìn)程之后開始啟用,Redis 服務(wù)器主進(jìn)程在執(zhí)行完寫命令之后,會(huì)同時(shí)將這個(gè)寫命令追加到 AOF 緩沖區(qū)和 AOF 重寫緩沖區(qū)
即子進(jìn)程在執(zhí)行 AOF 重寫時(shí),主進(jìn)程需要執(zhí)行以下三個(gè)工作:

  • 執(zhí)行 client 發(fā)來的命令請(qǐng)求
  • 將寫命令追加到現(xiàn)有的 AOF 文件中
  • 將寫命令追加到 AOF 重寫緩存中

可以保證:

  • AOF 緩沖區(qū)的內(nèi)容會(huì)定期被寫入和同步到 AOF 文件中,對(duì)現(xiàn)有的 AOF 文件的處理工作會(huì)正常進(jìn)行
  • 從創(chuàng)建子進(jìn)程開始,服務(wù)器執(zhí)行的所有寫操作都會(huì)被記錄到 AOF 重寫緩沖區(qū)中

當(dāng)子進(jìn)程完成對(duì) AOF 文件重寫之后,它會(huì)向父進(jìn)程發(fā)送一個(gè)完成信號(hào),父進(jìn)程接到該完成信號(hào)之后,會(huì)調(diào)用一個(gè)信號(hào)處理函數(shù),該函數(shù)完成以下工作:

  • 將 AOF 重寫緩存中的內(nèi)容全部寫入到新的 AOF 文件中;這個(gè)時(shí)候新的 AOF 文件所保存的數(shù)據(jù)庫(kù)狀態(tài)和服務(wù)器當(dāng)前的數(shù)據(jù)庫(kù)狀態(tài)一致
  • 對(duì)新的 AOF 文件進(jìn)行改名,原子地覆蓋原有的 AOF 文件;完成新舊兩個(gè) AOF 文件的替換

當(dāng)這個(gè)信號(hào)處理函數(shù)執(zhí)行完畢之后,主進(jìn)程就可以繼續(xù)像往常一樣接收命令請(qǐng)求了

在整個(gè) AOF 后臺(tái)重寫過程中,只有最后的信號(hào)處理函數(shù)執(zhí)行時(shí)會(huì)造成主進(jìn)程阻塞,在其他時(shí)候,AOF 后臺(tái)重寫都不會(huì)對(duì)主進(jìn)程造成阻塞,這將 AOF 重寫對(duì)性能造成的影響降到最低

以上,即 AOF 后臺(tái)重寫,也就是 BGREWRITEAOF 命令的工作原理

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 從這篇文章開始,將依次介紹Redis高可用相關(guān)的知識(shí)——持久化、復(fù)制(及讀寫分離)、哨兵、以及集群。 本文將先說明...
    不變甄心閱讀 738評(píng)論 0 4
  • 一、Redis高可用概述 在介紹Redis高可用之前,先說明一下在Redis的語(yǔ)境中高可用的含義。 我們知道,在w...
    空語(yǔ)閱讀 1,681評(píng)論 0 2
  • 前言 在上一篇文章中,介紹了Redis內(nèi)存模型,從這篇文章開始,將依次介紹Redis高可用相關(guān)的知識(shí)——持久化、復(fù)...
    Java架構(gòu)閱讀 2,503評(píng)論 3 21
  • 企業(yè)級(jí)redis集群架構(gòu)的特點(diǎn) 海量數(shù)據(jù) 高并發(fā) 高可用 要達(dá)到高可用,持久化是不可減少的,持久化主要是做災(zāi)難恢復(fù)...
    lucode閱讀 2,283評(píng)論 0 7
  • 我的大馬之旅 抱著滿心的歡喜期待和一點(diǎn)點(diǎn)的緊張,踏上了這段探索自己的旅程。 項(xiàng)目一共有8個(gè)EP,四個(gè)來自中國(guó)的女生...
    Hayleyyyy閱讀 320評(píng)論 0 0

友情鏈接更多精彩內(nèi)容