解決的問(wèn)題
HBase的Write Ahead Log (WAL)提供了一種高并發(fā)、持久化的日志保存與回放機(jī)制。每一個(gè)業(yè)務(wù)數(shù)據(jù)的寫入操作(PUT / DELETE)執(zhí)行前,都會(huì)記賬在WAL中。
如果出現(xiàn)HBase服務(wù)器宕機(jī),則可以從WAL中回放執(zhí)行之前沒(méi)有完成的操作。
本文主要探討HBase的WAL機(jī)制,如何從線程模型、消息機(jī)制的層面上,解決這些問(wèn)題:
1. 由于多個(gè)HBase客戶端可以對(duì)某一臺(tái)HBase Region Server發(fā)起并發(fā)的業(yè)務(wù)數(shù)據(jù)寫入請(qǐng)求,因此WAL也要支持并發(fā)的多線程日志寫入。——確保日志寫入的線程安全、高并發(fā)。
2. 對(duì)于單個(gè)HBase客戶端,它在WAL中的日志順序,應(yīng)該與這個(gè)客戶端發(fā)起的業(yè)務(wù)數(shù)據(jù)寫入請(qǐng)求的順序一致。
(對(duì)于以上兩點(diǎn)要求,大家很容易想到,用一個(gè)隊(duì)列就搞定了。見(jiàn)下文的架構(gòu)圖。)
3. 為了保證高可靠,日志不僅要寫入文件系統(tǒng)的內(nèi)存緩存,而且應(yīng)該盡快、強(qiáng)制刷到磁盤上(即WAL的Sync操作)。但是Sync太頻繁,性能會(huì)變差。所以:
(1) Sync應(yīng)當(dāng)在多個(gè)后臺(tái)線程中異步執(zhí)行
(2) 頻繁的多個(gè)Sync,可以合并為一次Sync——適當(dāng)放松對(duì)可靠性的要求,提高性能。
架構(gòu)圖——線程模型、消息機(jī)制
下面是我畫的HBase WAL架構(gòu)圖。我在圖上加了不少注解,所以這張圖應(yīng)該是自解釋的:

Region Server RPC服務(wù)線程
這些線程處理HBase客戶端通過(guò)RPC服務(wù)調(diào)用(實(shí)際上是Google Protobuf服務(wù)調(diào)用)發(fā)出的業(yè)務(wù)數(shù)據(jù)寫入請(qǐng)求。在上圖的例子中,“Region Server RPC服務(wù)線程1” 做了3個(gè)Row的Append操作,和一個(gè)強(qiáng)制刷磁盤的Sync操作。
Sync操作是為了確保之前的Append操作(包括涉及的業(yè)務(wù)數(shù)據(jù))一定可靠地記錄到了磁盤上的日志中,然后HBase才能做后續(xù)相對(duì)不可靠的復(fù)雜操作,比如寫入MemStore。——這就是Write Ahead的語(yǔ)義。
從架構(gòu)圖中可見(jiàn),并發(fā)的Append操作只是往隊(duì)列中增加了Append請(qǐng)求對(duì)象。
這里的隊(duì)列是一個(gè)LMAX Disrutpor RingBuffer(我的這篇文章作了介紹),你可以簡(jiǎn)單理解為是一個(gè)無(wú)鎖高并發(fā)隊(duì)列。
Append的具體代碼如下:

對(duì)于Sync操作:
(1)往隊(duì)列里放一個(gè)SyncFuture對(duì)象,代表一次Sync操作請(qǐng)求。
每一個(gè)SyncFuture都有一個(gè)自增的Sequence ID——這是全局唯一的,由LMAX Disrutpor隊(duì)列創(chuàng)建。后來(lái)的SyncFuture的Sequence ID更高。
(2)調(diào)用SyncFuture.get() 阻塞等待 ,直到后臺(tái)線程(架構(gòu)圖中的SyncRunner)通知SyncFuture退出阻塞,表明WAL日志已經(jīng)保存在了磁盤上。

WAL日志消費(fèi)線程
WAL機(jī)制中,只有一個(gè)WAL日志消費(fèi)線程,從隊(duì)列中獲取Append和Sync操作。這樣一個(gè) 多生產(chǎn)者,單消費(fèi)者的模式 ,決定了WAL日志并發(fā)寫入時(shí)日志的全局唯一順序。
1. 對(duì)于獲取到的Append操作,直接調(diào)用Hadoop Sequence File Writer將這個(gè)Append操作(包括元數(shù)據(jù)和row key, family, qualifier, timestamp, value等業(yè)務(wù)數(shù)據(jù))寫入文件。

因此WAL日志文件使用的是Hadoop Sequence文件格式。當(dāng)然,它也可以替換成其他存儲(chǔ)格式,如Avro。
Hadoop Sequence文件格式不再這里累述,其主要特點(diǎn)是:
(1) 二進(jìn)制格式。row key, family, qualifier, timestamp, value等HBase byte[]數(shù)據(jù),都原封不動(dòng)地順序?qū)懭胛募?/p>
(2) Sequence文件中,每隔若干行,會(huì)插入一個(gè)16字節(jié)的魔數(shù)作為分隔符。這樣如果文件損壞,導(dǎo)致某一行殘缺不全,可以通過(guò)這個(gè)魔數(shù)分隔符跳過(guò)這一行,繼續(xù)讀取下一個(gè)完整的行。
(3) 支持壓縮??梢园葱袎嚎s。也可以按塊壓縮(將多行打成一個(gè)塊)
2. 對(duì)于獲取到的Sync操作,會(huì)提交給后臺(tái)SyncRunner的線程池(見(jiàn)上文架構(gòu)圖)異步執(zhí)行。
