HBase的Write Ahead Log (WAL) —— 整體架構、執行緒模式【轉】

來源:互聯網
上載者:User

標籤:自增   無鎖   alt   hadoop   strong   多線程   row   如何   檔案中   

轉自:http://www.cnblogs.com/ohuang/p/5807543.html

解決的問題

HBase的Write Ahead Log (WAL)提供了一種高並發、持久化的日誌儲存與回放機制。每一個業務資料的寫入操作(PUT / DELETE)執行前,都會記賬在WAL中。

如果出現HBase伺服器宕機,則可以從WAL中回放執行之前沒有完成的操作。

本文主要探討HBase的WAL機制,如何從執行緒模式、訊息機制的層面上,解決這些問題:

1. 由於多個HBase用戶端可以對某一台HBase Region Server發起並發的業務資料寫入請求,因此WAL也要支援並發的多線程日誌寫入。——確保日誌寫入的安全執行緒、高並發。

2. 對於單個HBase用戶端,它在WAL中的日誌順序,應該與這個用戶端發起的業務資料寫入請求的順序一致。

(對於以上兩點要求,大家很容易想到,用一個隊列就搞定了。見下文的架構圖。)

3. 為了保證高可靠,日誌不僅要寫入檔案系統的記憶體緩衝,而且應該儘快、強制刷到磁碟上(即WAL的Sync操作)。但是Sync太頻繁,效能會變差。所以:

 (1) Sync應當在多個後台線程中非同步執行

 (2) 頻繁的多個Sync,可以合并為一次Sync——適當放鬆對可靠性的要求,提高效能。

 

架構圖——執行緒模式、訊息機制

下面是我畫的HBase WAL架構圖。我在圖上加了不少註解,所以這張圖應該是自解釋的:

 

 

 Region Server RPC服務線程

這些線程處理HBase用戶端通過RPC服務調用(實際上是Google Protobuf服務調用)發出的業務資料寫入請求。在的例子中,“Region Server RPC服務線程1” 做了3個Row的Append操作,和一個強制刷磁碟的Sync操作。

Sync操作是為了確保之前的Append操作(包括涉及的業務資料)一定可靠地記錄到了磁碟上的日誌中,然後HBase才能做後續相對不可靠的複雜操作,比如寫入MemStore。——這就是Write Ahead的語義。

從架構圖中可見,並發的Append操作只是往隊列中增加了Append請求對象。

這裡的隊列是一個LMAX Disrutpor RingBuffer(我的這篇文章作了介紹),你可以簡單理解為是一個無鎖高並發隊列。

Append的具體代碼如下:

 

對於Sync操作:

(1)往隊列裡放一個SyncFuture對象,代表一次Sync操作請求。

每一個SyncFuture都有一個自增的Sequence ID——這是全域唯一的,由LMAX Disrutpor隊列建立。後來的SyncFuture的Sequence ID更高。

(2)調用SyncFuture.get()阻塞等待,直到後台線程(架構圖中的SyncRunner)通知SyncFuture退出阻塞,表明WAL日誌已經儲存在了磁碟上。

 

WAL日誌消費線程

WAL機制中,只有一個WAL日誌消費線程,從隊列中擷取Append和Sync操作。這樣一個多生產者,單消費者的模式,決定了WAL日誌並發寫入時日誌的全域唯一順序。

1. 對於擷取到的Append操作,直接調用Hadoop Sequence File Writer將這個Append操作(包括中繼資料和row key, family, qualifier, timestamp, value等業務資料)寫入檔案。

    因此WAL記錄檔使用的是Hadoop Sequence檔案格式。當然,它也可以替換成其他儲存格式,如Avro。

    Hadoop Sequence檔案格式不再這裡累述,其主要特點是:

   (1) 二進位格式。row key, family, qualifier, timestamp, value等HBase byte[]資料,都原封不動地順序寫入檔案。

   (2) Sequence檔案中,每隔若干行,會插入一個16位元組的魔數作為分隔字元。這樣如果檔案損壞,導致某一行殘缺不全,可以通過這個魔數分隔字元跳過這一行,繼續讀取下一個完整的行。

   (3) 支援壓縮。可以按行壓縮。也可以按塊壓縮(將多行打成一個塊)

2. 對於擷取到的Sync操作,會提交給後台SyncRunner的線程池(見上文架構圖)非同步執行。

以上的this.syncRunners就是SyncRunner線程池。可以看到,通過計算syncRunnerIndex,採用了簡單的輪循提交演算法。

  • 另外,WAL日誌消費線程,會嘗試收集一批SyncFuture對象(即sync操作),一次提交給SyncRunner。

        所以,在以上代碼中,可以看到傳入offer()方法的,是this.syncFutures這一SyncFutures[]數組,而不是單個SyncFuture對象。

        收集一批次再提交,效能比較好。但是單個批次需要積攢的SyncFuture對象越多,則Sync的及時性越差,會導致前台Region Server RPC服務線程阻塞在SyncFuture.get()上的時間就越長。

        因此,這裡存在輸送量和及時性之間的平衡。HBase為了支援海量資料的寫入,在這裡更傾向於高輸送量,體現在了以下注釋中。具體多少個SyncFuture構成一個批次,有一定的策略,在此不再累述。

SyncRunner線程

1. 從隊列中擷取一個由WAL日誌消費線程提交的SyncFuture(紅框中的代碼)。

2. 調用檔案系統API,執行sync()操作(藍框中的代碼)

  • 合并多次頻繁的sync()操作,提高效能。

        上文提到,WAL日誌消費線程一次會提交多個SyncFuture。對此,SyncRunner線程只會落實執行其中最新的SyncFuture(也就是Sequence ID最大的那個)所代表的Sync操作。而忽略之前的SyncFuture。

        這就是綠框中的代碼。

3. 如果sync()完成,或者因為上面提到的合并忽略了某一個SyncFuture,那麼會調用releaseSyncFuture() ==> Object.notify()來通知SyncFuture阻塞退出。

   之前阻塞在SyncFuture.get()上的Region Server RPC服務線程就可以繼續往下執行了。

至此,整個WAL寫入流程完成。

 

總結

我覺得對線程並發寫入檔案時,用隊列來協調,保證日誌寫入的順序,這還是比較容易想到的。

但是,提供Sync() API確保日誌寫入的可靠性,同時避免頻繁的Sync()操作影響效能。——這是HBase WAL實現的一大亮點。

後續我再研究研究WAL的checkpoint和讀取WAL回放機制,再和大家分享。

 

HBase的Write Ahead Log (WAL) —— 整體架構、執行緒模式【轉】

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.