通過(guò)上一篇Zeppelin不是飛艇之概述的介紹冯痢,相信讀者已經(jīng)對(duì)Zeppelin有了大致的了解浦楣,這篇就將詳細(xì)介紹其中的存儲(chǔ)節(jié)點(diǎn)集群(Node Server)振劳。存儲(chǔ)節(jié)點(diǎn)負(fù)責(zé)最終的數(shù)據(jù)存儲(chǔ)寸癌,每個(gè)Node Server會(huì)負(fù)責(zé)多個(gè)分片副本弱贼,每個(gè)分片副本對(duì)應(yīng)一個(gè)DB和一個(gè)Binlog溪烤。同一分片的不同副本之間會(huì)建立主從關(guān)系,進(jìn)行數(shù)據(jù)同步槽驶,并在主節(jié)點(diǎn)異常時(shí)自動(dòng)切換掂铐。本文將從請(qǐng)求處理堡纬、線(xiàn)程模型、元信息變化炮叶、副本同步及故障檢測(cè)來(lái)展開(kāi)介紹镜悉,最后總結(jié)在存儲(chǔ)節(jié)點(diǎn)的設(shè)計(jì)開(kāi)發(fā)過(guò)程中的兩點(diǎn)啟發(fā)侣肄。
請(qǐng)求處理
Node Server會(huì)與Client直接連接,接受用戶(hù)請(qǐng)求醇份,處理過(guò)程會(huì)經(jīng)過(guò)如下層級(jí):
Client與存儲(chǔ)節(jié)點(diǎn)Node之間用Protobuf協(xié)議通信稼锅,網(wǎng)絡(luò)模塊會(huì)先進(jìn)行協(xié)議解析;之后進(jìn)入命令的處理層僚纷,區(qū)分命令類(lèi)型矩距,判斷合法性及讀寫(xiě)屬性;寫(xiě)請(qǐng)求會(huì)先寫(xiě)Rocksdb怖竭,之后寫(xiě)B(tài)inlog锥债,Binlog被用來(lái)進(jìn)行副本主從間的數(shù)據(jù)同步;Rocksdb是LSM(The Log-Structured Merge-Tree)的優(yōu)秀實(shí)現(xiàn)痊臭,數(shù)據(jù)會(huì)先被寫(xiě)入Rocksdb的內(nèi)存Memtable及Log,并在之后的Compaction中逐步寫(xiě)入不同層級(jí)的SST文件中去。
線(xiàn)程模型
Zeppelin的線(xiàn)程模型如下圖所示:
通過(guò)不同的顏色我們將Zeppelin的線(xiàn)程分為四大塊:
用戶(hù)命令處理模塊:包括紅色顯示的Dispatch Thread和Worker Thread蹋凝,Dispatch線(xiàn)程接受請(qǐng)求,建立連接,并將連接分發(fā)給不同的Worker線(xiàn)程;Worker線(xiàn)程與Client通信盗扇,接受請(qǐng)求斑鼻、處理命令史汗、返回結(jié)果悼瓮。
副本同步模塊:如圖中藍(lán)色所示命贴,TrySync線(xiàn)程為所有本節(jié)點(diǎn)負(fù)責(zé)的Slave分片向Master發(fā)起數(shù)據(jù)同步請(qǐng)求樱报;Binlog Sender線(xiàn)程負(fù)責(zé)Binlog的發(fā)送盗飒;Binlog Receiver章喉,Receiver Worker負(fù)責(zé)Binlog的接受和處理,與用戶(hù)命令處理模塊類(lèi)似。
元信息模塊:綠色所示,包括與Meta進(jìn)行心跳的Heartbeat線(xiàn)程及拉取元信息并更新本地狀態(tài)的MetaCmd線(xiàn)程崇败。
后臺(tái)輔助模塊:Binlog Purge線(xiàn)程定時(shí)刪除過(guò)期的Binlog以維持較小的空間占用岸霹,BgSave and DbSync線(xiàn)程負(fù)責(zé)分片的備份及與Slave分片的全量數(shù)據(jù)發(fā)送。
具有1-5工作經(jīng)驗(yàn)的琉历,面對(duì)目前流行的技術(shù)不知從何下手蝇恶,需要突破技術(shù)瓶頸的可以加群贿衍。在公司待久了擎淤,過(guò)得很安逸席吴,但跳槽時(shí)面試碰壁襟交。需要在短時(shí)間內(nèi)進(jìn)修迹鹅、跳槽拿高薪的可以加群蚤霞。如果沒(méi)有工作經(jīng)驗(yàn)删壮,但基礎(chǔ)非常扎實(shí),對(duì)java工作機(jī)制翻擒,常用設(shè)計(jì)思想议慰,常用java開(kāi)發(fā)框架掌握熟練的可以加群。java架構(gòu)群:582505643一起交流。
元信息變化
當(dāng)有節(jié)點(diǎn)起宕烂完,節(jié)點(diǎn)加入退出或創(chuàng)建刪除表等元信息變化時(shí)吻谋,存儲(chǔ)節(jié)點(diǎn)需要感知并作出對(duì)應(yīng)的改變低千。正常情況下,存儲(chǔ)節(jié)點(diǎn)Node與元信息節(jié)點(diǎn)Meta之間維持一個(gè)心跳感帅,Meta通過(guò)心跳向Node發(fā)送當(dāng)前的元信息版本號(hào)Epoch,Node向Meta發(fā)送當(dāng)前負(fù)責(zé)分片的Binlog偏移量金赦。元信息改變時(shí),Node會(huì)從心跳得到更大的Epoch恨诱,這時(shí)Heartbeat線(xiàn)程通知MetaCmd線(xiàn)程向Meta主動(dòng)發(fā)起Pull請(qǐng)求把将,獲得最新的元信息镜雨,之后Node進(jìn)行對(duì)應(yīng)的主從遷移,分片添加刪除等操作。
副本同步
Zeppelin的副本之間采用異步復(fù)制的方式城豁,由Slave發(fā)起建立主從關(guān)系攒盈,當(dāng)存儲(chǔ)節(jié)點(diǎn)發(fā)現(xiàn)自己所負(fù)責(zé)的分片有主從關(guān)系變化時(shí),會(huì)觸發(fā)Slave向?qū)?yīng)的Master發(fā)起TrySync請(qǐng)求喉酌,TrySync中攜帶Slave當(dāng)前的Binlog偏移,Master從該偏移順序發(fā)送Binlog信息蔬捷。下圖所示是主從之間配合數(shù)據(jù)同步的線(xiàn)程關(guān)系备恤。
Binlog
Binlog支持尾部的Append操作,由多個(gè)固定大小的文件組成锦秒,文件編號(hào)和文件內(nèi)偏移一起標(biāo)記一個(gè)Binlog位置露泊。如下圖所示,每條用戶(hù)的寫(xiě)請(qǐng)求被記錄在一個(gè)Record中旅择,Record Header記錄了Value的Length惭笑,校驗(yàn)Checksum及類(lèi)型Type,Type Full表示Record被完整的記錄在一個(gè)Block中生真,F(xiàn)irst沉噩,Middle,Last表示該Record橫跨多個(gè)Block柱蟀,當(dāng)前是開(kāi)頭川蒙,中間或是結(jié)尾的部分。
可以看出每個(gè)Record的解析长已,十分依賴(lài)從Header中讀到的Length畜眨,那么當(dāng)Binlog文件中有一小段損壞時(shí),就會(huì)因?yàn)闊o(wú)法找到后一條而損失整個(gè)Binlog文件术瓮,為了降低這個(gè)損失康聂,Binlog被劃分為固定大小的Block,每個(gè)Block的開(kāi)頭都保證是一個(gè)Record開(kāi)頭胞四,Binlog損壞時(shí)恬汁,只需要略過(guò)當(dāng)前Block,繼續(xù)后續(xù)的解析辜伟。
Binlog發(fā)送
當(dāng)主從關(guān)系建立以后氓侧,Master副本需要不斷的給Slave副本發(fā)送Binlog信息。我們之前提到游昼,一個(gè)分片都會(huì)對(duì)應(yīng)一個(gè)Binlog,當(dāng)有很多分片時(shí)尝蠕,就沒(méi)有辦法給每個(gè)Binlog分配一個(gè)發(fā)送線(xiàn)程烘豌。因此Zeppelin采用了如下圖所示機(jī)制:當(dāng)前存儲(chǔ)節(jié)點(diǎn)所負(fù)責(zé)的每個(gè)Master分片的Binlog發(fā)送任務(wù)被封裝為一個(gè)Task,Task中記錄其對(duì)應(yīng)的Table看彼,分片號(hào)廊佩,目標(biāo)Slave節(jié)點(diǎn)地址,當(dāng)前要發(fā)送的Binlog位置(文件號(hào)加文件內(nèi)偏移)靖榕。所有的Task被排成一個(gè)FIFO隊(duì)列标锄,固定個(gè)數(shù)的Binglog發(fā)送線(xiàn)程從隊(duì)列頭中取出一個(gè)Task,服務(wù)固定的時(shí)間片長(zhǎng)度后將其插回隊(duì)列尾部茁计。
針對(duì)每個(gè)Task料皇,Binlog發(fā)送線(xiàn)程會(huì)從當(dāng)前的Binlog偏移量發(fā)送順序發(fā)送Binlog Record的內(nèi)容給對(duì)應(yīng)的Slave的接受線(xiàn)程,并更新Binlog偏移。
Binlog接收
對(duì)應(yīng)節(jié)點(diǎn)的Binlog Receive線(xiàn)程會(huì)接受所有來(lái)自不同Master分片的Binlog消息践剂,按照分片號(hào)分發(fā)給多個(gè)Binlog Worker鬼譬,Binlog Worker順序執(zhí)行Binlog消息,同樣要寫(xiě)DB及Binlog逊脯,從而完成與Master分片的數(shù)據(jù)同步优质。
Binlog壓縮及全同步
可以看出Binlog同樣需要占用大量的磁盤(pán)空間,為了不使這種消耗無(wú)限增長(zhǎng)军洼,Zeppelin設(shè)置保留Binlog的時(shí)間和個(gè)數(shù)巩螃,并定時(shí)清理不需要的Binlog文件,稱(chēng)為Binlog壓縮匕争。
這帶來(lái)了新的問(wèn)題避乏,當(dāng)Master收到Trysync請(qǐng)求時(shí),發(fā)現(xiàn)Slave的Binlog 偏移量指向的Binlog文件已經(jīng)被刪除汗捡,正常的部分同步無(wú)法建立淑际。這時(shí)就需要全同步的過(guò)程,Master分片會(huì)先將當(dāng)前的DB打一個(gè)快照扇住,并將這個(gè)快照及快照對(duì)應(yīng)的Binlog位置發(fā)送給Slave春缕,Slave替換自己的DB,并用新的Binlog位置發(fā)起新的Trysync過(guò)程艘蹋。
Zeppelin利用LSM引擎所有文件寫(xiě)入后只會(huì)刪除不會(huì)修改的特性锄贼,通過(guò)硬鏈實(shí)現(xiàn)秒級(jí)的快照,同時(shí)快照本身也不會(huì)占用過(guò)多空間女阀。相關(guān)內(nèi)容可以參考Rocksdb Checkpoint宅荤。
Binlog一致
需要注意的是分片副本間主從關(guān)系并不穩(wěn)定,會(huì)由于節(jié)點(diǎn)的起宕或網(wǎng)絡(luò)的中斷自動(dòng)切換浸策,為了保證新的主從關(guān)系可以正常建立冯键,我們要求每個(gè)Binlog Record的位置在所有的副本看來(lái)是一致的,也就是副本間的Binlog一致庸汗。Zeppelin采取了如下策略:
Binlog檢查拒絕機(jī)制:Slave副本檢查Binlog的發(fā)送方地址惫确、發(fā)送方元信息版本及前一條Binlog的偏移,拒絕錯(cuò)誤的Binlog請(qǐng)求蚯舱。這些信息也需要在Master副本所發(fā)送的Binlog請(qǐng)求中攜帶改化。
Trysync偏移回退機(jī)制:當(dāng)Master副本收到Trysync的偏移大于自己或者不合法時(shí),需要通知對(duì)方回退到一個(gè)指定的合法的位置枉昏,以完成主從關(guān)系的正常建立陈肛。這種情況會(huì)發(fā)生在頻繁的副本主從切換。
Master觸發(fā)Skip機(jī)制:Master副本發(fā)現(xiàn)Binlog損壞時(shí)兄裂,會(huì)略過(guò)一個(gè)或多個(gè)Block句旱,為了保證Binlog一致阳藻,此時(shí)Master需要強(qiáng)制要求所有的Slave略過(guò)同樣長(zhǎng)度的Binlog。通過(guò)特殊的Skip命令來(lái)完成這個(gè)任務(wù)前翎。Slave的Binlog會(huì)填充同樣長(zhǎng)度的一段類(lèi)型為Empty的空白內(nèi)容稚配。
具有1-5工作經(jīng)驗(yàn)的,面對(duì)目前流行的技術(shù)不知從何下手港华,需要突破技術(shù)瓶頸的可以加群道川。在公司待久了,過(guò)得很安逸立宜,但跳槽時(shí)面試碰壁冒萄。需要在短時(shí)間內(nèi)進(jìn)修、跳槽拿高薪的可以加群橙数。如果沒(méi)有工作經(jīng)驗(yàn)尊流,但基礎(chǔ)非常扎實(shí),對(duì)java工作機(jī)制灯帮,常用設(shè)計(jì)思想崖技,常用java開(kāi)發(fā)框架掌握熟練的可以加群。java架構(gòu)群:582505643一起交流钟哥。
故障檢測(cè)
節(jié)點(diǎn)異常
節(jié)點(diǎn)異常時(shí)迎献,元信息節(jié)點(diǎn)會(huì)感知并完成需要的主從切換,并通知所有的存儲(chǔ)節(jié)點(diǎn)腻贰,發(fā)生變化的節(jié)點(diǎn)會(huì)進(jìn)行狀態(tài)遷移并建立新的主從關(guān)系吁恍。
主從鏈接異常檢測(cè)及恢復(fù)
為了副本復(fù)制的高效,Binlog的發(fā)送采用單向傳輸播演,避免了等待Slave的確認(rèn)信息冀瓦,但這樣就無(wú)法檢測(cè)到主從之間鏈接的異常。Zeppelin復(fù)用了BInlog發(fā)送鏈路來(lái)進(jìn)行異常檢測(cè)写烤,如下圖所示翼闽,左邊為Master節(jié)點(diǎn),右邊為Slave節(jié)點(diǎn):
Slave副本維護(hù)一個(gè)Master的超時(shí)時(shí)間和上一次通信時(shí)間洲炊,收到合法的Binlog請(qǐng)求或Lease命令會(huì)更新通信時(shí)間感局。否則,超時(shí)后觸發(fā)TrySync Moudle發(fā)起新的主動(dòng)同步請(qǐng)求选浑。Master在收到新的TrySync請(qǐng)求后會(huì)用新的Binlog發(fā)送任務(wù)替換之前的蓝厌,從而恢復(fù)Binlog同步過(guò)程玄叠。
Master動(dòng)態(tài)更新Slave超時(shí)時(shí)間:由于我們用固定數(shù)量的Binlog Sender負(fù)責(zé)所有分片的Binlog發(fā)送古徒,上面提到,當(dāng)某個(gè)發(fā)送任務(wù)的時(shí)間片用完后會(huì)被放回到任務(wù)隊(duì)列等待下一次處理读恃,當(dāng)Master負(fù)載較高時(shí)這個(gè)間隙就會(huì)變長(zhǎng)隧膘。為了不讓Slave無(wú)效的觸發(fā)TrySync代态,每次時(shí)間片用完被放回任務(wù)隊(duì)列前,Master都會(huì)向Slave發(fā)送Lease命令疹吃,向Slave刷新自己的超時(shí)時(shí)間蹦疑。這個(gè)超時(shí)是通過(guò)Master節(jié)點(diǎn)的當(dāng)前負(fù)載動(dòng)態(tài)計(jì)算的:
Timeout = MIN((TaskCount * TimeSlice / SenderCount + RedundantTime), MinTime)
Lessons We Learn
1,限制資源線(xiàn)性增長(zhǎng)
分片個(gè)數(shù)是Zeppelin的一個(gè)很重要的參數(shù)萨驶,為了支持更大的集群規(guī)模歉摧,需要更多的分片數(shù)。而因?yàn)榉制菙?shù)據(jù)存儲(chǔ)腔呜,同步叁温,備份的最小單位,分片數(shù)的增多勢(shì)必會(huì)導(dǎo)致資源的膨脹核畴,Zeppelin中做了很多設(shè)計(jì)來(lái)阻止這種資源隨分片數(shù)的線(xiàn)性增長(zhǎng):
減少Binlog發(fā)送線(xiàn)程數(shù):通過(guò)上面介紹Task Pool及Slave的動(dòng)態(tài)租約來(lái)限制Binlog發(fā)送線(xiàn)程數(shù)膝但;
限制Rocksdb實(shí)例增多帶來(lái)的資源壓力:通過(guò)多實(shí)例公用Option來(lái)實(shí)現(xiàn)共享Flush,Compact線(xiàn)程谤草,內(nèi)存配額等跟束;
減少心跳信息:通過(guò)DIFF的方式來(lái)減少Node與Meta之間交互的分片Binlog Offset信息。
2丑孩,異步比同步帶來(lái)更多的成本
無(wú)論是副本同步還是請(qǐng)求處理冀宴,異步方式都會(huì)比同步方式帶來(lái)更好的性能或吞吐。而通過(guò)上面副本同步部分的介紹可以看出嚎杨,由于采用了異步的副本同步方式花鹅,需要增加額外的機(jī)制來(lái)保證Binlog一致,檢測(cè)鏈路異常枫浙,這些都是在同步場(chǎng)景下不需要的刨肃。給了我們一個(gè)啟發(fā)就是應(yīng)該更慎重的考慮異步選項(xiàng)。
之后在Zeppelin不是飛艇之元信息節(jié)點(diǎn)中箩帚,將詳細(xì)介紹Zeppelin的另一個(gè)重要角色Meta真友。