HBase理解
2019獨角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
1.簡介
HBase– Hadoop Database,是一個高可靠性、高性能、面向列、可伸縮的分布式存儲系統(tǒng),利用HBase技術(shù)可在廉價PC Server上搭建起大規(guī)模結(jié)構(gòu)化存儲集群。
HBase是GoogleBigtable的開源實現(xiàn),類似Google Bigtable利用GFS作為其文件存儲系統(tǒng),HBase利用HadoopHDFS作為其文件存儲系統(tǒng);Google運行MapReduce來處理Bigtable中的海量數(shù)據(jù),HBase同樣利用Hadoop MapReduce來處理HBase中的海量數(shù)據(jù);Google Bigtable利用 Chubby作為協(xié)同服務(wù),HBase利用Zookeeper作為對應(yīng)。
上圖描述了Hadoop EcoSystem中的各層系統(tǒng),其中HBase位于結(jié)構(gòu)化存儲層,Hadoop HDFS為HBase提供了高可靠性的底層存儲支持,Hadoop MapReduce為HBase提供了高性能的計算能力,Zookeeper為HBase提供了穩(wěn)定服務(wù)和failover機制。
此外,Pig和Hive還為HBase提供了高層語言支持,使得在HBase上進行數(shù)據(jù)統(tǒng)計處理變的非常簡單。?Sqoop則為HBase提供了方便的RDBMS數(shù)據(jù)導(dǎo)入功能,使得傳統(tǒng)數(shù)據(jù)庫數(shù)據(jù)向HBase中遷移變的非常方便。
2.HBase使用場景
當(dāng)我們對于數(shù)據(jù)結(jié)構(gòu)字段不夠確定或雜亂無章很難按一個概念去進行抽取的數(shù)據(jù)適合用使用什么數(shù)據(jù)庫?答案是什么,如果我們使用的傳統(tǒng)數(shù)據(jù)庫,肯定留有多余的字段,10個不行,20個,但是這個嚴重影響了質(zhì)量。并且如果面對大數(shù)據(jù)庫,pt級別的數(shù)據(jù),這種浪費更是嚴重的,那么我們該使用是什么數(shù)據(jù)庫?hbase數(shù)個不錯的選擇,那么我們對于hbase還存在下列問題:
1.Column Family代表什么?
2.HBase通過row和column確定一份數(shù)據(jù),這份數(shù)據(jù)的值可能有多個版本,為什么會存在多個版本?
3.查詢的時候會顯示那個版本?
4.它們的存儲類型是什么?
5.tableName是什么類型?
6.RowKey 和 ColumnName是什么類型?
7.Timestamp 是什么類型?
8.value 是什么類型?
?
引言 團隊中使用HBase的項目多了起來,對于業(yè)務(wù)人員而言,通常并不需要從頭搭建、維護一套HBase的集群環(huán)境,對于其架構(gòu)細節(jié)也不一定要深刻理解(交由HBase集群維護團隊負責(zé)),迫切需要的是快速理解基本技術(shù)來解決業(yè)務(wù)問題。最近在XX項目輪崗過程中,嘗試著從業(yè)務(wù)人員視角去看HBase,將一些過程記錄下來,期望對快速了解HBase、掌握相關(guān)技術(shù)來開展工作的業(yè)務(wù)人員有點幫助。我覺得作為一個初次接觸HBase的業(yè)務(wù)開發(fā)測試人員,他需要迫切掌握的至少包含以下幾點: 深入理解HTable,掌握如何結(jié)合業(yè)務(wù)設(shè)計高性能的HTable 掌握與HBase的交互,反正是離不開數(shù)據(jù)的增刪改查,通過HBase Shell命令及Java Api都是需要的 掌握如何用MapReduce分析HBase里的數(shù)據(jù),HBase里的數(shù)據(jù)總要分析的,用MapReduce是其中一種方式 掌握如何測試HBase MapReduce,總不能光寫不管正確性吧,debug是需要的吧,看看如何在本機單測debug吧 本系列將圍繞以上幾點展開,篇幅較長,如果是HBase初學(xué)者建議邊讀邊練,對于HBase比較熟練的,可以選讀下,比如關(guān)注下HBase的MapReduce及其測試方法。 從一個示例說起 傳統(tǒng)的關(guān)系型數(shù)據(jù)庫想必大家都不陌生,我們將以一個簡單的例子來說明使用RDBMS和HBase各自的解決方式及優(yōu)缺點。 以博文為例,RDBMS的表設(shè)計如下: |
?
?為了方便理解,我們以一些數(shù)據(jù)示例下
?
?上面的例子,我們用HBase可以按以下方式設(shè)計
?
?同樣為了方便理解,我們以一些數(shù)據(jù)示例下,同時用紅色標(biāo)出了一些關(guān)鍵概念,后面會解釋
?HTable一些基本概念
Row key
行主鍵, HBase不支持條件查詢和Order by等查詢,讀取記錄只能按Row key(及其range)或全表掃描,因此Row key需要根據(jù)業(yè)務(wù)來設(shè)計以利用其存儲排序特性(Table按Row key字典序排序如1,10,100,11,2)提高性能。
Column Family(列族)
在表創(chuàng)建時聲明,每個Column Family為一個存儲單元。在上例中設(shè)計了一個HBase表blog,該表有兩個列族:article和author。
Column(列)
HBase的每個列都屬于一個列族,以列族名為前綴,如列article:title和article:content屬于article列族,author:name和author:nickname屬于author列族。
Column不用創(chuàng)建表時定義即可以動態(tài)新增,同一Column Family的Columns會群聚在一個存儲單元上,并依Column key排序,因此設(shè)計時應(yīng)將具有相同I/O特性的Column設(shè)計在一個Column Family上以提高性能。同時這里需要注意的是:這個列是可以增加和刪除的,這和我們的傳統(tǒng)數(shù)據(jù)庫很大的區(qū)別。所以他適合非結(jié)構(gòu)化數(shù)據(jù)。
Timestamp
HBase通過row和column確定一份數(shù)據(jù),這份數(shù)據(jù)的值可能有多個版本,不同版本的值按照時間倒序排序,即最新的數(shù)據(jù)排在最前面,查詢時默認返回最新版本。如上例中row key=1的author:nickname值有兩個版本,分別為1317180070811對應(yīng)的“一葉渡江”和1317180718830對應(yīng)的“yedu”(對應(yīng)到實際業(yè)務(wù)可以理解為在某時刻修改了nickname為yedu,但舊值仍然存在)。Timestamp默認為系統(tǒng)當(dāng)前時間(精確到毫秒),也可以在寫入數(shù)據(jù)時指定該值。
Value
每個值通過4個鍵唯一索引,tableName+RowKey+ColumnKey+Timestamp=>value,例如上例中{tableName=’blog’,RowKey=’1’,ColumnName=’author:nickname’,Timestamp=’ 1317180718830’}索引到的唯一值是“yedu”。
存儲類型
TableName 是字符串
RowKey 和 ColumnName 是二進制值(Java 類型 byte[])
Timestamp 是一個 64 位整數(shù)(Java 類型 long)
value 是一個字節(jié)數(shù)組(Java類型 byte[])。
存儲結(jié)構(gòu)
可以簡單的將HTable的存儲結(jié)構(gòu)理解為
?
即HTable按Row key自動排序,每個Row包含任意數(shù)量個Columns,Columns之間按Column key自動排序,每個Column包含任意數(shù)量個Values。理解該存儲結(jié)構(gòu)將有助于查詢結(jié)果的迭代。
話說什么情況需要HBase
半結(jié)構(gòu)化或非結(jié)構(gòu)化數(shù)據(jù)
對于數(shù)據(jù)結(jié)構(gòu)字段不夠確定或雜亂無章很難按一個概念去進行抽取的數(shù)據(jù)適合用HBase。以上面的例子為例,當(dāng)業(yè)務(wù)發(fā)展需要存儲author的email,phone,address信息時RDBMS需要停機維護,而HBase支持動態(tài)增加.
記錄非常稀疏
RDBMS的行有多少列是固定的,為null的列浪費了存儲空間。而如上文提到的,HBase為null的Column不會被存儲,這樣既節(jié)省了空間又提高了讀性能。
多版本數(shù)據(jù)
如上文提到的根據(jù)Row key和Column key定位到的Value可以有任意數(shù)量的版本值,因此對于需要存儲變動歷史記錄的數(shù)據(jù),用HBase就非常方便了。比如上例中的author的Address是會變動的,業(yè)務(wù)上一般只需要最新的值,但有時可能需要查詢到歷史值。
超大數(shù)據(jù)量
當(dāng)數(shù)據(jù)量越來越大,RDBMS數(shù)據(jù)庫撐不住了,就出現(xiàn)了讀寫分離策略,通過一個Master專門負責(zé)寫操作,多個Slave負責(zé)讀操作,服務(wù)器成本倍增。隨著壓力增加,Master撐不住了,這時就要分庫了,把關(guān)聯(lián)不大的數(shù)據(jù)分開部署,一些join查詢不能用了,需要借助中間層。隨著數(shù)據(jù)量的進一步增加,一個表的記錄越來越大,查詢就變得很慢,于是又得搞分表,比如按ID取模分成多個表以減少單個表的記錄數(shù)。經(jīng)歷過這些事的人都知道過程是多么的折騰。采用HBase就簡單了,只需要加機器即可,HBase會自動水平切分擴展,跟Hadoop的無縫集成保障了其數(shù)據(jù)可靠性(HDFS)和海量數(shù)據(jù)分析的高性能(MapReduce)。
?3.HBase的優(yōu)缺點
HBase的優(yōu)點:
1 列的可以動態(tài)增加,并且列為空就不存儲數(shù)據(jù),節(jié)省存儲空間.
2 Hbase自動切分數(shù)據(jù),使得數(shù)據(jù)存儲自動具有水平scalability.
3 Hbase可以提供高并發(fā)讀寫操作的支持
Hbase的缺點:
1 不能支持條件查詢,只支持按照Row key來查詢.
2 暫時不能支持Master?server的故障切換,當(dāng)Master宕機后,整個存儲系統(tǒng)就會掛掉.
4.HBase術(shù)語及原理
術(shù)語
?catalog 表
-ROOT- 表用來跟蹤?.META. 表。
META 用來保存所有 region 列表。
客戶端直接和對應(yīng)的 regionserver 聯(lián)系。不通過 master。一個 region 是否應(yīng)該被重新分配要么由 master 的負載均衡決定要么一個 regionserer 死了,客戶端重新查詢 catalog 表來看新的 region 在哪個 regionserver 上。
關(guān)于 master
用來監(jiān)視所有的 RegionServer 的行為,同時也是所有 meta 數(shù)據(jù)改變的接口。
啟動行為
在多主環(huán)境下,主會競爭。
運行時的影響
如果主掛掉,由于客戶端直接和 RegionServer 通信,因此 cluster 可能短期依然是可運行的。catalog 表不一定存在于 master 上。master 應(yīng)該盡快恢復(fù)。
接口
master 暴露的接口包括:表的創(chuàng)建,修改,刪除等等;region 的移動,分配;列族的增加修改等等。
master?有幾個后臺線程:
負載均衡線程,.META. 的清理等等。
regionserver
暴露的方法包括數(shù)據(jù)的增加,刪除,next,get 等;
region 的拆分緊湊等等。
當(dāng) HBaseAdmin 的 majorCompact 方法在一個表上被請求時,客戶端實際上是直接和每個 region 在通信。
會啟動下面幾個線程:
compact,split,memstore flush,HLog 檢查。
major 和 minor compact 區(qū)別是啥?
“minor compaction” 僅僅合并小文件為大文件,major compaction 則合并一個 region 內(nèi)的所有文件,并進行清理操作。
log 總是刷嗎?
是的,也可以不刷。
zookeeper 作用:
保存了 root 在哪里。
Zookeeper為HBase提供了穩(wěn)定服務(wù)和failover機制。
ROOT- 和.META表
HBase中有兩張?zhí)厥獾腡able,-ROOT-和.META.
META.:記錄了用戶表的Region信息,.META.可以有多個regoin
ROOT-:記錄了.META.表的Region信息,-ROOT-只有一個region
Zookeeper中記錄了-ROOT-表的location
Client訪問用戶數(shù)據(jù)之前需要首先訪問zookeeper,然后訪問-ROOT-表,接著訪問.META.表,最后才能找到用戶數(shù)據(jù)的位置去訪問,中間需要多次網(wǎng)絡(luò)操作,不過client端會做cache緩存。
Zookeeper
Zookeeper Quorum中除了存儲了-ROOT-表的地址和HMaster的地址,HRegionServer也會把自己以Ephemeral方式注冊到Zookeeper中,使得HMaster可以隨時感知到各個HRegionServer的健康狀態(tài)。此外,Zookeeper也避免了HMaster的單點問題
原理簡介
前提是大家至少了解HBase的基本需求和組件。
從大家最熟悉的客戶端發(fā)起請求開始講起吧,這樣大家能夠深有體會的逐步了解原理。比如我們發(fā)起了一條PUT請求,客戶端首先需要查找到需要響應(yīng)請求的REGIONSERVER。 記錄region->regionserver映射是由HBASE系統(tǒng)表.META.記錄的。所以我們只要知道. META.表的位置就能知道每個region響應(yīng)的key的范圍 和region所在機器。但是.META.表又保存在哪些機器上呢?這又是由-ROOT-表記錄的 master在分配完-ROOT-表后 會將-ROOT-表的位置放到ZOOKEEPER中。所以我們在配置客戶端的時候配置的是ZOOKEEPER的位置,而不是MASTER位置。
為什么要分為-ROOT-和.META.呢?這是因為region信息本身很多 一個集群中可能會出現(xiàn)成千上萬的region 因此.META.表本身也無法在一個region中保存所有用戶region的信息,所以本身也會分裂。而.META.表的region數(shù)就比較有限了所以-ROOT-是不會分裂的.
綜上,客戶端首次請求時,先拿-ROOT-然后通過請求范圍找對應(yīng)的.META.,在.META.中找打具體的region server 然后發(fā)送請求。-ROOT-和.META.是可以緩存的。
現(xiàn)在,我們解決了 客戶端應(yīng)當(dāng)把PUT發(fā)送到哪個rs的問題,接下來就要發(fā)送請求了。region server收到請求后會保存PUT數(shù)據(jù)。這就不得不說HBASE的數(shù)據(jù)模型了,HBASE使用的列式存儲,基本數(shù)據(jù)結(jié)構(gòu)為LSMT log structure merge tree。簡略的思路描述是,將操作記錄在樹中的節(jié)點上然后適時的將節(jié)點合并從而使key的刪除修改能夠最終體現(xiàn)在一個節(jié)點上,讀取的時候會讀取帶有key相應(yīng)操作的節(jié)點,返回最終key的值。可以看到lsmt是將隨機讀寫轉(zhuǎn)化為順序讀寫的數(shù)據(jù)結(jié)構(gòu),讀方面更適合掃庫那樣的順序讀取,不太適合隨機讀取。
那么一個PUT請求時怎么和LSMT搭上關(guān)系的呢?首先region server接到請求時,先將操作(keyvalue 時間戳 操作類型)保存為HLog,然后在保存到memstore中,然后即可返回寫入成功的請求。其中memstore保存在內(nèi)存中,寫滿后flush為hdfs文件。hlog是為了防止rs故障時,memstore數(shù)據(jù)必然丟失導(dǎo)致的數(shù)據(jù)丟失,在客戶端可以禁用hblog來加快寫入速度,但這是用數(shù)據(jù)不安全換來的。只要每次memstore刷入hdfs后,會判斷hdfs刷入的中最早的操作 然后由另外的線程根據(jù)此記錄刪除舊的HLog文件。
接下來說說memstore寫滿時的處理。memstore寫滿(每個region的列族都有單獨的memstore對象但實際上共用一塊內(nèi)存池)時,會將其中的操作分發(fā)到對應(yīng)region的每個列族(store)做處理。然后store將這些操作序列保存為存儲文件(storefile)。
從大體上粗略的看 region server這邊重要的實體結(jié)構(gòu)是這樣:regionserver : region = 1 : n;region : store= 1 : n;store : storefile = 1 : n。對于每個列族的數(shù)據(jù)文件,實機上是一個LSMT的葉子節(jié)點,每個文件中保存的是最近的對于列族中key的操作。
當(dāng)一個列族中文件過多的時候,會觸發(fā)compact,也就是說的文件合并。HBase的compact分為兩種 minor和major:minor是小范圍內(nèi)的合并文件,只合并部分。目的在于把小文件積累成大文件。因為沒有全量數(shù)據(jù),所以對于一個key的刪除操作還是需要保留標(biāo)記,無法物理刪除。majorcompact把列族中的所有文件合并為一個,目的在于使key的修改和刪除,最終在物理上生效。因為major compact操作的是此列族的全量數(shù)據(jù),所以可以做物理刪除。但是也由于是全量數(shù)據(jù),執(zhí)行起來耗費時間也會比價長,所以hbase對major compact做了時間間隔限制。
當(dāng)store的store file集合中總文件長度太大時(超過配置的閾值),這個region會一分為二,也就是split。由于split是以region為單位的,所以有些列族因為其他列族過大也被連坐般的split。所以從這個流程粗略的看來 put會觸發(fā)flush,flush會觸發(fā)compact,compact會觸發(fā)split。當(dāng)然這都是在多個線程中執(zhí)行的,不會明顯的阻塞住客戶端請求。
store file的大小和memstore大小有關(guān)系,一次flush會在一個列族里生成一個store file。所以memstore越大,產(chǎn)生大store file的機會也就越多。put不均勻時,有的列族里會有比較多的長度較小的store file,但是文件多了會觸發(fā)compact。小文件compact很快,所以不用擔(dān)心。
store file?
------------------------------------------------
|block? ?? ?? ?? ?? ?? ?? ?? ? |
|----------------------------------------------|
|block? ?? ?? ?? ?? ?? ?? ?? ? |
...
|??meta? ?? ?? ?? ?? ?? ?? ? |
|---------------------------------------------|
|block索引,以及一些key范圍信息|
|---------------------------------------------|
|布隆過濾? ?? ?? ?? ?? ?? ? |
-----------------------------------------------
可以粗略的認為 一個storefile的結(jié)構(gòu)是這樣的,尾部的順序和細節(jié)記不太清楚了。一個block包括多個key value,key在文件內(nèi)是有序的。一條key value記錄如下圖:
?
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?
讀數(shù)據(jù)的時候我會發(fā)送一個get請求,在region server內(nèi)部會轉(zhuǎn)為一個scan。他會到相關(guān)列族中去scan storefile。storefile的尾部包含block索引、布隆過濾器、更新時間等所以這可以加快需要scan的文件過濾。所以針對一個store file讀是這樣的:判斷get請求中的row key是否在文件保存的數(shù)據(jù)范圍內(nèi);判斷get請求中的row key是否能從布龍過濾器中找到(如果過濾器為row-col過濾器還可以判斷是否包括需要get的col);判斷get請求中的時間范圍 是否在文件保存的數(shù)據(jù)的時間范圍中;獲取對應(yīng)的block index;把block加載到block cache中;然后scan block;從多個store file的結(jié)果中 get請求中需要包含的version個數(shù),取前幾個從而滿足get請求中需要包含的version個數(shù)。get可以看做特殊的scan操作。
總得blockcache大小是有限的,會有淘汰的.實際上blockcache對于scan來說更合適,因為scan一般是一個范圍的掃,block中的row key又是有序的,所以說順序讀會比隨機讀快。一般hbase比較難適應(yīng)高并發(fā)的隨機讀,因為blockcache這個設(shè)計的本身,就不適合緩存隨機的row key:隨機讀的特點就是讀的key均勻散列,這樣會使讀操作,落在每個block上,導(dǎo)致讀的時候每個block先被加載到內(nèi)存,然后很快因為其他的block持續(xù)加載進來而被淘汰出去,然后就這樣換來換去,反而更浪費時間。
最后兩個比較重要的操作是open和close region。這兩個在容災(zāi)和均衡中常用。
先說close吧 正常close時會先flush memstore 然后通知master close結(jié)束。非正常關(guān)閉時,就來不及flush了。master會通過zk和region server之間的心跳這兩種途徑得知regionsever掛掉的情況。
open 一般由master發(fā)起。master先找到包含region操作對應(yīng)的HLog文件,然后挑選出region對應(yīng)的操作放到region目錄中,然后命令某個region server open之。open時先重演HLog中記錄的操作,然后再加載region對應(yīng)的store和store file。
比較重要的原理就是這樣的了。原理清楚了的話,再分析起來代碼,就能有一個宏觀的了解了。
?
?
?
?
?
?
?
轉(zhuǎn)載于:https://my.oschina.net/MrMichael/blog/315595
總結(jié)
- 上一篇: webform开发经验(一):Asp.N
- 下一篇: laravel实现数据库读写分离配置或者