redis 持久化策略

企業(yè)級(jí)redis集群架構(gòu)的特點(diǎn)

  • 海量數(shù)據(jù)
  • 高并發(fā)
  • 高可用

要達(dá)到高可用,持久化是不可減少的,持久化主要是做災(zāi)難恢復(fù),數(shù)據(jù)恢復(fù),也可以歸類到高可用的一個(gè)環(huán)節(jié)里面去,比如你redis整個(gè)掛了,然后redis就不可用了,你要做的事情是讓redis變得可用,盡快變得可用,重啟redis,盡快讓它對(duì)外提供服務(wù),如果你沒做數(shù)據(jù)備份,這個(gè)時(shí)候redis啟動(dòng)了,也不可用啊,數(shù)據(jù)都沒了。很可能說,大量的請求過來,緩存全部無法命中,在redis里根本找不到數(shù)據(jù),這個(gè)時(shí)候就死定了,緩存雪崩問題,所有請求,沒有在redis命中,就會(huì)去mysql數(shù)據(jù)庫這種數(shù)據(jù)源頭中去找,一下子mysql承接高并發(fā),然后就掛了,mysql掛掉,你都沒法去找數(shù)據(jù)恢復(fù)到redis里面去,redis的數(shù)據(jù)從哪兒來?從mysql來。。。
如果你把redis的持久化做好,備份和恢復(fù)方案做到企業(yè)級(jí)的程度,那么即使你的redis故障了,也可以通過備份數(shù)據(jù),快速恢復(fù),一旦恢復(fù)立即對(duì)外提供服務(wù)。
當(dāng)然集群高可用并不止持久化,在Redis中,實(shí)現(xiàn)高可用的技術(shù)主要包括持久化、復(fù)制、哨兵和集群,下面分別說明它們的作用,以及解決了什么樣的問題。

RDB和AOF兩種持久化機(jī)制的介紹

RDB持久化機(jī)制,對(duì)redis中的數(shù)據(jù)執(zhí)行周期性的持久化,可以理解為定時(shí)備份,定時(shí)快照。
AOF機(jī)制對(duì)每條寫入命令作為日志,以append-only的模式寫入一個(gè)日志文件中,在redis重啟的時(shí)候,可以通過回放AOF日志中的寫入指令來重新構(gòu)建整個(gè)數(shù)據(jù)集。類似于MySQL的binlog。

當(dāng)然,如果我們想要redis僅僅作為純內(nèi)存的緩存來用,那么可以禁止RDB和AOF所有的持久化機(jī)制。

通過RDB或AOF,都可以將redis內(nèi)存中的數(shù)據(jù)給持久化到磁盤上面來,然后可以將這些數(shù)據(jù)備份到別的地方去,比如說阿里云,云服務(wù)。如果redis掛了,服務(wù)器上的內(nèi)存和磁盤上的數(shù)據(jù)都丟了,可以從云服務(wù)上拷貝回來之前的數(shù)據(jù),放到指定的目錄中,然后重新啟動(dòng)redis,redis就會(huì)自動(dòng)根據(jù)持久化數(shù)據(jù)文件中的數(shù)據(jù),去恢復(fù)內(nèi)存中的數(shù)據(jù),繼續(xù)對(duì)外提供服務(wù)。

如果同時(shí)使用RDB和AOF兩種持久化機(jī)制,那么在redis重啟的時(shí)候,會(huì)使用AOF來重新構(gòu)建數(shù)據(jù),因?yàn)锳OF中的數(shù)據(jù)更加完整。

RDB持久化策略

如何觸發(fā) RDB

savebgsave都可以生成RDB文件
還分為手動(dòng)觸發(fā)和自動(dòng)觸發(fā)兩個(gè)條件

save命令會(huì)阻塞Redis服務(wù)器進(jìn)程,直到RDB文件創(chuàng)建完畢為止,在Redis服務(wù)器阻塞期間,服務(wù)器不能處理任何命令請求

bgsave命令會(huì)創(chuàng)建一個(gè)子進(jìn)程,由子進(jìn)程來負(fù)責(zé)創(chuàng)建RDB文件,父進(jìn)程(即Redis主進(jìn)程)則繼續(xù)處理請求

bgsave命令執(zhí)行過程中,只有fork子進(jìn)程時(shí)會(huì)阻塞服務(wù)器
而對(duì)于save命令,整個(gè)過程都會(huì)阻塞服務(wù)器
因此save已基本被廢棄,線上環(huán)境要杜絕save的使用;

RDB 自動(dòng)觸發(fā)
save m n

自動(dòng)觸發(fā)最常見的情況是在配置文件中通過save m n,指定當(dāng)m秒內(nèi)發(fā)生n次變化時(shí),會(huì)觸發(fā)bgsave。

配置文件

其中save 900 1的含義是:當(dāng)時(shí)間到900秒時(shí),如果redis數(shù)據(jù)發(fā)生了至少1次變化,則執(zhí)行bgsave;save 300 10和save 60 10000同理。當(dāng)三個(gè)save條件滿足任意一個(gè)時(shí),都會(huì)引起bgsave的調(diào)用。

除了save m n 以外,還有一些其他情況會(huì)觸發(fā)bgsave:

  • 在主從復(fù)制場景下,如果從節(jié)點(diǎn)執(zhí)行全量復(fù)制操作,則主節(jié)點(diǎn)會(huì)執(zhí)行bgsave命令,并將rdb文件發(fā)送給從節(jié)點(diǎn)
  • 執(zhí)行shutdown命令時(shí),自動(dòng)執(zhí)行rdb持久化.
    redis-cli -h 127.0.0.1 -p 6379 -a 123 shutdown
    關(guān)閉

    啟動(dòng)時(shí)候自動(dòng)默認(rèn)加載RDB

    當(dāng)AOF關(guān)閉的時(shí)候才去加載RDB。
    Redis載入RDB文件時(shí),會(huì)對(duì)RDB文件進(jìn)行校驗(yàn),如果文件損壞,則日志中會(huì)打印錯(cuò)誤,Redis啟動(dòng)失敗。

save m n的實(shí)現(xiàn)原理

Redis的save m n,是通過serverCron函數(shù)、dirty計(jì)數(shù)器、和lastsave時(shí)間戳來實(shí)現(xiàn)的。

serverCron是Redis服務(wù)器的周期性操作函數(shù),默認(rèn)每隔100ms執(zhí)行一次;該函數(shù)對(duì)服務(wù)器的狀態(tài)進(jìn)行維護(hù),其中一項(xiàng)工作就是檢查 save m n 配置的條件是否滿足,如果滿足就執(zhí)行bgsave。

dirty計(jì)數(shù)器是Redis服務(wù)器維持的一個(gè)狀態(tài),記錄了上一次執(zhí)行bgsave/save命令后,服務(wù)器狀態(tài)進(jìn)行了多少次修改(包括增刪改);而當(dāng)save/bgsave執(zhí)行完成后,會(huì)將dirty重新置為0。

例如,如果Redis執(zhí)行了set mykey helloworld,則dirty值會(huì)+1;如果執(zhí)行了sadd myset v1 v2 v3,則dirty值會(huì)+3;注意dirty記錄的是服務(wù)器進(jìn)行了多少次修改,而不是客戶端執(zhí)行了多少修改數(shù)據(jù)的命令。

lastsave時(shí)間戳也是Redis服務(wù)器維持的一個(gè)狀態(tài),記錄的是上一次成功執(zhí)行save/bgsave的時(shí)間。

save m n的原理如下:每隔100ms,執(zhí)行serverCron函數(shù);在serverCron函數(shù)中,遍歷save m n配置的保存條件,只要有一個(gè)條件滿足,就進(jìn)行bgsave。對(duì)于每一個(gè)save m n條件,只有下面兩條同時(shí)滿足時(shí)才算滿足:

(1)當(dāng)前時(shí)間-lastsave > m
(2)dirty >= n

bgsave執(zhí)行流行

image.png

圖片中的5個(gè)步驟所進(jìn)行的操作如下:

  1. Redis父進(jìn)程首先判斷:當(dāng)前是否在執(zhí)行save,或bgsave/bgrewriteaof(后面會(huì)詳細(xì)介紹該命令)的子進(jìn)程,如果在執(zhí)行則bgsave命令直接返回。bgsave/bgrewriteaof 的子進(jìn)程不能同時(shí)執(zhí)行,主要是基于性能方面的考慮:兩個(gè)并發(fā)的子進(jìn)程同時(shí)執(zhí)行大量的磁盤寫操作,可能引起嚴(yán)重的性能問題。

  2. 父進(jìn)程執(zhí)行fork操作創(chuàng)建子進(jìn)程,這個(gè)過程中父進(jìn)程是阻塞的,Redis不能執(zhí)行來自客戶端的任何命令

  3. 父進(jìn)程fork后,bgsave命令返回”Background saving started”信息并不再阻塞父進(jìn)程,并可以響應(yīng)其他命令

  4. 子進(jìn)程創(chuàng)建RDB文件,根據(jù)父進(jìn)程內(nèi)存快照生成臨時(shí)快照文件,完成后對(duì)原有文件進(jìn)行原子替換

  5. 子進(jìn)程發(fā)送信號(hào)給父進(jìn)程表示完成,父進(jìn)程更新統(tǒng)計(jì)信息

RDB 文件分析

存儲(chǔ)文件
路徑和名字的配置

我默認(rèn)采用的是和配置同路徑


image.png

動(dòng)態(tài)設(shè)定:Redis啟動(dòng)后也可以動(dòng)態(tài)修改RDB存儲(chǔ)路徑,在磁盤損害或空間不足時(shí)非常有用;執(zhí)行命令為config set dir {newdir}和config set dbfilename {newFileName}

RDB文件格式
圖片來源:《Redis設(shè)計(jì)與實(shí)現(xiàn)》

其中各個(gè)字段的含義說明如下:

  1. REDIS:常量,保存著”REDIS”5個(gè)字符。

  2. db_version:RDB文件的版本號(hào),注意不是Redis的版本號(hào)。

  3. SELECTDB 0 pairs:表示一個(gè)完整的數(shù)據(jù)庫(0號(hào)數(shù)據(jù)庫),同理SELECTDB 3 pairs表示完整的3號(hào)數(shù)據(jù)庫;只有當(dāng)數(shù)據(jù)庫中有鍵值對(duì)時(shí),RDB文件中才會(huì)有該數(shù)據(jù)庫的信息(上圖所示的Redis中只有0號(hào)和3號(hào)數(shù)據(jù)庫有鍵值對(duì));如果Redis中所有的數(shù)據(jù)庫都沒有鍵值對(duì),則這一部分直接省略。其中:SELECTDB是一個(gè)常量,代表后面跟著的是數(shù)據(jù)庫號(hào)碼;0和3是數(shù)據(jù)庫號(hào)碼;pairs則存儲(chǔ)了具體的鍵值對(duì)信息,包括key、value值,及其數(shù)據(jù)類型、內(nèi)部編碼、過期時(shí)間、壓縮信息等等。

  4. EOF:常量,標(biāo)志RDB文件正文內(nèi)容結(jié)束。

  5. check_sum:前面所有內(nèi)容的校驗(yàn)和;Redis在載入RBD文件時(shí),會(huì)計(jì)算前面的校驗(yàn)和并與check_sum值比較,判斷文件是否損壞。

壓縮

Redis默認(rèn)采用LZF算法對(duì)RDB文件進(jìn)行壓縮。雖然壓縮耗時(shí),但是可以大大減小RDB文件的體積,因此壓縮默認(rèn)開啟;


image.png

RDB常用配置總結(jié)

下面是RDB常用的配置項(xiàng),以及默認(rèn)值;前面介紹過的這里不再詳細(xì)介紹。

save m n:bgsave自動(dòng)觸發(fā)的條件;如果沒有save m n配置,相當(dāng)于自動(dòng)的RDB持久化關(guān)閉,不過此時(shí)仍可以通過其他方式觸發(fā)

stop-writes-on-bgsave-error yes:當(dāng)bgsave出現(xiàn)錯(cuò)誤時(shí),Redis是否停止執(zhí)行寫命令;設(shè)置為yes,則當(dāng)硬盤出現(xiàn)問題時(shí),可以及時(shí)發(fā)現(xiàn),避免數(shù)據(jù)的大量丟失;設(shè)置為no,則Redis無視bgsave的錯(cuò)誤繼續(xù)執(zhí)行寫命令,當(dāng)對(duì)Redis服務(wù)器的系統(tǒng)(尤其是硬盤)使用了監(jiān)控時(shí),該選項(xiàng)考慮設(shè)置為no

rdbcompression yes:是否開啟RDB文件壓縮

rdbchecksum yes:是否開啟RDB文件的校驗(yàn),在寫入文件和讀取文件時(shí)都起作用;關(guān)閉checksum在寫入文件和啟動(dòng)文件時(shí)大約能帶來10%的性能提升,但是數(shù)據(jù)損壞時(shí)無法發(fā)現(xiàn)

dbfilename dump.rdb:RDB文件名

dir ./:RDB文件和AOF文件所在目錄

RDB持久化機(jī)制的優(yōu)點(diǎn)和缺點(diǎn)

優(yōu)點(diǎn)

(1)RDB會(huì)生成多個(gè)數(shù)據(jù)文件,每個(gè)數(shù)據(jù)文件都代表了某一個(gè)時(shí)刻中redis的數(shù)據(jù),這種多個(gè)數(shù)據(jù)文件的方式,非常適合做冷備,可以將這種完整的數(shù)據(jù)文件發(fā)送到一些遠(yuǎn)程的安全存儲(chǔ)上去,比如說Amazon的S3云服務(wù)上去,在國內(nèi)可以是阿里云的ODPS分布式存儲(chǔ)上,以預(yù)定好的備份策略來定期備份redis中的數(shù)據(jù)

(2)RDB對(duì)redis對(duì)外提供的讀寫服務(wù),影響非常小,可以讓redis保持高性能,因?yàn)閞edis主進(jìn)程只需要fork一個(gè)子進(jìn)程,讓子進(jìn)程執(zhí)行磁盤IO操作來進(jìn)行RDB持久化即可

(3)相對(duì)于AOF持久化機(jī)制來說,直接基于RDB數(shù)據(jù)文件來重啟和恢復(fù)redis進(jìn)程,更加快速

缺點(diǎn)

(1)如果想要在redis故障時(shí),盡可能少的丟失數(shù)據(jù),那么RDB沒有AOF好。一般來說,RDB數(shù)據(jù)快照文件,都是每隔5分鐘,或者更長時(shí)間生成一次,這個(gè)時(shí)候就得接受一旦redis進(jìn)程宕機(jī),那么會(huì)丟失最近5分鐘的數(shù)據(jù)
(2)RDB每次在fork子進(jìn)程來執(zhí)行RDB快照數(shù)據(jù)文件生成的時(shí)候,如果數(shù)據(jù)文件特別大,可能會(huì)導(dǎo)致對(duì)客戶端提供的服務(wù)暫停數(shù)毫秒,或者甚至數(shù)秒

AOF 持久化策略

RDB持久化是將進(jìn)程數(shù)據(jù)寫入文件,而AOF持久化(即Append Only File持久化),則是將Redis執(zhí)行的每次寫命令記錄到單獨(dú)的日志文件中(有點(diǎn)像MySQL的binlog);當(dāng)Redis重啟時(shí)再次執(zhí)行AOF文件中的命令來恢復(fù)數(shù)據(jù)。

與RDB相比,AOF的實(shí)時(shí)性更好,因此已成為主流的持久化方案。

開啟AOF

Redis服務(wù)器默認(rèn)開啟RDB,關(guān)閉AOF;要開啟AOF,需要在配置文件中配置:
appendonly yes

執(zhí)行流程

由于需要記錄Redis的每條寫命令,因此AOF不需要觸發(fā),下面介紹AOF的執(zhí)行流程。

AOF的執(zhí)行流程包括:

  • 命令追加(append):將Redis的寫命令追加到緩沖區(qū)aof_buf;
  • 文件寫入(write)和文件同步(sync):根據(jù)不同的同步策略將aof_buf中的內(nèi)容同步到硬盤;
  • 文件重寫(rewrite):定期重寫AOF文件,達(dá)到壓縮的目的。

命令追加(append)

Redis先將寫命令追加到緩沖區(qū),而不是直接寫入文件,主要是為了避免每次有寫命令都直接寫入硬盤,導(dǎo)致硬盤IO成為Redis負(fù)載的瓶頸。
命令追加的格式是Redis命令請求的協(xié)議格式,它是一種純文本格式,具有兼容性好、可讀性強(qiáng)、容易處理、操作簡單避免二次開銷等優(yōu)點(diǎn);具體格式略。在AOF文件中,除了用于指定數(shù)據(jù)庫的select命令(如select 0 為選中0號(hào)數(shù)據(jù)庫)是由Redis添加的,其他都是客戶端發(fā)送來的寫命令。

文件寫入(write)和文件同步(sync)

Redis提供了多種AOF緩存區(qū)的同步文件策略,策略涉及到操作系統(tǒng)的write函數(shù)和fsync函數(shù),說明如下:
為了提高文件寫入效率,在現(xiàn)代操作系統(tǒng)中,當(dāng)用戶調(diào)用write函數(shù)將數(shù)據(jù)寫入文件時(shí),操作系統(tǒng)通常會(huì)將數(shù)據(jù)暫存到一個(gè)內(nèi)存緩沖區(qū)里,當(dāng)緩沖區(qū)被填滿或超過了指定時(shí)限后,才真正將緩沖區(qū)的數(shù)據(jù)寫入到硬盤里。這樣的操作雖然提高了效率,但也帶來了安全問題:如果計(jì)算機(jī)停機(jī),內(nèi)存緩沖區(qū)中的數(shù)據(jù)會(huì)丟失;因此系統(tǒng)同時(shí)提供了fsync、fdatasync等同步函數(shù),可以強(qiáng)制操作系統(tǒng)立刻將緩沖區(qū)中的數(shù)據(jù)寫入到硬盤里,從而確保數(shù)據(jù)的安全性。
AOF緩存區(qū)的同步文件策略由參數(shù)appendfsync控制,各個(gè)值的含義如下:

always:命令寫入aof_buf后立即調(diào)用系統(tǒng)fsync操作同步到AOF文件,fsync完成后線程返回。這種情況下,每次有寫命令都要同步到AOF文件,硬盤IO成為性能瓶頸,Redis只能支持大約幾百TPS寫入,嚴(yán)重降低了Redis的性能;即便是使用固態(tài)硬盤(SSD),每秒大約也只能處理幾萬個(gè)命令,而且會(huì)大大降低SSD的壽命。

no:命令寫入aof_buf后調(diào)用系統(tǒng)write操作,不對(duì)AOF文件做fsync同步;同步由操作系統(tǒng)負(fù)責(zé),通常同步周期為30秒。這種情況下,文件同步的時(shí)間不可控,且緩沖區(qū)中堆積的數(shù)據(jù)會(huì)很多,數(shù)據(jù)安全性無法保證。
everysec:命令寫入aof_buf后調(diào)用系統(tǒng)write操作,write完成后線程返回;fsync同步文件操作由專門的線程每秒調(diào)用一次。everysec是前述兩種策略的折中,是性能和數(shù)據(jù)安全性的平衡,因此是Redis的默認(rèn)配置,也是我們推薦的配置。

文件重寫(rewrite)

隨著時(shí)間流逝,Redis服務(wù)器執(zhí)行的寫命令越來越多,AOF文件也會(huì)越來越大;過大的AOF文件不僅會(huì)影響服務(wù)器的正常運(yùn)行,也會(huì)導(dǎo)致數(shù)據(jù)恢復(fù)需要的時(shí)間過長。
文件重寫是指定期重寫AOF文件,減小AOF文件的體積。需要注意的是,AOF重寫是把Redis進(jìn)程內(nèi)的數(shù)據(jù)轉(zhuǎn)化為寫命令,同步到新的AOF文件;不會(huì)對(duì)舊的AOF文件進(jìn)行任何讀取、寫入操作!
關(guān)于文件重寫需要注意的另一點(diǎn)是:對(duì)于AOF持久化來說,文件重寫雖然是強(qiáng)烈推薦的,但并不是必須的;即使沒有文件重寫,數(shù)據(jù)也可以被持久化并在Redis啟動(dòng)的時(shí)候?qū)?;因此在一些?shí)現(xiàn)中,會(huì)關(guān)閉自動(dòng)的文件重寫,然后通過定時(shí)任務(wù)在每天的某一時(shí)刻定時(shí)執(zhí)行。
文件重寫之所以能夠壓縮AOF文件,原因在于:
過期的數(shù)據(jù)不再寫入文件,無效的命令不再寫入文件:如有些數(shù)據(jù)被重復(fù)設(shè)值(set mykey v1, set mykey v2)、有些數(shù)據(jù)被刪除了(sadd myset v1, del myset)等等,多條命令可以合并為一個(gè):如sadd myset v1, sadd myset v2, sadd myset v3可以合并為sadd myset v1 v2 v3。不過為了防止單條命令過大造成客戶端緩沖區(qū)溢出,對(duì)于list、set、hash、zset類型的key,并不一定只使用一條命令;而是以某個(gè)常量為界將命令拆分為多條。這個(gè)常量在redis.h/REDIS_AOF_REWRITE_ITEMS_PER_CMD中定義,不可更改,3.0版本中值是64。
通過上述內(nèi)容可以看出,由于重寫后AOF執(zhí)行的命令減少了,文件重寫既可以減少文件占用的空間,也可以加快恢復(fù)速度。

文件重寫的觸發(fā)

文件重寫的觸發(fā),分為手動(dòng)觸發(fā)和自動(dòng)觸發(fā):

  1. 手動(dòng)觸發(fā):直接調(diào)用bgrewriteaof命令,該命令的執(zhí)行與bgsave有些類似:都是fork子進(jìn)程進(jìn)行具體的工作,且都只有在fork時(shí)阻塞。


    image.png

2.自動(dòng)觸發(fā):根據(jù)auto-aof-rewrite-min-sizeauto-aof-rewrite-percentage參數(shù),以及aof_current_sizeaof_base_size狀態(tài)確定觸發(fā)時(shí)機(jī)。
auto-aof-rewrite-min-size:執(zhí)行AOF重寫時(shí),文件的最小體積,默認(rèn)值為64MB。
auto-aof-rewrite-percentage:執(zhí)行AOF重寫時(shí),當(dāng)前AOF大小(即aof_current_size)和上一次重寫時(shí)AOF大小(aof_base_size)的比值。
其中,參數(shù)可以通過config get命令查看:

image.png

AOF文件重寫的流程
image.png

對(duì)照上圖,文件重寫的流程如下:

  1. Redis父進(jìn)程首先判斷當(dāng)前是否存在正在執(zhí)行 bgsave/bgrewriteaof的子進(jìn)程,如果存在則bgrewriteaof命令直接返回,如果存在bgsave命令則等bgsave執(zhí)行完成后再執(zhí)行。前面曾介紹過,這個(gè)主要是基于性能方面的考慮。

  2. 父進(jìn)程執(zhí)行fork操作創(chuàng)建子進(jìn)程,這個(gè)過程中父進(jìn)程是阻塞的。

3.1 父進(jìn)程fork后,bgrewriteaof命令返回”Background append only file rewrite started”信息并不再阻塞父進(jìn)程,并可以響應(yīng)其他命令。Redis的所有寫命令依然寫入AOF緩沖區(qū),并根據(jù)appendfsync策略同步到硬盤,保證原有AOF機(jī)制的正確。

3.2 由于fork操作使用寫時(shí)復(fù)制技術(shù),子進(jìn)程只能共享fork操作時(shí)的內(nèi)存數(shù)據(jù)。由于父進(jìn)程依然在響應(yīng)命令,因此Redis使用AOF重寫緩沖區(qū)(圖中的aof_rewrite_buf)保存這部分?jǐn)?shù)據(jù),防止新AOF文件生成期間丟失這部分?jǐn)?shù)據(jù)。也就是說,bgrewriteaof執(zhí)行期間,Redis的寫命令同時(shí)追加到aof_buf和aof_rewirte_buf兩個(gè)緩沖區(qū)。

  1. 子進(jìn)程根據(jù)內(nèi)存快照,按照命令合并規(guī)則寫入到新的AOF文件。

5.1 子進(jìn)程寫完新的AOF文件后,向父進(jìn)程發(fā)信號(hào),父進(jìn)程更新統(tǒng)計(jì)信息,具體可以通過info persistence查看。

5.2 父進(jìn)程把AOF重寫緩沖區(qū)的數(shù)據(jù)寫入到新的AOF文件,這樣就保證了新AOF文件所保存的數(shù)據(jù)庫狀態(tài)和服務(wù)器當(dāng)前狀態(tài)一致。

5.3 使用新的AOF文件替換老文件,完成AOF重寫。

啟動(dòng)時(shí)加載

注意只有配置文件開始 AOF 的時(shí)候啟動(dòng)才會(huì)加載AOF文件,如果文件不存在,也不會(huì)去加載的RDB

AOF常用配置總結(jié)

appendonly no:是否開啟AOF

appendfilename "appendonly.aof":AOF文件名
dir ./:RDB文件和AOF文件所在目錄

appendfsync everysec:fsync持久化策略

no-appendfsync-on-rewrite no:AOF重寫期間是否禁止fsync;如果開啟該選項(xiàng),可以減輕文件重寫時(shí)CPU和硬盤的負(fù)載(尤其是硬盤),但是可能會(huì)丟失AOF重寫期間的數(shù)據(jù);需要在負(fù)載和安全性之間進(jìn)行平衡

auto-aof-rewrite-percentage 100:文件重寫觸發(fā)條件之一

auto-aof-rewrite-min-size 64mb:文件重寫觸發(fā)提交之一

aof-load-truncated yes:如果AOF文件結(jié)尾損壞,Redis啟動(dòng)時(shí)是否仍載入AOF文件

AOF持久化機(jī)制的優(yōu)點(diǎn)和缺點(diǎn)

優(yōu)點(diǎn)

(1)AOF可以更好的保護(hù)數(shù)據(jù)不丟失,一般AOF會(huì)每隔1秒,通過一個(gè)后臺(tái)線程執(zhí)行一次fsync操作,最多丟失1秒鐘的數(shù)據(jù)

(2)AOF日志文件以append-only模式寫入,所以沒有任何磁盤尋址的開銷,寫入性能非常高,而且文件不容易破損,即使文件尾部破損,也很容易修復(fù)

(3)AOF日志文件即使過大的時(shí)候,出現(xiàn)后臺(tái)重寫操作,也不會(huì)影響客戶端的讀寫。因?yàn)樵趓ewrite log的時(shí)候,會(huì)對(duì)其中的指導(dǎo)進(jìn)行壓縮,創(chuàng)建出一份需要恢復(fù)數(shù)據(jù)的最小日志出來。再創(chuàng)建新日志文件的時(shí)候,老的日志文件還是照常寫入。當(dāng)新的merge后的日志文件ready的時(shí)候,再交換新老日志文件即可。

(4)AOF日志文件的命令通過非??勺x的方式進(jìn)行記錄,這個(gè)特性非常適合做災(zāi)難性的誤刪除的緊急恢復(fù)。比如某人不小心用flushall命令清空了所有數(shù)據(jù),只要這個(gè)時(shí)候后臺(tái)rewrite還沒有發(fā)生,那么就可以立即拷貝AOF文件,將最后一條flushall命令給刪了,然后再將該AOF文件放回去,就可以通過恢復(fù)機(jī)制,自動(dòng)恢復(fù)所有數(shù)據(jù)

缺點(diǎn)

(1)對(duì)于同一份數(shù)據(jù)來說,AOF日志文件通常比RDB數(shù)據(jù)快照文件更大

(2)AOF開啟后,支持的寫QPS會(huì)比RDB支持的寫QPS低,因?yàn)锳OF一般會(huì)配置成每秒fsync一次日志文件,當(dāng)然,每秒一次fsync,性能也還是很高的。

(3)以前AOF發(fā)生過bug,就是通過AOF記錄的日志,進(jìn)行數(shù)據(jù)恢復(fù)的時(shí)候,沒有恢復(fù)一模一樣的數(shù)據(jù)出來。所以說,類似AOF這種較為復(fù)雜的基于命令日志/merge/回放的方式,比基于RDB每次持久化一份完整的數(shù)據(jù)快照文件的方式,更加脆弱一些,容易有bug。不過AOF就是為了避免rewrite過程導(dǎo)致的bug,因此每次rewrite并不是基于舊的指令日志進(jìn)行merge的,而是基于當(dāng)時(shí)內(nèi)存中的數(shù)據(jù)進(jìn)行指令的重新構(gòu)建,這樣健壯性會(huì)好很多。

RDB和AOF到底該如何選擇?

(1)不要僅僅使用RDB,因?yàn)槟菢訒?huì)導(dǎo)致你丟失很多數(shù)據(jù)

(2)也不要僅僅使用AOF,因?yàn)槟菢佑袃蓚€(gè)問題,第一,你通過AOF做冷備,沒有RDB做冷備,來的恢復(fù)速度更快; 第二,RDB每次簡單粗暴生成數(shù)據(jù)快照,更加健壯,可以避免AOF這種復(fù)雜的備份和恢復(fù)機(jī)制的bug

(3)綜合使用AOF和RDB兩種持久化機(jī)制,用AOF來保證數(shù)據(jù)不丟失,作為數(shù)據(jù)恢復(fù)的第一選擇; 用RDB來做不同程度的冷備,在AOF文件都丟失或損壞不可用的時(shí)候,還可以使用RDB來進(jìn)行快速的數(shù)據(jù)恢復(fù)

在主從復(fù)制模式下可以這樣
master:完全關(guān)閉持久化(包括RDB和AOF),這樣可以讓master的性能達(dá)到最好。
slave:關(guān)閉RDB,開啟AOF(如果對(duì)數(shù)據(jù)安全要求不高,開啟RDB關(guān)閉AOF也可以),并定時(shí)對(duì)持久化文件進(jìn)行備份(如備份到其他文件夾,并標(biāo)記好備份的時(shí)間);然后關(guān)閉AOF的自動(dòng)重寫,然后添加定時(shí)任務(wù),在每天Redis閑時(shí)(如凌晨12點(diǎn))調(diào)用bgrewriteaof。
這里需要解釋一下,為什么開啟了主從復(fù)制,可以實(shí)現(xiàn)數(shù)據(jù)的熱備份,還需要設(shè)置持久化呢?因?yàn)樵谝恍┨厥馇闆r下,主從復(fù)制仍然不足以保證數(shù)據(jù)的安全,例如:
master和slave進(jìn)程同時(shí)停止:考慮這樣一種場景,如果master和slave在同一棟大樓或同一個(gè)機(jī)房,則一次停電事故就可能導(dǎo)致master和slave機(jī)器同時(shí)關(guān)機(jī),Redis進(jìn)程停止;如果沒有持久化,則面臨的是數(shù)據(jù)的完全丟失。
master誤重啟:考慮這樣一種場景,master服務(wù)因?yàn)楣收襄吹袅?,如果系統(tǒng)中有自動(dòng)拉起機(jī)制(即檢測到服務(wù)停止后重啟該服務(wù))將master自動(dòng)重啟,由于沒有持久化文件,那么master重啟后數(shù)據(jù)是空的,slave同步數(shù)據(jù)也變成了空的;如果master和slave都沒有持久化,同樣會(huì)面臨數(shù)據(jù)的完全丟失。需要注意的是,即便是使用了哨兵(關(guān)于哨兵后面會(huì)有文章介紹)進(jìn)行自動(dòng)的主從切換,也有可能在哨兵輪詢到master之前,便被自動(dòng)拉起機(jī)制重啟了。因此,應(yīng)盡量避免“自動(dòng)拉起機(jī)制”和“不做持久化”同時(shí)出現(xiàn)。

異地災(zāi)備(同城容災(zāi))
上述討論的幾種持久化策略,針對(duì)的都是一般的系統(tǒng)故障,如進(jìn)程異常退出、宕機(jī)、斷電等,這些故障不會(huì)損壞硬盤。但是對(duì)于一些可能導(dǎo)致硬盤損壞的災(zāi)難情況,如火災(zāi)地震,就需要進(jìn)行異地災(zāi)備。例如對(duì)于單機(jī)的情形,可以定時(shí)將RDB文件或重寫后的AOF文件,通過scp拷貝到遠(yuǎn)程機(jī)器,如阿里云、AWS等;對(duì)于主從的情形,可以定時(shí)在master上執(zhí)行bgsave,然后將RDB文件拷貝到遠(yuǎn)程機(jī)器,或者在slave上執(zhí)行bgrewriteaof重寫AOF文件后,將AOF文件拷貝到遠(yuǎn)程機(jī)器上。一般來說,由于RDB文件文件小、恢復(fù)快,因此災(zāi)難恢復(fù)常用RDB文件;異地備份的頻率根據(jù)數(shù)據(jù)安全性的需要及其他條件來確定,但最好不要低于一天一次。

fork阻塞:CPU的阻塞

在Redis的實(shí)踐中,眾多因素限制了Redis單機(jī)的內(nèi)存不能過大,例如:

  • 當(dāng)面對(duì)請求的暴增,需要從庫擴(kuò)容時(shí),Redis內(nèi)存過大會(huì)導(dǎo)致擴(kuò)容時(shí)間太長;
  • 當(dāng)主機(jī)宕機(jī)時(shí),切換主機(jī)后需要掛載從庫,Redis內(nèi)存過大導(dǎo)致掛載速度過慢;
  • 以及持久化過程中的fork操作

首先說明一下fork操作:
linux 底層中,父進(jìn)程通過fork操作可以創(chuàng)建子進(jìn)程;子進(jìn)程創(chuàng)建后,父子進(jìn)程共享代碼段,不共享進(jìn)程的數(shù)據(jù)空間,但是子進(jìn)程會(huì)獲得父進(jìn)程的數(shù)據(jù)空間的副本。在操作系統(tǒng)fork的實(shí)際實(shí)現(xiàn)中,基本都采用了寫時(shí)復(fù)制技術(shù),即在父/子進(jìn)程試圖修改數(shù)據(jù)空間之前,父子進(jìn)程實(shí)際上共享數(shù)據(jù)空間;但是當(dāng)父/子進(jìn)程的任何一個(gè)試圖修改數(shù)據(jù)空間時(shí),操作系統(tǒng)會(huì)為修改的那一部分(內(nèi)存的一頁)制作一個(gè)副本。
雖然fork時(shí),子進(jìn)程不會(huì)復(fù)制父進(jìn)程的數(shù)據(jù)空間,但是會(huì)復(fù)制內(nèi)存頁表(頁表相當(dāng)于內(nèi)存的索引、目錄);父進(jìn)程的數(shù)據(jù)空間越大,內(nèi)存頁表越大,fork時(shí)復(fù)制耗時(shí)也會(huì)越多。

在Redis中,無論是RDB持久化的bgsave,還是AOF重寫的bgrewriteaof,都需要fork出子進(jìn)程來進(jìn)行操作。如果Redis內(nèi)存過大,會(huì)導(dǎo)致fork操作時(shí)復(fù)制內(nèi)存頁表耗時(shí)過多;而Redis主進(jìn)程在進(jìn)行fork時(shí),是完全阻塞的,也就意味著無法響應(yīng)客戶端的請求,會(huì)造成請求延遲過大。
對(duì)于不同的硬件、不同的操作系統(tǒng),fork操作的耗時(shí)會(huì)有所差別,一般來說,如果Redis單機(jī)內(nèi)存達(dá)到了10GB,fork時(shí)耗時(shí)可能會(huì)達(dá)到百毫秒級(jí)別(如果使用Xen虛擬機(jī),這個(gè)耗時(shí)可能達(dá)到秒級(jí)別)。因此,一般來說Redis單機(jī)內(nèi)存一般要限制在10GB以內(nèi);不過這個(gè)數(shù)據(jù)并不是絕對(duì)的,可以通過觀察線上環(huán)境fork的耗時(shí)來進(jìn)行調(diào)整。觀察的方法如下:執(zhí)行命令info stats,查看latest_fork_usec的值,單位為微秒。
為了減輕fork操作帶來的阻塞問題,那就是買買買,超級(jí)吊的磁盤加上超級(jí)吊的CPU是一個(gè)不錯(cuò)的選擇。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,570評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,505評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評(píng)論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,786評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,219評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,438評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,971評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,796評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,995評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,230評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評(píng)論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,697評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,991評(píng)論 2 374