Hbase生產(chǎn)實踐

???????????????????????????????????? Hbase生產(chǎn)實踐

背景

HBase是一個分布式的、面向列的開源數(shù)據(jù)庫,它是hadoop生態(tài)圈的一員,有海量數(shù)據(jù)存儲能力,對資源的消耗也相對較小,但同時查詢能力也有局限,因此如何正確的使用hbase非常關鍵。

關于hbase

一個表可以有上億行,上百萬列

面向列(族)的存儲和權限控制,列(族)獨立檢索。

對于為空(null)的列,并不占用存儲空間,因此,表可以設計的非常稀疏。

選擇完成時,被選擇的列要重新組裝

INSERT/UPDATE比較麻煩

Hbase基本概念

Region是HBase中分布式存儲和負載均衡的最小單元。不同Region分布到不同RegionServer上,但并不是存儲的最小單元。

Region由一個或者多個Store組成,每個store保存一個columns

family,每個Strore又由一個memStore和0至多個StoreFile 組成。memStore存儲在內存中, StoreFile存儲在HDFS上。

HBase通過將region切分在許多機器上實現(xiàn)分布式。也就是說,你如果有16GB的數(shù)據(jù),只分了2個region, 你卻有20臺機器,有18臺就浪費了。

數(shù)目太多就會造成性能下降,現(xiàn)在比以前好多了。但是對于同樣大小的數(shù)據(jù),300個region比1000個要好。

數(shù)目太少就會妨礙可擴展性,降低并行能力。有的時候導致壓力不夠分散。這就是為什么,你向一個10節(jié)點的HBase集群導入200MB的數(shù)據(jù),大部分的節(jié)點是idle的。

RegionServer中1個region和10個region索引需要的內存量沒有太多的差別。

關于family和column

它是column的集合,在創(chuàng)建表的時候就指定,不能頻繁修改。值得注意的是,列族的數(shù)量越少越好,因為過多的列族相互之間會影響,生產(chǎn)環(huán)境中的列族一般是一個到兩個。

和列族的限制數(shù)量不同,列族可以包含很多個列,前面說的“幾十億行*百萬列”就是這個意思。

存在單元格(cell)中。每一列的值允許有多個版本,由timestamp來區(qū)分不同版本。多個版本產(chǎn)生原因:向同一行下面的同一個列多次插入數(shù)據(jù),每插入一次就有一個對應版本的value。

結合車聯(lián)網(wǎng)業(yè)務,family的設計一般按照不同的業(yè)務數(shù)據(jù)和獲取頻次進行設計,總的family個數(shù)不超過3個為最好,同時將經(jīng)常讀取的數(shù)據(jù)歸類到一個family。

關于rowkey

rowkey是hbase的唯一id,也是hbase查詢的主要途徑,既然HBase是采用KeyValue的列存儲,那Rowkey就是KeyValue的Key了,表示唯一一行。Rowkey也是一段二進制碼流,最大長度為64KB,內容可以由使用的用戶自定義。數(shù)據(jù)加載時,一般也是根據(jù)Rowkey的二進制序由小到大進行的。

HBase是根據(jù)Rowkey來進行檢索的,系統(tǒng)通過找到某個Rowkey (或者某個 Rowkey 范圍)所在的Region,然后將查詢數(shù)據(jù)的請求路由到該Region獲取數(shù)據(jù)。HBase的檢索支持3種方式:

(1) 通過單個Rowkey訪問,即按照某個Rowkey鍵值進行get操作,這樣獲取唯一一條記錄;

(2) 通過Rowkey的range進行scan,即通過設置startRowKey和endRowKey,在這個范圍內進行掃描。這樣可以按指定的條件獲取一批記錄;

(3) 全表掃描,即直接掃描整張表中所有行記錄。

HBASE按單個Rowkey檢索的效率是很高的,耗時在1毫秒以下,每秒鐘可獲取1000~2000條記錄,不過非key列的查詢很慢。

那么rowkey該如何設計?

Hbase是按ASCII碼排序的,其排序規(guī)則類似于字典序,例如一個AAA_BBB_CCC的rowkey可以支持以AAA,AAA_BBB,AAA_BBB_CCC的范圍進行查詢,但是不能以AAA__CCC或者_*_CCC這樣的順序進行查詢(*代表缺失)。

結合我們的場景,如果要查詢一個用戶一段時間內的數(shù)據(jù),其rowkey應該這樣設計,即USER_(Long.Max-TIME)_EVENT,某個USER的數(shù)據(jù)會按時間倒序插入hbase,最新的數(shù)據(jù)會排在最前面,能很容易的找到最新的數(shù)據(jù),rowkey上的EVENT是為了避免同一時間會有不同的事件上報被覆蓋,但EVENT不能用于rowkey查詢,因為TIME是在不斷變化的。

這種rowkey的設計其查詢方式可以有:

(1)? 查詢USER的所有數(shù)據(jù),即rowkey范圍為{USER_,USER`}

(2)? 查詢USER一段時間內的數(shù)據(jù),即rowkey范圍為{USER_( Long.Max-ENDTIME), USER_( Long.Max-STARTRIME)

(3)? 查詢USER一段時間內的符合條件的數(shù)據(jù),rowkey按照(2)的方式生成,結合filter

region預分區(qū)和寫熱點

上面提到rowkey設計,我們把USER放在rowkey的首位,假設采用hbase默認的策略,即建表初始化一個region,默認達到10G進行拆分,在region分裂之后,不同的USER就會分別寫到不同的region里面去,達到并行寫的目的。但是如果采用(Long.Max-TIME)_USER_EVENT的rowkey方式,region拆分后,后續(xù)的數(shù)據(jù)由于時間越來越來,(Long.Max-TIME)越來越小,數(shù)據(jù)就只會寫到范圍小的region里面,出現(xiàn)寫熱點問題,所以必須合理的設計rowkey以達到提高寫性能。

Hbase默認是一個表一個region,在region未拆分之前,所有的數(shù)據(jù)都會往一個region里面寫,即使第一次拆分之后也還是只有2個region,這樣會導致region分布不均,有些節(jié)點沒有工作,浪費資源。這時候我們需要考慮region預分區(qū),即一開始就創(chuàng)建足夠的region,每個region劃分一個rowkey范圍。一般我們會按照10進制00000000-FFFFFFFF劃分16個region,如果服務器較少,可以自己制定預分區(qū)策略。

Hbase1.x之后,默認的region拆分策略是按照region大小拆分的,早期版本是按照128*(2的n次方)進行拆分的,region拆分的太多不利于regionserver管理,拆的太少不利于數(shù)據(jù)寫入,具體要根據(jù)業(yè)務量來制定。

關于filter

顧名思義,filter就是過濾器,filter的作用域是單個region,也就是說filter會在每個region上面獨立生效,當一個用戶的數(shù)據(jù)跨了幾個region之后,而查詢的范圍又包含這幾個region,如果使用pagefilter分頁,就會返回region個數(shù)*分頁條數(shù)的數(shù)據(jù)量。

Filter可以減少io開銷,返回我們所需要的數(shù)據(jù),但是如果和scan結合使用需要指定rowkey范圍,scan是掃描表,沒有rowkey范圍就會掃描所有的region,性能非常差。

關于二級索引

由于hbase的rowkey有一定的局限,當查詢條件不在rowkey上,或者不是按照rowkey的組裝順序時,無法通過rowkey來快速找到對應的region和Strore。這時候需要考慮二級索引,二級索引的方式有多種,以下介紹2種方式:

(1)? 通過多張hbase表,一張表存數(shù)據(jù),另一張表建立索引和數(shù)據(jù)表進行關聯(lián),寫數(shù)據(jù)的時候同時寫兩張表。

(2)? 通過協(xié)處理器在put之前建立二級索引,同時寫索引表。

(3)? 結合elasticsearch,hbase存原始數(shù)據(jù),elasticsearch建立索引。

關于protobuf

? 在實際業(yè)務中,數(shù)據(jù)通常會比較復雜,一個用戶或者設備會有各種嵌套的屬性,數(shù)據(jù)在寫入hbase的時候可以以json的方式,也可以以protobuf的方式,這里建議以protobuf的方式,protobuf在序列化和反序列化性能方面比json效率高,同時占用空間也比json要少。

應用實踐規(guī)范和注意事項

設計合理的表名,表名不要太長,自注釋的表名最好。

創(chuàng)建表時指定壓縮方式,建議采用LZO,snappy壓縮。

合理安排family,個數(shù)不要超過3個,訪問頻繁和訪問關聯(lián)的數(shù)據(jù)放在相同的family中。

合理的設計rowkey,避免以自增長的數(shù)據(jù)作為rowkey開頭,如果需要,可以hash之后再保存,但hash之后rowkey的順序(比如時間序)已經(jīng)無法保證了。

盡量簡化封裝,避免使用反射等操作,采用原生api最佳。

數(shù)據(jù)結構為一對多場景,即一個user對應多個屬性,采用protobuf進行編碼,將多個信號序列化為一個字段。

Hbase連接采用長連接方式。

由于數(shù)據(jù)上報頻次高,數(shù)據(jù)量大,采用批量異步保存方式進行保存。利用kafka的特性,一次性拉取一定條數(shù)的數(shù)據(jù),將這一批數(shù)據(jù)提交到線程池,批量保存到hbase。

注意不同的hbase版本,zookpeer中的hbase的根節(jié)點不同(原生的hbase節(jié)點為/hbase,hdp中為/hbase_unsecure)。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容