轉(zhuǎn)載--日志

問題概述

在分布式系統(tǒng)中冤吨,宕機是需要考慮的重要組成部分呻右。日志技術是宕機恢復的重要技術之一哑子。日志技術應用廣泛舅列,早些更是廣泛應用在數(shù)據(jù)庫設計實現(xiàn)中肌割。本文先介紹基本原理概念,最后通過redis介紹生產(chǎn)環(huán)境中的實現(xiàn)方法帐要。

Redo Log

數(shù)據(jù)庫設計中把敞,需要滿足ACID,尤其是在支持事務的系統(tǒng)中榨惠。當系統(tǒng)遇到未知錯誤時奋早,可以恢復到一個穩(wěn)定可靠的狀態(tài)。有一個很簡單的思路赠橙,就是記錄所有對數(shù)據(jù)庫的寫操作日志耽装。那么一旦發(fā)生故障,即使丟失掉內(nèi)存中所有數(shù)據(jù)期揪,當下一次啟動時掉奄,通過復現(xiàn)已經(jīng)記錄的數(shù)據(jù)庫寫操作日志,依然可以回到故障之前的狀態(tài)(如果在寫操作作日志的時候發(fā)生故障凤薛,那么這次數(shù)據(jù)庫操作失斝战ā)。

操作流程簡單如下(假設每次數(shù)據(jù)變化缤苫,都提交):

  1. 更新的操作方式依次記錄到磁盤日志文件速兔。
  2. 更新內(nèi)存中的數(shù)據(jù)。
  3. 返回更新成功結果活玲。

恢復流程如下

  1. 讀取日志文件憨栽,依次修改內(nèi)存中的數(shù)據(jù)。

優(yōu)點:

  1. 日志文件有序翼虫,可以通過append的方式寫入磁盤屑柔,性能很高。
  2. 簡單可靠珍剑,應用廣泛掸宛。可以把內(nèi)存中的數(shù)據(jù)招拙,做備份在磁盤中唧瘾。

缺點:

  1. 使用時間一長,恢復宕機的時間很慢别凤。

解決方法

先具體化下饰序,如果我們內(nèi)存中保留一個a的值,記錄了寫操作比如 a = 4; a++; a--; 當這些操作上千萬规哪、億之后求豫,恢復非常慢。甚至可能最后一條就是a=0,按照之前的算法蝠嘉,我們卻跑了很長時間最疆。

那么根據(jù)這個場景,很容易想到一個解決方案蚤告。

操作流程:

  1. 日志文件記錄begin check point
  2. 在某個時刻努酸,把內(nèi)存中的數(shù)值,直接snapshot或dump到磁盤上.(比如直接記錄a=4)
  3. 日志文件記錄end check point

恢復流程:

1.掃描日志文件杜恰,找到最后的end check point中配對的begin check point获诈。
2.讀入dump文件。
3.依次回放記錄的日志操作心褐。

優(yōu)點:

  1. 應用廣泛烙荷,包括 mysql,oracle檬寂。

一些棘手的問題:

  1. 在做snapshot的時候终抽,往往不能停止數(shù)據(jù)庫的服務,那么很可能記錄了begin check point之后的日志桶至。那么在重新load begin check point之后的日志時昼伴,最后恢復的數(shù)據(jù)很有可能不對刃泌。比如我們記錄的是a++這樣的日志, 那么重復一條日志美浦,就會讓a的值加1。反之如果我們記錄是冪等的且改,比如一直是 a=5 這種操作女蜈,那么就對最后結果沒有影響持舆。很顯然,設計冪等操作系統(tǒng)很麻煩伪窖。

  2. 設計一個支持snapshot的內(nèi)存數(shù)據(jù)結構逸寓,也比較麻煩。

典型的是通過copy-on-write機制覆山。和操作系統(tǒng)中的概念一樣竹伸。當這個數(shù)據(jù)結構被修改,就創(chuàng)建一份真正的copy簇宽。老數(shù)據(jù)增加一份dirty flag勋篓。如果沒有修改就繼續(xù)使用之前的內(nèi)存。這樣在做snapshot的時候魏割,保證我們的dump數(shù)據(jù)是begin check point這個時刻的數(shù)據(jù)譬嚣。顯然這個也比較麻煩。

還有一種支持snapshot的思路是begin check point后钞它,不動老的數(shù)據(jù)拜银。內(nèi)存中的數(shù)據(jù)在新的地方殊鞭,日志也寫在新的地方。最后在end check point做一次merge盐股。這個實現(xiàn)起來簡單,但是內(nèi)存消耗不小耻卡。

Redis是如何解決日志問題的

Redis 是一個基于內(nèi)存的database疯汁,不同于memcached,他支持持久化卵酪。另外由于redis處理client request 和 response 都是在一個thread里面幌蚊,也沒有搶占式的調(diào)度系統(tǒng),核心業(yè)務都是按照event loop順序執(zhí)行溃卡,而磁盤寫日志又開銷很大溢豆,所以redis實現(xiàn)日志功能做了很多優(yōu)化。并且提供2種持久化方案瘸羡。我們需要在不同的場景下漩仙,采用不同的方式配置。

snapshotting

某個時刻犹赖,redis會把內(nèi)存中的所有數(shù)據(jù)snapshot到磁盤文件队他。更通俗的說法是fork一個child process,把內(nèi)存中的數(shù)據(jù)序列化到臨時文件峻村,然后在main event loop 中原子的更換文件名麸折。redis,利用了操作系統(tǒng)VM的copy-on-write機制粘昨,在不阻塞主線程的情況下垢啼,利用子進程和父進程共享的data segment實現(xiàn)snapshot。具體是代碼實現(xiàn)在rdb.c, function at rdbSaveBackground

優(yōu)點:

  1. 簡單可靠张肾,如果database 不大芭析,執(zhí)行的效果非常好。

缺點:

1.如果database size 很大吞瞪,每一次snapshot時間非常長放刨。不得不配置大的間隔,提高了宕機時數(shù)據(jù)丟失的風險尸饺。
為了解決上面的問題进统,redis增加了AOF。

Append Only File(AOF)

在database術語中浪听,也被叫做WAL螟碎。如果開啟的AOF的配置,redis會記錄所有寫操作到日志文件中迹栓。那么redis同樣會遇到之前我們提到過的問題掉分。

  1. 即便是追加寫,磁盤的操作依然比內(nèi)存慢好幾個數(shù)量級,頻繁的操作容易產(chǎn)生瓶頸酥郭。
  2. 如果數(shù)據(jù)量操作頻繁华坦,會產(chǎn)生大量的重復日志數(shù)據(jù),導致恢復時間太長不从。比如記錄一條微博的瀏覽量惜姐,會記錄大量重復的+1日志。

那么redis是如何解決的呢椿息?

  1. 文件寫操作消耗的時間很長歹袁,redis會先把記錄日志寫在內(nèi)存buffer中,在每一次event loop 結束之后寝优,根據(jù)配置判斷是否做寫操作条舔。每個buffer的大小有限制,這樣每次寫操作時間不會太長乏矾。
  2. 即便是調(diào)用write操作孟抗,OS并沒有立即寫入磁盤,redis 同樣提供了一些方案決定刷新OS IO buffer的時機(1秒钻心、從不夸浅、每次)。
  3. redis 提供一種AOF重寫的方式rewriteAppendOnlyFile來處理AOF文件過大情況扔役。

前面我們知道了帆喇,這種check point的機制還是比較麻煩的。那么redis是怎么設計的呢?

rewrite

  1. 為了避免加鎖亿胸,redis 依然創(chuàng)建了一個child process坯钦,利用VM的copy-on-write,共享數(shù)據(jù)侈玄。同時保證主線程依然可以處理client請求婉刀。
  2. 根據(jù)KV的類型,先從內(nèi)存讀取數(shù)據(jù)序仙,然后再寫數(shù)據(jù)到磁盤突颊,和之前的AOF文件無關。
    那么當子進程rewrite AOF的過程中潘悼,main thread依然可以處理新的client request律秃。新增的數(shù)據(jù)會被放在rewrite buffer中,而且寫到原有的AOF文件中治唤。
  3. child process完成后會通知主線程棒动。主線程有一個定時任務,也就是會不斷輪詢child process是否已經(jīng)完成(通過信號量)宾添。
  4. 主線程會merge 變化的數(shù)據(jù)到temp file船惨。
  5. 主線程原子的rename到一個新的AOF文件柜裸,老AOF就不起作用了。

優(yōu)點:

  1. 除了merge 和 rename需要阻塞主線程粱锐,rewrite不會阻塞主線程疙挺。(前提是使用bgrewrite command)。

最后

這些都是性能和穩(wěn)定性之間做的權衡怜浅,根據(jù)不同場景需要調(diào)整铐然。

參考

Redis latency problems troubleshooting
分布式系統(tǒng)原理介紹
Thoughts on Redis

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市海雪,隨后出現(xiàn)的幾起案子锦爵,更是在濱河造成了極大的恐慌舱殿,老刑警劉巖奥裸,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異沪袭,居然都是意外死亡湾宙,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門冈绊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來侠鳄,“玉大人,你說我怎么就攤上這事死宣∥岸瘢” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵毅该,是天一觀的道長博秫。 經(jīng)常有香客問我,道長眶掌,這世上最難降的妖魔是什么挡育? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮朴爬,結果婚禮上即寒,老公的妹妹穿的比我還像新娘。我一直安慰自己召噩,他們只是感情好母赵,可當我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著具滴,像睡著了一般市咽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上抵蚊,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天施绎,我揣著相機與錄音溯革,去河邊找鬼。 笑死谷醉,一個胖子當著我的面吹牛致稀,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播俱尼,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼抖单,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了遇八?” 一聲冷哼從身側(cè)響起矛绘,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎刃永,沒想到半個月后货矮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡斯够,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年囚玫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片读规。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡抓督,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出束亏,到底是詐尸還是另有隱情铃在,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布碍遍,位于F島的核電站定铜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏雀久。R本人自食惡果不足惜宿稀,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赖捌。 院中可真熱鬧祝沸,春花似錦、人聲如沸越庇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卤唉。三九已至涩惑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間桑驱,已是汗流浹背竭恬。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工跛蛋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人痊硕。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓赊级,卻偏偏與公主長得像,于是被迫代替她去往敵國和親岔绸。 傳聞我的和親對象是個殘疾皇子理逊,可洞房花燭夜當晚...
    茶點故事閱讀 42,802評論 2 345

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