Hadoop之HBase
1、HBase概述
HBase是一個分散式的、面向列的開源資料庫,該技術來源於Fay Chang所撰寫的Google論文——「Bigtable:一個結構化數據的分散式存儲系統」。就像Bigtable利用了Google文件系統(File System)所提供的分散式數據存儲一樣,HBase在Hadoop之上提供了類似於Bigtable的能力。
HBase是Hadoop Database的簡稱,它是Apache的Hadoop項目中的一個子項目,HBase依託於Hadoop的HDFS作為其最基本的存儲單元,通過使用Hadoop的HDFS工具就可以看到這些數據存儲文件夾的結構,還可以通過MapReduce的框架對HBase進行操作。HBase不同於一般的關係型資料庫,它是一個適合於非結構化數據存儲的資料庫,另一個不同點是HBase採用基於列(更準確地說是基於列族)而不是基於行的模式。
HBase是一個數據模型,可以提供快速隨機訪問海量結構化數據的優勢,它還充分利用了Hadoop的文件系統提供的容錯能力。使用HBase在HDFS上讀取消費/隨機訪問數據,並提供讀寫訪問,如下圖所示:
2、HBase的體系結構
在HBase中,表被分割成區域(Region,對應於列族),並由區域伺服器(RegionServer,對應於一個機器節點)提供服務,區域被列族垂直分為「Store_File」,Store_File又以HFile文件的形式被保存在HDFS文件系統中,下圖展示了HBase的體系結構。
Region內部解析:剛開始時數據都直接保存到mem_store內存中,待到mem_store滿時,便會flush成一個Store_File文件,直到增長到一定閾值,便會觸發Compact合併操作,將多個Store_File文件合併成一個大的Store_File文件(對應於HFile),同時進行版本合併和數據刪除;由於HDFS數據塊大小默認是128M,為了節省空間及提高效率,這個大的Store_File文件(也就是HFile),將以一個數據塊的大小128M保存到HDFS文件系統中。
HBase主要由三部分構成,即客戶端Client、主伺服器HMaster以及區域伺服器Region Server,區域伺服器可按照應用需求進行添加和刪除。
A、客戶端Client
包含訪問HBase的介面,並維護cache來加快對HBase的訪問,比如Region的位置信息等。
B、主伺服器HMaster
為Region Server分配Region;
負責Region Server的負載均衡;
發現失效的Region Server並重新分配其上的Region;
管理用戶對table的增刪改查操作。
C、區域伺服器RegionServer
Region Server維護Region,處理對這些Region的IO請求;
Region Server負責切分在運行過程中變得過大的Region。
D、Zookeeper
通過選舉,保證在任何時候,集群中只有一個主伺服器HMaster,HMaster與RegionServer啟動時會向Zookeeper註冊;
存儲所有Region的定址入口;
實時監控RegionServer的上線和下線信息,並實時通知給HMaster;
存儲HBase的schema和table元數據;
默認情況下,HBase管理Zookeeper實例,比如啟動或者停止Zookeeper;
Zookeeper的引入,解決了HMaster單點故障的問題。
3、HBase的特點
A、HBase的存儲機制
HBase是一個面向列的資料庫,在表中它由行排序,表模式定義為列族,也就是鍵值對,一個表有多個列族(需要在創建表時就指定)以及每一個列族可以有任意數量的列,後續列的值連續地存儲在磁碟上。表中的每個單元格值都具有時間戳(HBase默認添加)。總的來說,在一個HBase中:
表是行的集合;
行是列族的結合;
列族是列的集合;
列是鍵值對的集合。
舉一個HBase表的實例,其表結構如下圖所示,需要注意的是,rowkey(類似於關係型資料庫中的主鍵)是可以重複的,相同的rowkey記錄的是同一行數據;一個列族對應於一個Region。
B、HBase和HDFS
兩者都具有良好的容錯性和擴展性,都可以擴展成百上千個節點。HBase適用於大數據量存儲,大數據量高並發操作,適用於需要對數據進行隨機讀寫的簡單操作;HDFS適用於批處理場景,不支持數據隨機查找,不適合增量數據處理,不支持數據更新。
下面的表格簡單地類比了HBase和HDFS。
C、面向行和面向列
面向列的資料庫是將數據表作為數據列的部分進行存儲,而不是作為數據行進行存儲;面向列的資料庫相對來說,對於大數據量的查詢操作具有較高的效率,而面向行的資料庫,對於增、刪、改這些操作具有較高的效率。下面的表格對列式資料庫和行式資料庫進行了簡單的類比。
D、HBase和RDBMS
下面的表格簡單類比了基於列的資料庫HBase與通用的關係型資料庫RDBMS。
E、HBase容錯性
HMaster容錯:Zookeeper重新選舉出一個新的HMaster,在沒有HMaster的過程中,數據讀取仍照常進行,但region切分、負載均衡等操作無法進行;
RegionServer容錯:定時向Zookeeper彙報心跳,如果一定時間內未出現心跳,HMaster將該RegionServer上的Region重新分配到其他RegionServer上,失效伺服器上「預寫」日誌由主伺服器進行分割並派送給新的RegionServer;
在分散式系統環境中,無法避免系統出錯或者宕機,一旦HRegionServer意外退出,mem_store中的內存數據就會丟失,引入HLog就是為了防止這種情況。其工作機制是:每個HRegionServer中都會有一個HLog對象,每次用戶操作寫入mem_store的同時,也會寫一份數據到HLog文件,HLog文件定期會滾動出新,並刪除舊的文件(對應已經持久化到Store_File中的數據)。當HRegionServer意外終止後,HMaster會通過Zookeeper感知,HMaster首先處理遺留的HLog文件,將不同Region的log數據拆分,分別放到相應Region目錄下,然後再將失效的Region(帶有剛剛拆分的log)重新分配,領取到這些Region的HRegionServer在Load Region的過程中,會發現有歷史HLog需要處理,因此會Replay HLog中的數據到mem_store中,然後flush到Store_File,完成數據恢復。
Zookeeper容錯:Zookeeper是一個可靠的服務,一般配置3到5個Zookeeper實例。
4、HBase數據讀/寫流程
A、HBase表數據的寫入流程
1)client先去訪問Zookeeper,從Zookeeper上獲取meta表的位置信息;
以前的版本hbase的系統表除了meta表還有root表;
在root表中存儲了meta表的位置信息;
新版本中將meta表的位置信息直接存入ZooKeeper中
2)client向meta表的region所在的regionserver發起訪問,讀取meta表的數據,獲取HBase集群上所有的表的元數據;
3)根據meta表的元數據信息(如某張表有幾個region及region如何分配及每個reigon的startkey和stopkey等),client找到當前要寫入的表對應的Region及所在RegionServer;
4)client向對應的RegionServer發起寫入請求;
5)RegionServer收到client請求並響應,client先把數據寫入到Hlog防止數據丟失;
6)再把數據寫入到mem_store內存緩存區(默認大小128M);
7)當數據寫入到Hlog及mem_store內存緩存區都成功時,寫入才算成功;
8)當mem_store達到128M或其他的因素觸發,會將mem_store中的數據flush成Store_File;
9)當Store_File越來越多,會觸發compact合併,將多個Store_File文件最終合併成一個文件;
合併分為minor compact和major compact;
在大合併期間打上『刪除』標籤的cell或者過期的cell會被統一清理
10)當某個store下的某個storeFile文件的最終合併後的大小達到10G時,會觸發整個region的split分割,一個region一分為二,由master進行分配;
B、HBase表數據的讀取過程
1)client先去訪問Zookeeper,從Zookeeper上獲取meta表的位置信息;
2)client向meta表的Region所在的RegionServer發起訪問,讀取meta表的數據,獲取HBase集群上所有表的元數據;
3)根據meta表的元數據信息(如某張表有幾個Region及Region如何分配及每個Reigon的startkey和stopkey),client找到當前要寫入的表對應的Region及所在RegionServer;
4)client向對應的RegionServer發起讀請求;
5)RegionServer收到客戶端的讀請求,會先掃描mem_store,再掃描blockcache(讀緩存),沒有找到數據,再去讀取Store_File文件;
6)RegionServer將數據返回給client。
5、Region分裂詳解
A、Region分裂的產生
在最初時,HBase中數據量會比較小,僅需要保存到一個Region上(如保存於下圖中的RegionServer1)。隨著數據量的增大,當HBase通過自檢查發現滿足相應的條件,觸發Region分裂(在HBase中不可避免會發生)使得Region數量變多並進行重新分布,如RegionServer1上先前的Region分裂成兩個,並將其中一個Region中的數據拷貝到其他RegionServer上的Region中,如下圖中的RegionServer2,該過程簡單描述如下圖。
因此,由於Region分裂的存在,需要採取其他必要的措施或進行合理規劃,將Region分裂產生的影響儘可能降到最低,防止對網路造成過大壓力,使整個環境崩潰。
B、尋找分裂點SplitPoint
Region分裂策略會觸發Region分裂,分裂開始之後的第一件事是尋找分裂點-SplitPoint。所有默認分裂策略,無論是ConstantSizeRegionSplit Policy、IncreasingToUpperBoundRegionSplitPolicy 抑或是SteppingSplit Policy,對於分裂點的定義都是一致的。當然,用戶手動執行分裂時是可以指定分裂點進行分裂的。
那分裂點是如何定位的呢? 整個Region中最大store中的最大文件中最中心的一個block的首個rowkey 。這是一句比較消耗腦力的語句,需要細細品味。另外,HBase還規定,如果定位到的rowkey是整個文件的首個rowkey或者最後一個rowkey的話,就認為沒有分裂點。
什麼情況下會出現沒有分裂點的場景呢?最常見的就是一個文件只有一個block,執行split的時候就會發現無法分裂。很多朋友在測試split的時候往往都是新建一張新表,然後往新表中插入幾條數據並執行一下flush,再執行split,奇蹟般地發現數據表並沒有真正執行分裂。
C、Region核心分裂流程
HBase將整個分裂過程包裝成了一個事務,意圖能夠保證分裂事務的原子性。整個分裂事務過程分為如下三個階段:prepare– execute – rollback,操作模板如下圖所示:
prepare階段:在內存中初始化兩個子Region,具體是生成兩個HRegionInfo對象,包含tableName、regionName、startkey、endkey等。同時會生成一個transactionjournal,這個對象用來記錄分裂的進展,具體見rollback階段。
execute階段:分裂的核心操作。如下圖所示:
具體過程如下:
1)、RegionServer更改ZK節點/region-in-transition中該Region的狀態為SPLITING;
2)、Master通過watch節點/region-in-transition檢測到Region狀態改變,並修改內存中Region的狀態,在Master頁面RIT模塊就可以看到Region執行split的狀態信息;
3)、在父存儲目錄下新建臨時文件夾.split保存split後的daughter region信息;
4)、關閉parent region:parent region關閉數據寫入並觸發flush操作,將寫入Region的數據全部持久化到磁碟。此後,短時間內客戶端落在父Region上的請求都會拋出異常NotServingRegionException;
5)、核心分裂步驟:在.split文件夾下新建兩個子文件夾,稱之為daughter A、daughter B,並在文件夾中生成reference文件,分別指向父Region中對應文件。這個步驟是所有操作步驟中最核心的一個環節;
6)、父Region分裂為兩個子Region後,將daughter A、daughter B拷貝到HBase根目錄下,形成兩個新的Region;
7)、parent region通知修改hbase.meta表後下線,不再提供服務。下線後parent region在meta表中的信息並不會馬上刪除,而是標註split列、offline列為true,並記錄兩個子Region;
8)、開啟daughter A、daughter B兩個子Region。通知修改hbase.meta表,正式對外提供服務。
rollback階段:如果execute階段出現異常,則執行rollback操作。為了實現回滾,整個分裂過程被分為很多子階段,回滾程序會根據當前進展到哪個子階段清理對應的垃圾數據。代碼中使用JournalEntryType來表徵各個子階段。
D、Region切分事務性保證
整個Region分裂是一個比較複雜的過程,涉及到父Region中HFile文件的切分、兩個子Region的生成、系統meta元數據的更改等很多子步驟,因此必須保證整個分裂過程的事務性,即要麼分裂完全成功,要麼分裂完全未開始,在任何情況下也不能出現分裂只完成一半的情況。
為了實現分裂的事務性,hbase設計了使用狀態機的方式保存分裂過程中的每個子步驟狀態,這樣一旦出現異常,系統可以根據當前所處的狀態決定是否回滾,以及如何回滾。遺憾的是,目前實現中這些中間狀態都只存儲在內存中,因此一旦在分裂過程中出現RegionServer宕機的情況,有可能會出現分裂處於中間狀態的情況,也就是RIT狀態。這種情況下需要使用hbck工具進行具體查看並分析解決方案。在2.0版本之後,HBase實現了新的分散式事務框架Procedure V2(HBASE-12439),新框架將會使用HLog存儲這種單機事務(DDL操作、Split操作、Move操作等)的中間狀態,因此可以保證即使在事務執行過程中參與者發生了宕機,依然可以使用HLog作為協調者對事務進行回滾操作或者重試提交,大大減少甚至杜絕RIT現象。
E、Region分裂對其他模塊的影響
通過Region分裂流程的了解,我們知道整個Region分裂過程並沒有涉及數據的移動,所以分裂本身的成本並不是很高,可以很快完成。分裂後子Region的文件實際沒有任何用戶數據,文件中存儲的僅是一些元數據信息,如分裂點rowkey等,那通過引用文件如何查找數據呢?子Region的數據實際在什麼時候完成真正遷移?數據遷移完成之後父Region什麼時候會被刪掉?
1)通過reference文件如何查找數據?
這裡就能看到reference文件名、文件內容的實際意義,整個操作流程如下所示:
i.根據reference文件名(Region名+真實文件名)定位到真實數據所在文件路徑;
ii.定位到真實數據文件就可以在整個文件中掃描待查KV了么?非也。因為reference文件通常都只引用了數據文件的一半數據,以分裂點為界,要麼上半部分文件數據,要麼下半部分數據。那到底是哪部分數據?分裂點又是哪個點?還記得上文提到的reference文件的文件內容吧,沒錯,就記錄在該文件中。
2)父Region的數據什麼時候會遷移到子Region目錄?
答案是子Region發生major_compaction時。我們知道compaction的執行實際上是將store中所有小文件一個KV一個KV從小到大讀出來之後再順序寫入一個大文件,完成之後再將小文件刪掉,因此compaction本身就需要讀取並寫入大量數據。子Region執行major_compaction後會將父目錄中屬於該子Region的所有數據讀出來並寫入子Region目錄數據文件中。可見將數據遷移放到compaction這個階段來做,是一件順其自然的事情。
3)父Region什麼時候會被刪除?
實際上HMaster會啟動一個線程定期遍歷檢查所有處於splitting狀態的父Region,以確定父Region是否可以被清理。檢測線程首先會在meta表中揪出所有split列為true的Region,並載入出其分裂後生成的兩個子Region(meta表中splitA列和splitB列),只需要檢查這兩個子Region是否還存在引用文件,如果都不存在引用文件就可以認為該父Region對應的文件可以被刪除。
TAG:程序猿的修身養性 |