天天看點

深入探讨HBASE

HBASE基礎

1. HBase簡介

HBase是一個高可靠、高性能、面向列的,主要用于海量結構化和半結構化資料存儲的分布式key-value存儲系統。

它基于Google Bigtable開源實作,但二者有明顯的差別:Google Bigtable基于GFS存儲,通過MAPREDUCE處理存儲的資料,通過chubby處理協同服務;而HBase底層存儲基于hdfs,可以利用MapReduce、Spark等計算引擎處理其存儲的資料,通過Zookeeper作為處理HBase叢集協同服務。

2. HBase表結構

HBase以表的形式将資料最終存儲的hdfs上,建表時無需指定表中字段,隻需指定若幹個列簇即可。插入資料時,指定任意多個列到指定的列簇中。通過行鍵、列簇、列和時間戳可以對資料進行快速定位。

2.1 行鍵(row key)

HBase基于row key唯一辨別一行資料,是用來檢索資料的主鍵。

HBase通過對row key進行字典排序進而對表中資料進行排序。基于這個特性,在設計row key時建議将經常一起讀取的資料存儲在一起。

2.2 列簇(column family)

HBase中的表可以有若幹個列簇,一個列簇下面可以有多個列,必須在建表時指定列簇,但不需要指定列。

一個列族的所有列存儲在同一個底層文存儲件中。

HBase對通路控制、磁盤和記憶體的使用統計都是在列族層面進行的。列族越多,在取一行資料時所要參與IO、搜尋的檔案就越多。是以,如果沒有必要,不要設定太多的列族,也不要修改的太頻繁。并且将經常一起查詢的列放到一個列簇中,減少檔案的IO、尋址時間,提升通路性能。

2.3 列(qualifier)

列可以是任意的位元組數組,都唯一屬于一個特定列簇,它也是按照字典順序排序的。

列名都以列簇為字首,常見引用列格式:column family:qualifier,如city:beijing、city:shanghai都屬于city這個列簇。

列值沒有類型和長度限定。

2.4 Cell

通過{row key, column family:qualifier, version}可以唯一确定的存貯單元,cell中的資料全部以位元組碼形式存貯。

2.5 時間戳(timestamp)

每個cell都可以儲存同一份資料的不同版本,不同版本的資料按照時間倒序排序,讀取時優先讀取最新值,并通過時間戳來索引。

時間戳的類型是64位整型,可以由用戶端顯式指派或者由HBase在寫入資料時自動指派(此時時間戳是精确到毫秒的目前系統時間),可以通過顯式生成唯一性的時間戳來避免資料版本沖突。

每個cell中,為了避免資料存在過多版本造成的的存貯、索引等管負擔,HBase提供了兩種資料版本回收方式(可以針對每個列簇進行設定):

1)儲存資料的最新n個版本

2)通過設定資料的生命周期儲存最近一段時間内的版本

将以上特點綜合在一起,就有了如下資料存取模式:

SortedMap<RowKey,List<SortedMap<Column,List<Value,Timestamp>>>>           

第一個SortedMap代表那個表,包含一個列族集合List(多個列族)。列族中包含了另一個SortedMap存儲列和相應的值。

HBASE系統架構

下圖展現了HBase叢集、内部存儲中的主要角色,以及存儲過程中與hdfs的互動:

深入探讨HBASE

下面介紹一下HBase叢集中主要角色的作用:

HMaster

HBase叢集的主節點,可以配置多個,用來實作HA,主要作用:

1.為RegionServer配置設定region

2.負責RegionServer的負載均衡

3.發現失效的RegionServer,重新配置設定它負責的region

4.hdfs上的垃圾檔案回收(标記為删除的且經過major compact的檔案)

5.處理schema更新請求

RegionServer(以下簡稱RS)

HBase叢集的從節點,負責資料存儲,主要作用:

1.RS維護HMaster配置設定給它的region,處理對這些region的IO請求

2.RS負責切分在運作過程中變得過大的region

Zookeeper(以下簡稱ZK)

1.通過選舉,保證任何時候,叢集中隻有一個active master(HMaster與RS啟動時會向ZK注冊)

2.存貯所有region的尋址入口,如-ROOT-表在哪台伺服器上

3.實時監控RS的狀态,将RS的上下線資訊通知HMaster

4.存儲HBase的中繼資料,如有哪些table,每個table有哪些column family

client包含通路HBase的接口,維護着一些緩存來加速對HBase的通路,比如region的位置資訊。

client在通路HBase上資料時不需要HMaster參與(尋址通路ZK和RS,資料讀寫通路RS),HMaster主要維護着table和region的中繼資料資訊,負載很低。

HBASE資料存儲

通過之前的HBase系統架構圖,可以看出:

1.HBase中table在行的方向上分割為多個region,它是HBase負載均衡的最小單元,可以分布在不同的RegionServer上,但是一個region不能拆分到多個RS上

2.region不是實體存儲的最小單元

region由一個或者多個store組成,每個store儲存一個column family。每個store由一個memstore和多個storefile組成,storefile由hfile組成是對hfile的輕量級封裝,存儲在hdfs上。

3.region按大小分割,預設10G,每個表一開始隻有一個region,随着表中資料不斷增加,region不斷增大,當增大到一個閥值時,region就會劃分為兩個新的region。

當表中的資料不斷增多,就會有越來越多的region,這些region由HMaster配置設定給相應的RS,實作負載均衡。

HBase底層存儲基于hdfs,但對于為null的列并不占據存儲空間,并且支援随機讀寫,主要通過以下機制完成:

1.HBase底層存儲結構依賴了LSM樹(Log-structured merge tree)

2.資料寫入時先寫入HLog,然後寫入memstore,當memstore存儲的資料達到門檻值,RS啟動flush cache将memstore中的資料刷寫到storefile

3.用戶端檢索資料時,先在client緩存中找,緩存中找不到則到memstore找,還找不到才會從storefile中查找

4.storefile底層以hfile的形式存儲到hdfs上,當storefile達到一定門檻值會進行合并

5.minor合并和major合并小檔案,删棄做過删除标記的資料

WAL log

即預寫日志,該機制用于資料的容錯和恢複,每次更新都會先寫入日志,隻有寫入成功才會通知用戶端操作成功,然後RS按需自由批量處理和聚合記憶體中的資料。

每個HRegionServer中都有一個HLog對象,它負責記錄資料的所有變更,被同一個RS中的所有region共享。

HLog是一個實作預寫日志的類,在每次使用者操作寫入memstore之前,會先寫一份資料到HLog檔案中,HLog檔案定期會滾動出新的,并删除已經持久化到storefile中的資料的檔案。

當RS意外終止後,HMaster會通過ZK感覺到,HMaster首先會處理遺留的HLog檔案,将其中不同region的日志資料進行拆分,分别放到相應region的目錄下,然後再将失效的region重新配置設定,領取到這些region的HRegionServer在加載region的過程中,如果發現有曆史HLog需要處理,會"重放日志"中的資料到memstore中,然後flush到storefile,完成資料恢複。

HLog檔案就是一個普通的Hadoop Sequence File。

HBASE中LSM樹的應用

1.輸入資料首先存儲在日志檔案 [檔案内資料完全有序,按鍵排序]

2.然後當日志檔案修改時,對應更新會被先儲存在記憶體中來加速查詢

3.資料經過多次修改,且記憶體空間達到設定門檻值,LSM樹将有序的"鍵記錄"flush到磁盤,同時建立一個新的資料存儲檔案。[記憶體中的資料由于已經被持久化了,就會被丢棄]

4.查詢時先從記憶體中查找資料,然後再查找磁盤上的檔案

5.删除隻是“邏輯删除”即将要删除的資料或者過期資料等做删除标記,查找時會跳過這些做了删除标記的資料

6.多次資料刷寫之後會建立許多資料存儲檔案,背景線程會自動将小檔案合并成大檔案。合并過程是重寫一遍資料,major compaction會略過做了删除标記的資料[丢棄]

7.LSM樹利用存儲的連續傳輸能力,以磁盤傳輸速率工作并能較好地擴充以處理大量資料。使用日志檔案和記憶體存儲将随機寫轉換成順序寫

8.LSM樹對磁盤順序讀取做了優化

9.LSM樹的讀和寫是獨立的

HBASE尋址機制

深入探讨HBASE

HBase提供了兩張特殊的目錄表-ROOT-和META表,-ROOT-表用來查詢所有的META表中region位置。HBase設計中隻有一個root region即root region從不進行切分,進而保證類似于B+樹結構的三層查找結構:

第1層:zookeeper中包含root region位置資訊的節點,如-ROOT-表在哪台regionserver上

第2層:從-ROOT-表中查找對應的meta region位置即.META.表所在位置

第3層:從META表中查找使用者表對應region位置

目錄表中的行健由region表名、起始行和ID(通常是以毫秒表示的目前時間)連接配接而成。HBase0.90.0版本開始,主鍵上有另一個散列值附加在後面,目前這個附加部分隻用在使用者表的region中。

注意:

1.root region永遠不會被split,保證了最多需要三次跳轉,就能定位到任意region

2META表每行儲存一個region的位置資訊,row key采用表名+表的最後一行編碼而成

3.為了加快通路,META表的全部region都儲存在記憶體中

4.client會将查詢過的位置資訊儲存緩存起來,緩存不會主動失效,是以如果client上的緩存全部失效,則需要進行最多6次網絡來回,才能定位到正确的region(其中三次用來發現緩存失效,另外三次用來擷取位置資訊)

關于尋址的幾個問題:

1.既然ZK中能儲存-ROOT-資訊,那麼為什麼不把META資訊直接儲存在ZK中,而需要通過-ROOT-表來定位?

ZK不适合儲存大量資料,而META表主要是儲存region和RS的映射資訊,region的數量沒有具體限制,隻要在記憶體允許的範圍内,region數量可以有很多,如果儲存在ZK中,ZK的壓力會很大。

是以,通過一個-ROOT-表來轉存到regionserver中相比直接儲存在ZK中,也就多了一層-ROOT-表的查詢(類似于一個索引表),對性能來說影響不大。

2.client查找到目标位址後,下一次請求還需要走ZK —> -ROOT- —> META這個流程麼?

不需要,client端有緩存,第一次查詢到相應region所在RS後,這個資訊将被緩存到client端,以後每次通路都直接從緩存中擷取RS位址即可。

但是如果通路的region在RS上發生了改變,比如被balancer遷移到其他RS上了,這個時候,通過緩存的位址通路會出現異常,在出現異常的情況下,client需要重新走一遍上面的流程來擷取新的RS位址。

minor合并和major合并

上文提到storefile最終是存儲在hdfs上的,那麼storefile就具有隻讀特性,是以HBase的更新其實是不斷追加的操作。

當一個store中的storefile達到一定的門檻值後,就會進行一次合并,将對同一個key的修改合并到一起,形成一個大的storefile,當storefile的大小達到一定門檻值後,又會對storefile進行split,劃分為兩個storefile。

由于對表的更新是不斷追加的,合并時,需要通路store中全部的storefile和memstore,将它們按row key進行合并,由于storefile和memstore都是經過排序的,并且storefile帶有記憶體中索引,合并的過程還是比較快的。

因為存儲檔案不可修改,HBase是無法通過移除某個鍵/值來簡單的删除資料,而是對删除的資料做個删除标記,表明該資料已被删除,檢索過程中,删除标記掩蓋該資料,用戶端讀取不到該資料。

随着memstore中資料不斷刷寫到磁盤中,會産生越來越多的hfile小檔案,HBase内部通過将多個檔案合并成一個較大的檔案解決這一小檔案問題。

1.minor合并(minor compaction)

将多個小檔案(通過參數配置決定是否滿足合并的條件)重寫為數量較少的大檔案,減少存儲檔案數量(多路歸并),因為hfile的每個檔案都是經過歸類的,是以合并速度很快,主要受磁盤IO性能影響

2)major合并(major compaction)

将一個region中的一個列簇的若幹個hfile重寫為一個新的hfile。而且major合并能掃描所有的鍵/值對,順序重寫全部資料,重寫過程中會略過做了删除标記的資料(超過版本号限制、超過生存時間TTL、用戶端API移除等資料)

region管理

region配置設定

任何時刻,一個region隻能配置設定給一個RS。

HMaster記錄了目前有哪些可用的RS。以及目前哪些region配置設定給了哪些RS,哪些region還沒有配置設定。當需要配置設定的新的region,并且有一個RS上有可用空間時,HMaster就給這個RS發送一個加載請求,把region配置設定給這個RS。RS得到請求後,就開始對此region提供服務。

region server上線

HMaster使用ZK來跟蹤RS狀态。

當某個RS啟動時,會首先在ZK上的server目錄下建立代表自己的znode。由于HMaster訂閱了server目錄上的變更消息,當server目錄下的檔案出現新增或删除操作時,HMaster可以得到來自zookeeper的實時通知。是以一旦RS上線,HMaster能馬上得到消息。

region server下線

當RS下線時,它和ZK的會話斷開,ZK自動釋放代表這台server的檔案上的獨占鎖。HMaster就可以确定RS都無法繼續為它的region提供服務了(比如RS和ZK之間的網絡斷開了或者RS挂了),此時HMaster會删除server目錄下代表這台RS的znode資料,并将這台RS的region配置設定給叢集中還活着的RS

HMaster工作機制

HMaster上線

master啟動之後會做如下事情:

1.從ZK上擷取唯一一個代表active master的鎖,用來阻止其它master成為active master

2.掃描ZK上的server父節點,獲得目前可用的RS清單

3.和每個RS通信,獲得目前已配置設定的region和RS的對應關系

4.掃描.META.region的集合,得到目前還未配置設定的region,将它們放入待配置設定region清單

從上線過程可以看到,HMaster儲存的資訊全是可以從系統其它地方收集到或者計算出來的。

HMaster下線

由于HMaster隻維護表和region的中繼資料,而不參與表資料IO的過程,HMaster下線僅導緻所有中繼資料的修改被當機(無法建立删除表,無法修改表的schema,無法進行region的負載均衡,無法處理region上下線,無法進行region的合并,唯一例外的是region的split可以正常進行,因為隻有region server參與),表的資料讀寫還可以正常進行。是以HMaster下線短時間内對整個HBase叢集沒有影響。

HBASE容錯性

HMaster容錯

配置HA,當active master當機時,通過ZK重新選擇一個新的active master。

1.無HMaster過程中,資料讀取仍照常進行

2.無HMaster過程中,region切分、負載均衡等無法進行

RegionServer容錯

定時向ZK彙報心跳,如果一定時間内未出現心跳,比如RS當機,HMaster将該RS上的region、預寫日志重新配置設定到其他RS上

HBASE資料遷移和備份

1. distcp指令拷貝hdfs檔案的方式

使用MapReduce實作檔案分發,把檔案和目錄的清單當做map任務的輸入,每個任務完成部分檔案的拷貝和傳輸工作。在目标叢集再使用bulkload的方式導入就實作了資料的遷移。

執行完distcp指令後,需要執行hbase hbck -repairHoles修複HBase表中繼資料。缺點在于需要停寫,不然會導緻資料不一緻,比較适合遷移曆史表(資料不會被修改的情況)

2. copytable的方式實作表的遷移和備份

以表級别進行遷移,其本質也是使用MapReduce的方式進行資料的同步,它是利用MapReduce去scan源表資料,然後把scan出來的資料寫到目标叢集,進而實作資料的遷移和備份。示例:

./bin/hbase
org.apache.hadoop.hbase.mapreduce.CopyTable
-Dhbase.client.scanner.caching=300
-Dmapred.map.tasks.speculative.execution=false
-Dmapreduc.local.map.tasks.maximum=20
--peer.adr=zk_address:/hbase
hbase_table_name           

這種方式需要通過scan資料,對于很大的表,如果這個表本身又讀寫比較頻繁的情況下,會對性能造成比較大的影響,并且效率比較低。

copytable常用參數說明(更多參數說明可參考hbase官方文檔)

startrow、stoprow:開始行、結束行

starttime:版本号最小值

endtime:版本号最大值,starttime和endtime必須同時制定

peer.adr:目标hbase叢集位址,格式:hbase.zk.quorum:hbase.zk.client.port:zk.znode.parent

families:要同步的列族,多個列族用逗号分隔

3. replication的方式實作表的複制

類似MySQL binlog日志的同步方式,HBase通過同步WAL日志中所有變更來實作表的同步,異步同步。

需要在兩個叢集資料一樣的情況下開啟複制,預設複制功能是關閉的,配置後需要重新開機叢集,并且如果主叢集資料有出現誤修改,備叢集的資料也會有問題。

4. Export/Import的方式實作表的遷移和備份

和copytable的方式類似,将HBase表的資料轉換成Sequence File并dump到hdfs,也涉及scan表資料。

和copytable不同的是,export不是将HBase的資料scan出來直接put到目标叢集,而是先轉換成檔案并同步到目标叢集,再通過import的方式導到對應的表中。

示例:在老叢集上執行:

./hbaseorg.apache.hadoop.hbase.mapreduce.Export test_tabNamehdfs://ip:port/test           

在新叢集上執行:

./hbase
org.apache.hadoop.hbase.mapreduce.Import test_tabNamehdfs://ip:port/test           

這種方式要求需要在import前在新叢集中将表建好。需要scan資料,會對HBase造成負載的影響,效率不高。

5. snapshot的方式實作表的遷移和備份

通過HBase快照的方式實作HBase資料的遷移和拷貝。示例:

1.在老叢集首先要建立快照:

snapshot 'tabName', 'snapshot_tabName'           

2

../bin/hbase
org.apache.hadoop.hbase.snapshot.ExportSnapshot
-snapshot snapshot_tabName-copy-from hdfs://src-hbase-dir/hbase
-copy-to hdfs://dst-hbase-dir/hbase
-mappers 30
-bandwidth 10           

這種方式比較常用,效率高,也是最為推薦的資料遷移方式。

本文轉載自公衆号:大資料學習與分享

原文連結:

https://mp.weixin.qq.com/s/Mzn9AaswDZ71x6TSUuRNZA

阿裡巴巴開源大資料技術團隊成立Apache Spark中國技術社群,定期推送精彩案例,技術專家直播,問答區近萬人Spark技術同學線上提問答疑,隻為營造純粹的Spark氛圍,歡迎釘釘掃碼加入!

深入探讨HBASE

對開源大資料和感興趣的同學可以加小編微信(下圖二維碼,備注“進群”)進入技術交流微信群。

深入探讨HBASE