Braft的日志存儲引擎實現(xiàn)分析

Braft的日志存儲引擎實現(xiàn)分析

1.架構(gòu)設(shè)計

1.1 函數(shù)接口說明

日志存儲引擎是用于存儲raft lib產(chǎn)生的日志菌瘪。提供的接口如下:

class LogStorage {
public:
    virtual ~LogStorage() {}

    // init logstorage, check consistency and integrity
    virtual int init(ConfigurationManager* configuration_manager) = 0;

    // first log index in log
    virtual int64_t first_log_index() = 0;

    // last log index in log
    virtual int64_t last_log_index() = 0;

    // get logentry by index
    virtual LogEntry* get_entry(const int64_t index) = 0;

    // get logentry's term by index
    virtual int64_t get_term(const int64_t index) = 0;

    // append entries to log
    virtual int append_entry(const LogEntry* entry) = 0;

    // append entries to log, return append success number
    virtual int append_entries(const std::vector<LogEntry*>& entries) = 0;

    // delete logs from storage's head, [first_log_index, first_index_kept) will be discarded
    virtual int truncate_prefix(const int64_t first_index_kept) = 0;

    // delete uncommitted logs from storage's tail, (last_index_kept, last_log_index] will be discarded
    virtual int truncate_suffix(const int64_t last_index_kept) = 0;

    // Drop all the existing logs and reset next log index to |next_log_index|.
    // This function is called after installing snapshot from leader
    virtual int reset(const int64_t next_log_index) = 0;

    // Create an instance of this kind of LogStorage with the parameters encoded 
    // in |uri|
    // Return the address referenced to the instance on success, NULL otherwise.
    virtual LogStorage* new_instance(const std::string& uri) const = 0;

    static LogStorage* create(const std::string& uri);
};

LogStorage只是一個抽象類衔彻,只定義了函數(shù)接口方援。具體的日志操作由SegmentLogStorage實現(xiàn)薛耻。

1.2 存儲引擎的數(shù)據(jù)組織

SegmentLogStorage實現(xiàn)了LogStorage的全部接口床玻。其數(shù)據(jù)組織格式如下:


image.png
  • segment名字為first_raft_index-last_raft_index翼虫,表示該segment的raft index范圍屑柔。
  • 只有最后一個segment可讀寫,其文件名為log_inprogress_first_raft_index珍剑,其他segment只讀掸宛。
  • segment文件對應(yīng)的index entry,Segment文件初始化時構(gòu)造出來招拙,存儲在內(nèi)存中唧瘾。不會持久化到磁盤。因此追加一次Log Entry只會引起一次磁盤操作别凤。

2.核心流程實現(xiàn)

2.1 存儲引擎的接口函數(shù)

2.2 存儲引擎的初始化

存儲引擎的初始化操作主要檢查文件信息饰序,將segment的索引信息加載到內(nèi)存,為讀寫操作做準備规哪。


image.png

函數(shù)主要功能如下所述:

  • init函數(shù)是SegmentLogStorage初始化的入口函數(shù)求豫,調(diào)用load_meta函數(shù),list_segment函數(shù)和load_segment函數(shù)诉稍。
  • load_meta函數(shù):從log_meta文件中讀取從SegmentLogStorage的第一個raft index值蝠嘉。
  • list_segment函數(shù):建立起segment的范圍信息,并將范圍異常的segment文件刪除杯巨。范圍信息存儲在一個map表中蚤告,map的key是first_raft_index,value是segment對象。
  • load_segments函數(shù):構(gòu)建出每個segment對應(yīng)的索引項服爷,通過解析segement內(nèi)容完成杜恰。索引項存儲在一個vector中获诈。至此,就可以根據(jù)范圍信息來定位到某個raft_index對應(yīng)的文件偏移箫章。

2.3 寫數(shù)據(jù)流程

寫數(shù)據(jù)到存儲引擎烙荷,會涉及到兩個函數(shù):

 // append entry to log
    int append_entry(const LogEntry* entry);
 // append entries to log, return success append number
   int append_entries(const std::vector<LogEntry*>& entries);

append_entry表示追加單條Log Entry到日志存儲引擎,append_entries用于同時追加多條Log Entry到日志存儲引擎檬寂。兩個函數(shù)主要流程相差不大终抽,我們以append_entries為例,分析一下寫入Log Entry的主要流程桶至。函數(shù)流程圖如下所示:


image.png
  • 檢查日志連續(xù)性:主要檢查last_raft_index 是否和追加的Log Entry保持連續(xù)昼伴。
  • 獲取Last_Segment:檢查last_segment是否超過Max_Segment_Size,如果超過則進行rolling操作(保存最后一個segment镣屹,并生成一個新的segment)圃郊。如果文件大小未超過Max_Segment_Size,則直接返回女蜈。
  • 循環(huán)追加日志:追加Log Entry到文件末尾持舆。
  • Last_Segment強制刷盤:調(diào)用fsync函數(shù)強制刷盤。

2.4 讀數(shù)據(jù)流程

根據(jù)raft_index讀取對應(yīng)的raft Log伪窖,根據(jù)我們前面提到的索引信息逸寓,braft很容易實現(xiàn),流程圖如下所示:


image.png

get_entry是入口函數(shù)覆山,get_segment函數(shù)主要是通過raft_index來定位到segment竹伸,通過之前建立的Map范圍信息很容易定位到。然后根據(jù)每個segment的Vector索引數(shù)組簇宽,定位到raft_index對應(yīng)的文件偏移信息勋篓。然后讀取文件。

2.5 刪除數(shù)據(jù)流程

刪除數(shù)據(jù)分為兩類:

  • 從前往后刪除魏割,對應(yīng)的函數(shù)是:
SegmentLogStorage::truncate_prefix(const int64_t first_index_kept)

truncate_prefix函數(shù)先將first_index_kept保存到Log_meta文件中譬嚣,這樣保證了即使后續(xù)的文件刪除操作失敗時,也可以知道整個日志的起始raft_index是多少钞它。保存完first_index_kept之后拜银,將first_index_kept之前的segment文件全部刪除。

  • 從后往前刪除须揣,對應(yīng)的函數(shù)是:
int SegmentLogStorage::truncate_suffix(const int64_t last_index_kept) 

主要用于raft lib中刪除未達成一致的Log Entry盐股。根據(jù)last_index_kept找到對應(yīng)的文件偏移,然后截斷文件耻卡。如果跨文件疯汁,還需要刪除最后一個segment文件,然后再截斷之前一個segment的內(nèi)容卵酪。

3.測試

在test/test_log.cpp文件中幌蚊,包含SegmentLogStorage類中主要的接口函數(shù)的單元測試谤碳,對理解SegmentLogStorage有比較大的幫助。

4.總結(jié)

Braft的日志存儲引擎溢豆,主要用于存儲raft log蜒简。當(dāng)執(zhí)行完一次snapshot操作后,就可以進行Log Compaction漩仙。將snapshot之前的raft log全部刪除搓茬。這使得Braft可以將Log的索引信息全部存儲在內(nèi)存中,因為存儲引擎中的Raft Log Entry不會太大队他。這樣追加或讀取Raft Log只需要一次磁盤操作卷仑,性能方面有保證。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末麸折,一起剝皮案震驚了整個濱河市锡凝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌垢啼,老刑警劉巖窜锯,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異芭析,居然都是意外死亡锚扎,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門放刨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來工秩,“玉大人尸饺,你說我怎么就攤上這事进统。” “怎么了浪听?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵螟碎,是天一觀的道長。 經(jīng)常有香客問我迹栓,道長掉分,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任克伊,我火速辦了婚禮酥郭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘愿吹。我一直安慰自己不从,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布犁跪。 她就那樣靜靜地躺著椿息,像睡著了一般歹袁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上寝优,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天条舔,我揣著相機與錄音,去河邊找鬼乏矾。 笑死孟抗,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的钻心。 我是一名探鬼主播夸浅,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼扔役!你這毒婦竟也來了帆喇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤亿胸,失蹤者是張志新(化名)和其女友劉穎坯钦,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體侈玄,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡婉刀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了序仙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片突颊。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖潘悼,靈堂內(nèi)的尸體忽然破棺而出律秃,到底是詐尸還是另有隱情,我是刑警寧澤治唤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布棒动,位于F島的核電站,受9級特大地震影響宾添,放射性物質(zhì)發(fā)生泄漏船惨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一缕陕、第九天 我趴在偏房一處隱蔽的房頂上張望粱锐。 院中可真熱鬧,春花似錦扛邑、人聲如沸怜浅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽海雪。三九已至锦爵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間奥裸,已是汗流浹背险掀。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留湾宙,地道東北人樟氢。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像侠鳄,于是被迫代替她去往敵國和親埠啃。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,472評論 2 348

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