HBase的Write Ahead Log (WAL) —— 整體架構、線程模型

来源:http://www.cnblogs.com/ohuang/archive/2016/08/25/5807543.html
-Advertisement-
Play Games

解決的問題 HBase的Write Ahead Log (WAL)提供了一種高併發、持久化的日誌保存與回放機制。每一個業務數據的寫入操作(PUT / DELETE)執行前,都會記賬在WAL中。 如果出現HBase伺服器宕機,則可以從WAL中回放執行之前沒有完成的操作。 本文主要探討HBase的WAL ...


解決的問題

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回放機制,再和大家分享。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 映射是鍵值對偶的集合。Scala有一個通用的叫法——元組:n個對象的聚集,並不一定要相同的類型。 構造映射 鍵A -> 值B scala> val scores = Map("wcc100"->100)//不可變映射 scores: scala.collection.immutable.Map[St ...
  • 以前在acm課上也講過一些關於背包的題,不過那些比較簡單,就是簡單的貪心問題,先排個序再處理就完了,而01背包,感覺就是比那個上了一個難度的問題,這個需要遍歷然後找其中合適的,簡單原理就是這樣。 例如:現在有容量為m的背包,還有重量為w,價值為v的k個不同的商品,問怎樣買才能使價值最大化? 思路:如 ...
  • 1、錯誤原因:系統函數與pcl中的max函數衝突導致的 2、兩種解決辦法: 1)錯誤中max和min函數用括弧括起來,例如"std::Max"修改為“(std::Max)”. 2) 在vs工程屬性中進行修改,“屬性-c++-預處理器-預處理器定義”中加入NOMINMAX ...
  • 概述 Tornado 是 FriendFeed 使用的可擴展的非阻塞式 web 伺服器及其相關工具的開源版本。這個 Web 框架看起來有些像web.py 或者 Google 的 webapp,不過為了能有效利用非阻塞式伺服器環境,這個 Web 框架還包含了一些相關的有用工具 和優化。 Tornado ...
  • 學習記錄 O(∩_∩)O 、 如果你恰巧路過,希望你能停下腳步瞧一瞧,不足之處望指出,感激不盡~ 使用工具: 1、eclipse 2、hibernate壓縮包(hibernate_4.3.11) 3、mysql 準備工作: 創建工程——>導入hibernate.jar包——>編寫 hibernate ...
  • 寫在前面的話 最近一直在邊工作邊學習分散式的東西,看到了構建Java中間件的基礎知識,裡面有提到Java多線程併發的工具類,例如ReentrantLock、CyclicBarrier、CountDownLatch... 以前在工作中也有用到過這些實用的工具類,但是瞭解不是特別深入,藉此機會打個卡,好 ...
  • Web框架本質 眾所周知,對於所有的Web應用,本質上其實就是一個socket服務端,用戶的瀏覽器其實就是一個socket客戶端。 上述通過socket來實現了其本質,而對於真實開發中的python web程式來說,一般會分為兩部分:伺服器程式和應用程式。伺服器程式負責對socket伺服器進行封裝, ...
  • 每一項技術用的人多了,就會有人將其進行優化,做成一個簡單、實用、大眾化的工具,這對於初識者來說是非常方便的,但是對於長久學習或工作這方面的人技術人員來說是不可取的,所以還是要學習基礎的實用方法。因此,我就在ubuntu下配置了Apache伺服器來更深入的學習。 這是一個預設安裝的方法,如果要指定 步 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...