Redis持久化

RDB

說(shuō)明

生成內(nèi)存文件快照

生成方式
  1. 手動(dòng)觸發(fā)
    1. save
      1. 由當(dāng)前主線程執(zhí)行,會(huì)阻塞redis操作,由主線程生成rdb文件
    2. bgsave
      1. 主線程fork出子線程,由子線程來(lái)完成rdb寫(xiě)入,但是在fork子線程的過(guò)程中,是阻塞的,而且內(nèi)存越大,fork子線程的時(shí)間也就越長(zhǎng)。子線程生成完rdb文件后,原子替換新rdb文件為原rdb文件,并通知主線程生成完畢。
  2. 自動(dòng)觸發(fā)
    1. redis.conf中若配置了save m n,即m秒中發(fā)生了n次修改時(shí),會(huì)觸發(fā)bgsave
    2. 主從復(fù)制時(shí),從節(jié)點(diǎn)要從主節(jié)點(diǎn)全量復(fù)制時(shí),也會(huì)觸發(fā)bgsave
    3. debug reload重啟時(shí),也會(huì)先bgsave保存全量快照
    4. shutdown時(shí),如果沒(méi)有配置aof,也會(huì)觸發(fā)
rdb配置
  1. ldbfilename:RDB文件在磁盤(pán)上的名稱。
  2. dir:RDB文件的存儲(chǔ)路徑。默認(rèn)設(shè)置為“./”,也就是Redis服務(wù)的主目錄。
  3. stop-writes-on-bgsave-error:上文提到的在快照進(jìn)行過(guò)程中,主進(jìn)程照樣可以接受客戶端的任何寫(xiě)操作的特性,是指在快照操作正常的情況下。如果快照操作出現(xiàn)異常(例如操作系統(tǒng)用戶權(quán)限不夠、磁盤(pán)空間寫(xiě)滿等等)時(shí),Redis就會(huì)禁止寫(xiě)操作。這個(gè)特性的主要目的是使運(yùn)維人員在第一時(shí)間就發(fā)現(xiàn)Redis的運(yùn)行錯(cuò)誤,并進(jìn)行解決。一些特定的場(chǎng)景下,您可能需要對(duì)這個(gè)特性進(jìn)行配置,這時(shí)就可以調(diào)整這個(gè)參數(shù)項(xiàng)。該參數(shù)項(xiàng)默認(rèn)情況下值為yes,如果要關(guān)閉這個(gè)特性,指定即使出現(xiàn)快照錯(cuò)誤Redis一樣允許寫(xiě)操作,則可以將該值更改為no。
  4. rdbcompression:該屬性將在字符串類型的數(shù)據(jù)被快照到磁盤(pán)文件時(shí),啟用LZF壓縮算法。Redis官方的建議是請(qǐng)保持該選項(xiàng)設(shè)置為yes,因?yàn)椤癷t’s almost always a win”。
  5. rdbchecksum:從RDB快照功能的version 5 版本開(kāi)始,一個(gè)64位的CRC冗余校驗(yàn)編碼會(huì)被放置在RDB文件的末尾,以便對(duì)整個(gè)RDB文件的完整性進(jìn)行驗(yàn)證。這個(gè)功能大概會(huì)多損失10%左右的性能,但獲得了更高的數(shù)據(jù)可靠性。所以如果您的Redis服務(wù)需要追求極致的性能,就可以將這個(gè)選項(xiàng)設(shè)置為no。
問(wèn)題
  1. redis在生成rdb的過(guò)程中,如果有新的寫(xiě)操作進(jìn)來(lái),如何保證一致性?
    由copy-on-write來(lái)實(shí)現(xiàn),在寫(xiě)操作的過(guò)程中,如果主線程需要修改一塊內(nèi)存值,那么這塊內(nèi)存就會(huì)生成一個(gè)內(nèi)存副本,由子線程來(lái)修改并寫(xiě)入到rdb中。


    image.png
  1. 在執(zhí)行快照的階段時(shí),如果發(fā)生服務(wù)器崩潰怎么辦?
    如果發(fā)生服務(wù)器崩潰,此次文件寫(xiě)入就會(huì)失敗,redis會(huì)以上次備份的rdb文件為準(zhǔn)。

  2. 可以每秒做一次快照嗎?
    如果頻繁的執(zhí)行全量快照,會(huì)發(fā)生2個(gè)問(wèn)題:

    1. 每次全量寫(xiě)入文件,會(huì)造成大量的IO,增加系統(tǒng)負(fù)擔(dān)
    2. 雖然子線程不會(huì)阻塞主線程,但是主線程fork出子線程的過(guò)程,依然是會(huì)對(duì)主線程阻塞的,依然會(huì)影響性能
優(yōu)缺點(diǎn)
  1. 優(yōu)點(diǎn)

    1. RDB在數(shù)據(jù)恢復(fù)時(shí),會(huì)執(zhí)行速度較快,優(yōu)于AOF
    2. RDB是基于全量數(shù)據(jù)存儲(chǔ)的,且經(jīng)過(guò)了LZF算法進(jìn)行壓縮,內(nèi)存空間遠(yuǎn)遠(yuǎn)小于原數(shù)據(jù),適用于備份,全量復(fù)制。
  2. 缺點(diǎn)

    1. 不具有實(shí)時(shí)性,無(wú)法做到秒級(jí)的持久化
    2. 文件是二進(jìn)制,不利于查看
    3. fork子線程的過(guò)程較重,頻繁執(zhí)行成本較高
    4. 版本兼容RDB問(wèn)題

AOF

說(shuō)明

寫(xiě)后日志,先執(zhí)行內(nèi)存操作,再將操作語(yǔ)句寫(xiě)入日志。

為什么采用寫(xiě)后日志
  1. 優(yōu)點(diǎn)

    1. 不阻塞內(nèi)存寫(xiě)入,內(nèi)存修改完畢后才去寫(xiě)日志
    2. 避免額外的資源開(kāi)銷,如果有一些redis操作是錯(cuò)誤的,將不會(huì)記錄到aof中,減少一部分錯(cuò)誤操作的冗余記錄
  2. 缺點(diǎn)

    1. 如果內(nèi)存操作完畢后宕機(jī),日志寫(xiě)入會(huì)失敗,恢復(fù)將丟失數(shù)據(jù)
    2. 主線程寫(xiě)磁盤(pán)慢,導(dǎo)致寫(xiě)盤(pán)慢,阻塞后續(xù)操作
如何實(shí)現(xiàn)
  1. 命令追加
    1. redis在執(zhí)行完一個(gè)寫(xiě)命令后,會(huì)將命令追加到服務(wù)器的緩沖區(qū)內(nèi)(aof_buf)
  2. 文件寫(xiě)入和同步
    redis提供了3種寫(xiě)入策略
    1. always:每個(gè)寫(xiě)命令執(zhí)行完畢后,立刻同步的寫(xiě)回磁盤(pán)
    2. everySec:輸出到緩沖區(qū)后,每隔1s,將緩沖區(qū)內(nèi)容寫(xiě)回磁盤(pán)
    3. no:輸出到緩沖區(qū)后,由系統(tǒng)控制何時(shí)寫(xiě)回磁盤(pán)
aof配置
  1. appendonly:默認(rèn)情況下AOF功能是關(guān)閉的,將該選項(xiàng)改為yes以便打開(kāi)Redis的AOF功能。
  2. appendfilename:這個(gè)參數(shù)項(xiàng)很好理解了,就是AOF文件的名字。
  3. appendfsync:這個(gè)參數(shù)項(xiàng)是AOF功能最重要的設(shè)置項(xiàng)之一,主要用于設(shè)置“真正執(zhí)行”操作命令向AOF文件中同步的策略。什么叫“真正執(zhí)行”呢?還記得Linux操作系統(tǒng)對(duì)磁盤(pán)設(shè)備的操作方式嗎? 為了保證操作系統(tǒng)中I/O隊(duì)列的操作效率,應(yīng)用程序提交的I/O操作請(qǐng)求一般是被放置在linux Page Cache中的,然后再由Linux操作系統(tǒng)中的策略自行決定正在寫(xiě)到磁盤(pán)上的時(shí)機(jī)。而Redis中有一個(gè)fsync()函數(shù),可以將Page Cache中待寫(xiě)的數(shù)據(jù)真正寫(xiě)入到物理設(shè)備上,而缺點(diǎn)是頻繁調(diào)用這個(gè)fsync()函數(shù)干預(yù)操作系統(tǒng)的既定策略,可能導(dǎo)致I/O卡頓的現(xiàn)象頻繁 。
  • 與上節(jié)對(duì)應(yīng),appendfsync參數(shù)項(xiàng)可以設(shè)置三個(gè)值,分別是:always、everysec、no,默認(rèn)的值為everysec
  1. no-appendfsync-on-rewrite:always和everysec的設(shè)置會(huì)使真正的I/O操作高頻度的出現(xiàn),甚至?xí)霈F(xiàn)長(zhǎng)時(shí)間的卡頓情況,這個(gè)問(wèn)題出現(xiàn)在操作系統(tǒng)層面上,所有靠工作在操作系統(tǒng)之上的Redis是沒(méi)法解決的。為了盡量緩解這個(gè)情況,Redis提供了這個(gè)設(shè)置項(xiàng),保證在完成fsync函數(shù)調(diào)用時(shí),不會(huì)將這段時(shí)間內(nèi)發(fā)生的命令操作放入操作系統(tǒng)的Page Cache(這段時(shí)間Redis還在接受客戶端的各種寫(xiě)操作命令)。
  2. auto-aof-rewrite-percentage:上文說(shuō)到在生產(chǎn)環(huán)境下,技術(shù)人員不可能隨時(shí)隨地使用“BGREWRITEAOF”命令去重寫(xiě)AOF文件。所以更多時(shí)候我們需要依靠Redis中對(duì)AOF文件的自動(dòng)重寫(xiě)策略。Redis中對(duì)觸發(fā)自動(dòng)重寫(xiě)AOF文件的操作提供了兩個(gè)設(shè)置:auto-aof-rewrite-percentage表示如果當(dāng)前AOF文件的大小超過(guò)了上次重寫(xiě)后AOF文件的百分之多少后,就再次開(kāi)始重寫(xiě)AOF文件。例如該參數(shù)值的默認(rèn)設(shè)置值為100,意思就是如果AOF文件的大小超過(guò)上次AOF文件重寫(xiě)后的1倍,就啟動(dòng)重寫(xiě)操作。
  3. auto-aof-rewrite-min-size:參考auto-aof-rewrite-percentage選項(xiàng)的介紹,auto-aof-rewrite-min-size設(shè)置項(xiàng)表示啟動(dòng)AOF文件重寫(xiě)操作的AOF文件最小大小。如果AOF文件大小低于這個(gè)值,則不會(huì)觸發(fā)重寫(xiě)操作。注意,auto-aof-rewrite-percentage和auto-aof-rewrite-min-size只是用來(lái)控制Redis中自動(dòng)對(duì)AOF文件進(jìn)行重寫(xiě)的情況,如果是技術(shù)人員手動(dòng)調(diào)用“BGREWRITEAOF”命令,則不受這兩個(gè)限制條件左右。
AOF重寫(xiě)

AOF會(huì)將每個(gè)執(zhí)行命令記錄到磁盤(pán)中,隨著時(shí)間增長(zhǎng),文件越來(lái)越大,這時(shí)候就需要將AOF文件重寫(xiě),來(lái)減少文件的大小。


image.png
問(wèn)題
  1. AOF重寫(xiě)會(huì)阻塞嗎?
    AOF日志需要重寫(xiě)時(shí),會(huì)由主線程fork出一個(gè)子線程bgrewriteaof,并copy一份內(nèi)存副本,然后子線程就可以根據(jù)內(nèi)存副本,來(lái)生成對(duì)應(yīng)的寫(xiě)操作,重寫(xiě)AOF文件。子線程重寫(xiě)的過(guò)程中對(duì)主線程沒(méi)有影響,但在fork的過(guò)程中會(huì)阻塞。

  2. AOF日志何時(shí)會(huì)重寫(xiě)?
    相關(guān)的配置有2個(gè)
    auto-aof-rewrite-min-size: 重寫(xiě)時(shí)的aof文件的最大大小,默認(rèn)是64MB
    auto-aof-rewrite-percentage: 重寫(xiě)時(shí)當(dāng)前AOF文件的大小,和上次重寫(xiě)完畢后的AOF文件的差值的百分比。比如上次重寫(xiě)完畢后是10MB,配置為100%,那么在新的aof文件為20MB時(shí),即發(fā)生重寫(xiě)。

  3. 重寫(xiě)日志時(shí),如果有新數(shù)據(jù)寫(xiě)入怎么辦?
    一份寫(xiě)入,兩份日志,當(dāng)在重寫(xiě)的過(guò)程中,主線程依然正常對(duì)之前的AOF文件正常輸入,同時(shí)會(huì)復(fù)制一份操作命令,追加到新AOF文件的緩沖區(qū),等待AOF文件重寫(xiě)完畢后。主線程會(huì)將新文件的緩沖區(qū)輸出到新AOF文件中,但在高并發(fā)的情況下,緩沖區(qū)的數(shù)據(jù)可能會(huì)太多,這樣就會(huì)對(duì)主線程造成阻塞。但Redis后來(lái)使用了linux的管道技術(shù),可以讓aof重寫(xiě)期間就能進(jìn)行回放,這樣后續(xù)只需寫(xiě)入少量操作即可。

  4. 總結(jié):

    1. fork出子線程,子線程去重寫(xiě)AOF文件
    2. 過(guò)程中如果有寫(xiě)操作,追加到新文件的緩沖區(qū)
    3. 重寫(xiě)完畢后替換老文件,并將緩沖區(qū)輸出到新文件
  5. 主線程fork出子線程,內(nèi)存的操作過(guò)程是怎么樣的
    在主線程fork子線程,阻塞的過(guò)程中,會(huì)創(chuàng)建一個(gè)當(dāng)前內(nèi)存的虛擬映射表,根據(jù)指針映射到之前的物理內(nèi)存中。fork完畢后,如果有寫(xiě)入操作,則將待修改的內(nèi)存創(chuàng)建一份副本,在副本上做修改,而子線程依然指向的是原有的內(nèi)存。


    image.png
  1. 在重寫(xiě)日志的過(guò)程中,哪些地方會(huì)發(fā)生阻塞

    1. fork出子線程時(shí)
    2. 在重寫(xiě)時(shí),如果有bigkey進(jìn)入,則需要產(chǎn)生對(duì)應(yīng)副本,也可能會(huì)阻塞
    3. 重寫(xiě)完畢后,替換原文件,并輸出緩沖區(qū),會(huì)阻塞
  2. 為什么AOF不采用原AOF的文件

    1. 父子線程同時(shí)操作一個(gè)文件,會(huì)產(chǎn)生競(jìng)爭(zhēng)
    2. 如果重寫(xiě)失敗,會(huì)導(dǎo)致原文件被污染,無(wú)法再使用

RDB和AOF混合(4.0版本)

image.png

image.png

實(shí)踐:

  • 降低fork的頻率,比如可以手動(dòng)來(lái)觸發(fā)RDB生成快照、與AOF重寫(xiě)
  • 控制Redis最大使用內(nèi)存,防止fork耗時(shí)過(guò)長(zhǎng);
  • 使用更牛逼的硬件;
  • 合理配置Linux的內(nèi)存分配策略,避免因?yàn)槲锢韮?nèi)存不足導(dǎo)致fork失敗。

參考文檔:
https://www.pdai.tech/md/db/nosql-redis/db-redis-x-rdb-aof.html

?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 前言 在上一篇文章中,介紹了Redis內(nèi)存模型,從這篇文章開(kāi)始,將依次介紹Redis高可用相關(guān)的知識(shí)——持久化、復(fù)...
    Java架構(gòu)閱讀 2,505評(píng)論 3 21
  • Redis支持RDB和AOF兩種持久化機(jī)制,持久化功能有效地避免因進(jìn)程退出造成的數(shù)據(jù)丟失問(wèn)題,當(dāng)下次重啟時(shí)利用之前...
    xuxw閱讀 2,205評(píng)論 0 0
  • 一、Redis高可用概述 在介紹Redis高可用之前,先說(shuō)明一下在Redis的語(yǔ)境中高可用的含義。 我們知道,在w...
    空語(yǔ)閱讀 1,683評(píng)論 0 2
  • 前言 在上一篇文章中,介紹了Redis的內(nèi)存模型,從這篇文章開(kāi)始,將依次介紹Redis高可用相關(guān)的知識(shí)——持久化、...
    不_一閱讀 178評(píng)論 0 1
  • 一、Redis高可用概述 在介紹Redis高可用之前,先說(shuō)明一下在Redis的語(yǔ)境中高可用的含義。 我們知道,在w...
    Java架構(gòu)_師閱讀 480評(píng)論 0 2

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