(轉(zhuǎn)載)Redis AOF與REWRITE機(jī)制

Redis AOF 簡介

Redis AOF是類似于log的機(jī)制慌核,每次寫操作都會寫到硬盤上距境,當(dāng)系統(tǒng)崩潰時,可以通過AOF來恢復(fù)數(shù)據(jù)垮卓。每個帶有寫操作的命令被Redis服務(wù)器端收到運(yùn)行時垫桂,該命令都會被記錄到AOF文件上。由于只是一個append到文件操作粟按,所以寫到硬盤上的操作往往非澄芴玻快。

其實(shí)Redis oaf機(jī)制包括了兩件事灭将,rewrite和AOF疼鸟。rewrite類似于普通數(shù)據(jù)庫管理系統(tǒng)日志恢復(fù)點(diǎn),當(dāng)AOF文件隨著寫命令的運(yùn)行膨脹時庙曙,當(dāng)文件大小觸碰到臨界時空镜,rewrite會被運(yùn)行。
rewrite會像replication一樣,fork出一個子進(jìn)程姑裂,創(chuàng)建一個臨時文件,遍歷數(shù)據(jù)庫男旗,將每個key舶斧、value對輸出到臨時文件。輸出格式就是Redis的命令察皇,但是為了減小文件大小茴厉,會將多個key、value對集合起來用一條命令表達(dá)什荣。在rewrite期間的寫操作會保存在內(nèi)存的rewrite buffer中矾缓,rewrite成功后這些操作也會復(fù)制到臨時文件中,在最后臨時文件會代替AOF文件稻爬。
以上在AOF打開的情況下嗜闻,如果AOF是關(guān)閉的,那么rewrite操作可以通過bgrewriteaof命令來進(jìn)行桅锄。

Redis AOF流程

Redis Server啟動琉雳,如果AOF機(jī)制打開那么初始化AOF狀態(tài),并且如果存在AOF文件友瘤,讀取AOF文件翠肘。
隨著Redis不斷接受命令,每個寫命令都被添加到AOF文件辫秧,AOF文件膨脹到需要rewrite時又或者接收到客戶端的bgrewriteaof命令束倍。
fork出一個子進(jìn)程進(jìn)行rewrite,而父進(jìn)程繼續(xù)接受命令盟戏,現(xiàn)在的寫操作命令都會被額外添加到一個aof_rewrite_buf_blocks緩沖中绪妹。
當(dāng)子進(jìn)程rewrite結(jié)束后,父進(jìn)程收到子進(jìn)程退出信號抓半,把a(bǔ)of_rewrite_buf_blocks的緩沖添加到rewrite后的文件中喂急,然后切換AOF的文件fd。rewrite任務(wù)完成笛求,繼續(xù)第二個步驟廊移。
關(guān)鍵點(diǎn)

由于寫操作通常是有緩沖的,所以有可能AOF操作并沒有寫到硬盤中探入,一般可以通過fsync()來強(qiáng)制輸出到硬盤中狡孔。而fsync()的頻率可以通過配置文件中的flush策略來指定,可以選擇每次事件循環(huán)寫操作都強(qiáng)制fsync或者每秒fsync至少運(yùn)行一次蜂嗽。
當(dāng)rewrite子進(jìn)程開始后苗膝,父進(jìn)程接受到的命令會添加到aof_rewrite_buf_blocks中,使得rewrite成功后植旧,將這些命令添加到新文件中辱揭。在rewrite過程中离唐,原來的AOF也可以選擇是不是繼續(xù)添加,由于存在性能上的問題问窃,在rewrite過程中亥鬓,如果fsync()繼續(xù)執(zhí)行,會導(dǎo)致IO性能受損影響Redis性能域庇。所以一般情況下rewrite期間禁止fsync()到舊AOF文件嵌戈。這策略可以在配置文件中修改。
在rewrite結(jié)束后听皿,在將新rewrite文件重命名為配置中指定的文件時熟呛,如果舊AOF存在,那么會unlink掉舊文件尉姨。這是就存在一個問題庵朝,處理rewrite文件遷移的是主線程,rename(oldpath, newpath)過程會覆蓋舊文件啊送,這是rename會unlink(oldfd)偿短,而unlink操作會導(dǎo)致block主線程。這時馋没,我們就需要類似libeio(http://software.schmorp.de/pkg/libeio.html)這樣的庫去進(jìn)行異步的底層IO昔逗。作者在bio.c有一個類似的機(jī)制,通過創(chuàng)建新線程來進(jìn)行異步操作篷朵。
==========================================================================================================

  • 自動的bgrewriteaof

為了避免aof文件過大勾怒,我們會周期性的做bgrewriteaof來重整aof文件。以前我們會額外的配置crontab在業(yè)務(wù)低峰期執(zhí)行這個命令声旺,這額外的增加一個workaroud的腳本任務(wù)在大集群里是很糟糕的笔链,不易檢查,出錯無法即時發(fā)現(xiàn)腮猖。

于是這個自動bgrewriteaof功能被直接加到redis的內(nèi)部鉴扫。首先對于aof文件,server對象添加一個字段來記錄aof文件的大小server.appendonly_current_size澈缺,每次aof發(fā)生變化都會維護(hù)這個字段坪创。

aof.c

=================
116     nwritten = write(server.appendfd,server.aofbuf姐赡,sdslen(server.aofbuf));
.....
128     server.appendonly_current_size += nwritten;
bgrewriteaof完畢或者實(shí)例啟動載入aof數(shù)據(jù)后也會調(diào)用aofUpdateCurrentSize這個函數(shù)維護(hù)這個字段莱预,同時會記錄下此時的aof文件的大小server.auto_aofrewrite_base_size作為基準(zhǔn)值,用于接下來判斷aof增長率项滑。

aof.c

=================
385     aofUpdateCurrentSize();
386     server.auto_aofrewrite_base_size = server.appendonly_current_size;
有了當(dāng)前值和基準(zhǔn)值我們就可以判斷aof文件的增長情況依沮。另外還需要配置兩個參數(shù)來判斷是否需要自動觸發(fā)bgrewriteaof。

redis.h

===============
int auto_aofrewrite_perc; /* Rewrite AOF if % growth is > M and... */
off_t auto_aofrewrite_min_size; /* the AOF file is at least N bytes. */

auto_aofrewrite_perc: aof文件的大小超過基準(zhǔn)百分之多少后觸發(fā)bgrewriteaof。默認(rèn)這個值設(shè)置為100危喉,意味著當(dāng)前aof是基準(zhǔn)大小的兩倍的時候觸發(fā)bgrewriteaof宋渔。把它設(shè)置為0可以禁用自動觸發(fā)的功能。
auto_aofrewrite_min_size: 當(dāng)前aof文件大于多少字節(jié)后才觸發(fā)辜限。避免在aof較小的時候無謂行為傻谁。默認(rèn)大小為64mb。
兩個參數(shù)都是可以在conf里靜態(tài)配置列粪,或者通過config set來動態(tài)修改的。

redis 127.0.0.1:6379> config get auto-aof-rewrite-percentage
1) "auto-aof-rewrite-percentage"
2) "100"
redis 127.0.0.1:6379> config get auto-aof-rewrite-min-size
1) "auto-aof-rewrite-min-size"
2) "1048576"
redis 127.0.0.1:6379> config get auto-aof-rewrite-min-size
1) "auto-aof-rewrite-min-size"
2) "1048576"
redis 127.0.0.1:6379> config set auto-aof-rewrite-percentage 200
OK
redis 127.0.0.1:6379> config set auto-aof-rewrite-min-size 10485760
OK

然后就是觸發(fā)檢查的主邏輯谈飒,serverCron時間事件中每次都會檢查現(xiàn)有狀態(tài)和參數(shù)來判斷是否需要啟動bgrewriteaof岂座。

redis.c

===============
635          if (server.bgsavechildpid == -1 &&
 636              server.bgrewritechildpid == -1 &&
 637              server.auto_aofrewrite_perc &&
 638              server.appendonly_current_size > server.auto_aofrewrite_min_size)
 639          {
 640             long long base = server.auto_aofrewrite_base_size ?
 641                             server.auto_aofrewrite_base_size : 1;
 642             long long growth = (server.appendonly_current_size*100/base) - 100;
 643             if (growth >= server.auto_aofrewrite_perc) {
 644                 redisLog(REDIS_NOTICE,"Starting automatic rewriting of AOF on %lld%% growth"杭措,growth);
 645                 rewriteAppendOnlyFileBackground();
 646             }
 647         }

以上代碼顯示费什,如果aof文件增長百分率growth大于auto_aofrewrite_perc,則自動的觸發(fā)后一個bgrewriteaof手素。

  • 延遲bgrewriteaof

這是個小的改進(jìn)鸳址,手動觸發(fā)的bgrewriteaof的時候如果同時存在bgsave在備份,會推遲這次操走的事件泉懦,設(shè)置server.aofrewrite_scheduled=1稿黍,待到bgsave結(jié)束后的下一次serverCron里才會觸發(fā)。

設(shè)置aofrewrite_scheduled=1

aof.c

706 void bgrewriteaofCommand(redisClient *c) {
707     if (server.bgrewritechildpid != -1) {
708         addReplyError(c崩哩,"Background append only file rewriting already in progress");
709     } else if (server.bgsavechildpid != -1) {
710         server.aofrewrite_scheduled = 1;
711         addReplyStatus(c巡球,"Background append only file rewriting scheduled");
712     } else if (rewriteAppendOnlyFileBackground() == REDIS_OK) {
713         addReplyStatus(c,"Background append only file rewriting started");
714     } else {
715         addReply(c邓嘹,shared.err);
716     }
717 }
  • 觸發(fā)bgrewriteaof

redis.c

 598     if (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1 &&
 599         server.aofrewrite_scheduled)
 600     {
 601         rewriteAppendOnlyFileBackground();
 602    }
 

總結(jié):

  • rewrite機(jī)制:aof里存放了所有的redis 操作指令酣栈,當(dāng)aof文件達(dá)到一定條件或者手動

  • bgrewriteaof命令都可以觸發(fā)rewrite。

rewrite之后aof文件會保存keys的最后的狀態(tài)汹押,清除掉之前冗余的矿筝,來縮小這個文件。

  • 自動觸發(fā)的條件:
 long long growth =(server.appendonly_current_size*100/base) - 100;
 if (growth >=server.auto_aofrewrite_perc)

在配置文件里設(shè)置過:

auto-aof-rewrite-percentage 100 (當(dāng)前寫入日志文件的大小超過上一次rewrite之后的文件大小的百分之100時就是2倍時觸發(fā)Rewrite)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末棚贾,一起剝皮案震驚了整個濱河市窖维,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鸟悴,老刑警劉巖陈辱,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異细诸,居然都是意外死亡沛贪,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來利赋,“玉大人水评,你說我怎么就攤上這事∶乃停” “怎么了中燥?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長塘偎。 經(jīng)常有香客問我疗涉,道長,這世上最難降的妖魔是什么吟秩? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任咱扣,我火速辦了婚禮,結(jié)果婚禮上涵防,老公的妹妹穿的比我還像新娘闹伪。我一直安慰自己,他們只是感情好壮池,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布偏瓤。 她就那樣靜靜地躺著,像睡著了一般椰憋。 火紅的嫁衣襯著肌膚如雪厅克。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天橙依,我揣著相機(jī)與錄音已骇,去河邊找鬼。 笑死票编,一個胖子當(dāng)著我的面吹牛褪储,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播慧域,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼鲤竹,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了昔榴?” 一聲冷哼從身側(cè)響起辛藻,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎互订,沒想到半個月后吱肌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡仰禽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年氮墨,在試婚紗的時候發(fā)現(xiàn)自己被綠了纺蛆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡规揪,死狀恐怖桥氏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情猛铅,我是刑警寧澤字支,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站奸忽,受9級特大地震影響堕伪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜栗菜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一刃跛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧苛萎,春花似錦、人聲如沸检号。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽齐苛。三九已至翘盖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間凹蜂,已是汗流浹背馍驯。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留玛痊,地道東北人汰瘫。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像擂煞,于是被迫代替她去往敵國和親混弥。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 一对省、Redis高可用概述 在介紹Redis高可用之前蝗拿,先說明一下在Redis的語境中高可用的含義。 我們知道蒿涎,在w...
    空語閱讀 1,597評論 0 2
  • 本文檔翻譯自http://redis.io/topics/persistence哀托。 這篇文章提供了 Redis 持...
    daos閱讀 694評論 0 10
  • 企業(yè)級redis集群架構(gòu)的特點(diǎn) 海量數(shù)據(jù) 高并發(fā) 高可用 要達(dá)到高可用,持久化是不可減少的劳秋,持久化主要是做災(zāi)難恢復(fù)...
    lucode閱讀 2,206評論 0 7
  • 現(xiàn)在來看仓手,一年做一件最重要的事情胖齐,且去考核這一件事情,是更聰明的做法俗或。 我不記得自己上半年的目標(biāo)是什么了市怎,下半年好...
    來是春初閱讀 297評論 1 2
  • 01. 作為日更打卡的第一天,是不是該戳個章? 02. 籬笆樊墻里 初蕊鵝黃綠 問君何駐足 香飄十萬里 03. 所...
    小阿雪dx閱讀 264評論 0 0