HBase的數(shù)據(jù)結(jié)構(gòu)原理與使用

2023-06-11 22:14:00 來源:博客園

一、HBase簡介

HBase是一個(gè)開源的、分布式的、版本化的NoSQL數(shù)據(jù)庫(即非關(guān)系型數(shù)據(jù)庫),依托Hadoop分布式文件系統(tǒng)HDFS提供分布式數(shù)據(jù)存儲(chǔ),利用MapReduce來處理海量數(shù)據(jù),用Zookeeper作為其分布式協(xié)同服務(wù),一般用于存儲(chǔ)海量數(shù)據(jù)。HDFS和HBase的區(qū)別在于,HDFS是文件系統(tǒng),而HBase是數(shù)據(jù)庫。HBase只是一個(gè)NoSQL數(shù)據(jù)庫,把數(shù)據(jù)存在HDFS上。可以把HBase當(dāng)做是MySQL,把HDFS當(dāng)做是硬盤。


(資料圖片僅供參考)

二、HBase的數(shù)據(jù)結(jié)構(gòu)

1、索引結(jié)構(gòu):LSM樹

傳統(tǒng)關(guān)系型數(shù)據(jù)普通索引采用B+樹。B+樹最大的性能問題是會(huì)產(chǎn)生大量的隨機(jī)IO,隨著新數(shù)據(jù)的插入,葉子節(jié)點(diǎn)會(huì)慢慢分裂,邏輯上連續(xù)的葉子節(jié)點(diǎn)在磁盤存儲(chǔ)上往往不連續(xù),分離得很遠(yuǎn),隨機(jī)讀寫概率會(huì)變大,做范圍查詢時(shí),會(huì)產(chǎn)生大量讀隨機(jī)IO。為了克服B+樹的弱點(diǎn),HBase引入了LSM樹的概念,即Log-Structured Merge-Trees,直譯為日志結(jié)構(gòu)合并樹。基于LSM樹實(shí)現(xiàn)的HBase的寫性能相比Mysql放棄部分磁盤讀性能,換取寫性能的大幅提升。

LSM樹嚴(yán)格來說不是一個(gè)具體的數(shù)據(jù)結(jié)構(gòu),更多是一種數(shù)據(jù)結(jié)構(gòu)的設(shè)計(jì)思想。LSM樹不是一棵樹,而是由至少兩個(gè)存儲(chǔ)結(jié)構(gòu)構(gòu)成。假設(shè)這兩顆樹分別為C0和C1,C0比較小,全部駐于內(nèi)存之中,具體可以是任何方便健值查找的數(shù)據(jù)結(jié)構(gòu)。而C1則駐于機(jī)械硬盤。一條新的記錄先是從C0中插入,如果這一次的插入造成了C0數(shù)據(jù)量超出了閥值,那么C0中的部分些數(shù)據(jù)片段則會(huì)直接合并到C1樹中。如果有多級樹,當(dāng)C1體量越來越大就向C2合并,低級的樹在達(dá)到大小閾值后也會(huì)在磁盤中進(jìn)行合并,以此類推,一直往上合并Ck。

LSM樹的設(shè)計(jì)思想:

劃分不同等級的樹。將對數(shù)據(jù)的修改增量保持在內(nèi)存中,數(shù)據(jù)更新只在內(nèi)存中操作,沒有磁盤訪問。達(dá)到指定的大小限制后將這些修改操作批量寫入磁盤。由于內(nèi)存的讀寫速率都比磁盤要快非常多,因此數(shù)據(jù)寫入內(nèi)存的效率很高。隨著小樹越來越大,達(dá)到指定的閥值限制后將這些修改操作批量寫入磁盤,磁盤中的樹定期做多路歸并操作,合并成一棵大樹,以優(yōu)化讀性能。隨機(jī)讀寫比順序讀寫慢很多,為了提升IO性能,需要將隨機(jī)操作變?yōu)轫樞虿僮鳌SM樹使用日志文件和一個(gè)內(nèi)存存儲(chǔ)結(jié)構(gòu)把隨機(jī)寫轉(zhuǎn)化成順序?qū)懀x寫?yīng)毩ⅲ瑪?shù)據(jù)從內(nèi)存刷入磁盤時(shí)是預(yù)排序的,寫性能大幅提升。讀取的時(shí)候稍微麻煩,需要先看是否命中內(nèi)存,如果讀取的是最近訪問過的數(shù)據(jù)則可以命中,否則需要訪問較多的磁盤文件。

使用LSM樹的數(shù)據(jù)庫除了HBase,還有nessDB、levelDB、TiDB、RocksDB等。

(圖中MongoDB只有WiredTiger(WT)存儲(chǔ)引擎既支持B-樹,又支持LSM樹存儲(chǔ)索引。)

2、存儲(chǔ)結(jié)構(gòu)

HBase的LSM樹中存儲(chǔ)的是多個(gè)Key-Value結(jié)構(gòu)組成的集合,每一個(gè)Key-Value一般都會(huì)用一個(gè)字節(jié)數(shù)組來表示。這個(gè)字節(jié)數(shù)組串設(shè)計(jì)如圖所示:

(圖源:胡爭,范欣欣《HBase原理與實(shí)踐》第二章《基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)與算法》)

字節(jié)數(shù)組主要分為以下幾個(gè)字段。其中Rowkey、Family、Qualifier、Timestamp、Type這5個(gè)字段組成KeyValue中的key部分。

? keyLen:用來存儲(chǔ)KeyValue結(jié)構(gòu)中Key所占用的字節(jié)長度。

? valueLen:用來存儲(chǔ)KeyValue結(jié)構(gòu)中Value所占用的字節(jié)長度。

? rowkeyLen:用來存儲(chǔ)rowkey占用的字節(jié)長度。

? rowkeyBytes:用來存儲(chǔ)rowkey的二進(jìn)制內(nèi)容。

? familyLen:用來存儲(chǔ)Family占用的字節(jié)長度。

? familyBytes:用來存儲(chǔ)Family的二進(jìn)制內(nèi)容。

? qualif ierBytes:用來存儲(chǔ)Qualif ier的二進(jìn)制內(nèi)。注意,HBase并沒有單獨(dú)分配字節(jié)用來存儲(chǔ)qualif ierLen,因?yàn)榭梢酝ㄟ^keyLen和其他字段的長度計(jì)算出qualif ierLen。

? timestamp:表示timestamp對應(yīng)的long值。

? type:表示這個(gè)KeyValue操作的類型,HBase內(nèi)有Put、Delete、Delete Column、DeleteFamily,等等。

HBase的LSM樹在內(nèi)存一般采用跳躍表存儲(chǔ),跳躍表的查找、刪除、插入的復(fù)雜度都是O(logN)。

LSM樹在磁盤中的數(shù)據(jù)結(jié)構(gòu)也不是樹結(jié)構(gòu),而是Key-Value結(jié)構(gòu)組成的序列,稱為SSTable(Sorted String Table)有序字符串表。當(dāng)SSTable太大時(shí),為了加快SSTable的讀取,可以將其劃分為多個(gè)塊,通過記錄每個(gè)塊的起始位置,構(gòu)建每個(gè)SSTable的稀疏索引。這樣在讀SSTable前,通過索引就知道要讀取的數(shù)據(jù)塊磁盤位置了。SSTable索引需要永遠(yuǎn)加載在內(nèi)存里。寫是寫內(nèi)存,因此隨機(jī)寫十分快。讀也是讀內(nèi)存里的 SSTable的索引,并且這里每一個(gè)SSTable索引如果用二分法查找,算法復(fù)雜度大致在O(lg(n))與O(n)之間,因此隨機(jī)讀也不慢。

3、表結(jié)構(gòu)與傳統(tǒng)的關(guān)系型數(shù)據(jù)庫類似,HBase也以表的形式組織數(shù)據(jù),表也由行和列組成,不同的是,HBase采用列式存儲(chǔ)。

如上圖所示的表,如果采用列式存儲(chǔ),會(huì)存成下圖的結(jié)構(gòu):

可以發(fā)現(xiàn),列式存儲(chǔ)就是把每列抽出來,然后關(guān)聯(lián)上ID,實(shí)際上是用Key-Value結(jié)構(gòu)保存的。這樣的優(yōu)點(diǎn)在于,當(dāng)表格中有空缺時(shí),可以充分利用存儲(chǔ)空間。

對HBase來說,一行數(shù)據(jù)由一個(gè)行鍵(RowKey)和一個(gè)或多個(gè)相關(guān)的列以及它的值所組成。列的組成都是靈活的,行與行之間的列不需要相同。行鍵(RowKey)就是SSTable的key。

在HBase里邊,先有列族(也叫“列簇”,Column Family),后有列。列族將一列或者多列組織在一起,HBase的每一個(gè)列都必須屬于某個(gè)列族。HBase的列都得歸屬到列族中,如圖所示:

數(shù)據(jù)寫到HBase的時(shí)候都會(huì)被記錄一個(gè)時(shí)間戳,這個(gè)時(shí)間戳被我們當(dāng)做一個(gè)版本。比如說,我們修改或者刪除某一條的時(shí)候,本質(zhì)上是往里邊新增一條數(shù)據(jù),記錄的版本加一了而已。如圖所示:

被更新和刪除的數(shù)據(jù)不會(huì)直接從磁盤上刪除,而是為數(shù)據(jù)添加一個(gè)刪除標(biāo)記,查找時(shí)會(huì)跳過被刪除的鍵,DBA運(yùn)維會(huì)定期刪除被標(biāo)記刪除的數(shù)據(jù)。因此,如果存在頻繁覆蓋刪除需要提前向運(yùn)維報(bào)備以免影響數(shù)據(jù)庫性能。

三、HBase的使用

1、HBase的讀寫

HBase提供了多種模式、多種語言的訪問接口。目前常用的包括Native Java API,Thrift和MapReduce模式。

(1)Java API是HBase提供的原生接口,具備完善的客戶端處理邏輯,直接與HBase Server進(jìn)行通信,效率最高,但受限于語言限制;

(2)Thrift不受語言限制,但會(huì)占用額外的網(wǎng)絡(luò)帶寬和處理時(shí)間;

(3)HBase還支持了MapReduce,可以通過編寫MapReduce任務(wù)進(jìn)行批量數(shù)據(jù)操作。

使用GoLang和PHP語言搭建的項(xiàng)目顯然得用Thrift接口。

常用的HBase的數(shù)據(jù)操作get、scan和put三種。

(1)get實(shí)現(xiàn)隨機(jī)讀取功能,根據(jù)指定RowKey獲取惟一一條記錄。

(2)scan提供批量查詢功能,按照指定的條件獲取一批記錄。通過指定起始和中止的key,即可獲取所有包含在內(nèi)的key對應(yīng)的數(shù)據(jù)。可以通過setStartRow與setEndRow來限定范圍,也可以通過setFilter方法添加過濾器,這也是分頁、多條件查詢的基礎(chǔ),用setCaching和setBatch方法能提高速度。

(3)put實(shí)現(xiàn)寫入,如果要批量導(dǎo)入大規(guī)模數(shù)據(jù),還可以采用bulkimport的方式。

2、行鍵(RowKey)設(shè)計(jì)

Rowkey相當(dāng)于HBase中數(shù)據(jù)的主鍵。HBase中的數(shù)據(jù)是按照RowKey的ASCII字典順序進(jìn)行全局排序。可以使相關(guān)行彼此靠近存儲(chǔ)。如果Rowkey設(shè)計(jì)不當(dāng)會(huì)引發(fā)熱點(diǎn)問題,即客戶端大量的讀寫請求都集中在一個(gè)或幾個(gè)節(jié)點(diǎn)上。從而導(dǎo)致性能下降。為防止數(shù)據(jù)寫入時(shí)出現(xiàn)熱點(diǎn),數(shù)據(jù)被寫入時(shí)應(yīng)寫入集群中的多個(gè)區(qū)域,而不是一次寫入一個(gè)區(qū)域(Hregion)。

設(shè)計(jì)原則:

1、唯一原則,要保證Rowkey的唯一性。若HBase中同一表插入相同Rowkey,則原先的數(shù)據(jù)會(huì)被覆蓋掉。設(shè)計(jì)Rowkey的時(shí)候,要充分利用這個(gè)排序的特點(diǎn),將經(jīng)常讀取的數(shù)據(jù)存儲(chǔ)到一塊,將最近可能會(huì)被訪問的數(shù)據(jù)放到一塊。

2、長度原則。Rowkey長度越短越好,一般不要超過16字節(jié)。因?yàn)镽owKey是一個(gè)二進(jìn)制碼流,可以是任意字符串,最大長度64KB,實(shí)際應(yīng)用中一般為10-100字節(jié),以byte[]形式保存。如果RowKey過長比如500個(gè)字節(jié),1000萬列數(shù)據(jù)僅RowKey就要占用5GB空間,非常影響HFile的存儲(chǔ)效率。

3、散列原則。用時(shí)間戳作為Rowkey的前綴會(huì)導(dǎo)致大量數(shù)據(jù)堆積在一個(gè)區(qū)域進(jìn)而導(dǎo)致熱點(diǎn)問題。如果Rowkey是按時(shí)間戳的方式遞增,不要將時(shí)間放在二進(jìn)制碼的前面,建議將Rowkey的高位作為散列字段,低位放時(shí)間字段。

3、列族(Column Family)的設(shè)計(jì)

設(shè)計(jì)原則:

1、列族的名稱盡可能短,甚至可以是一個(gè)字符。例如,“d”表示數(shù)據(jù)/默認(rèn)值。

2、HBase當(dāng)前不能很好地處理超過兩個(gè)或三個(gè)列族的數(shù)據(jù),因此請保持列族的數(shù)量較少。最好使用一個(gè)列族。僅在數(shù)據(jù)訪問通常是列范圍的情況下才引入第二和第三列族。即,一次只查詢一個(gè)列族,通常不會(huì)查詢兩個(gè)列族。

3、將相同IO特性的列放入同一列族。

4、多個(gè)列族中的數(shù)據(jù)(行數(shù))分布大致均勻。

5、對于臨時(shí)性的列族可以設(shè)置失效時(shí)間。一旦達(dá)到到期時(shí)間,HBase將自動(dòng)刪除行。

4、HBase Shell的安裝和使用

HBase自帶的操作工具只有HBase Shell這一命令行終端。通過HBase Shell工具,可以交互式地進(jìn)行數(shù)據(jù)管理,包括插入數(shù)據(jù)、刪除數(shù)據(jù)等。雖然也有一些第三方圖形界面客戶端支持HBase,如DBeaver、BigInsights、HbaseGUI,但系統(tǒng)部的HBase只支持HBase Shell。

安裝HBase Shell需要先挑選一臺用于安裝的虛擬機(jī),為該虛擬機(jī)安裝Java環(huán)境。之后在系統(tǒng)部奇麟大數(shù)據(jù)的客戶端管理頁面選擇“添加客戶端賬號”,申請為該虛擬機(jī)添加項(xiàng)目賬號。申請通過后勾選機(jī)器,單擊“部署Hadoop環(huán)境”在該機(jī)器上安裝HBase Shell。

安裝成功后,到虛擬機(jī)上使用sudo -iu命令先切換到項(xiàng)目賬號。然后切換到目錄cd $HBASE_HOME/bin,運(yùn)行hbase shell,即可進(jìn)入HBase Shell程序。

這里列出幾個(gè)常用的HBase Shell命令:

名稱命令表達(dá)式
查看存在哪些表list
添加數(shù)據(jù)put "表名稱", "行鍵", "列族 : 列名", "值"
查看一行數(shù)據(jù)get "表名稱", "行鍵"
查看指定列族的一行數(shù)據(jù)get "表名稱", "行鍵", "列族"
查看指定列族及列名的數(shù)據(jù)get "表名稱", "行鍵", "列族 : 列名",
查看表中的數(shù)據(jù)總量count "表名"
刪除一個(gè)單元格的數(shù)據(jù)delete "表名" ,"行鍵" , "列族 : 列名"
刪除一行所有數(shù)據(jù)delete "表名" ,"行鍵"
查看表的所有數(shù)據(jù)scan "表名"。注意,一般不應(yīng)直接使用scan掃描整個(gè)表的海量數(shù)據(jù)。
查看一列數(shù)據(jù)scan "表名" , "列族 : 列名"
查看幫助信息help

5、MongoDB數(shù)據(jù)遷移HBase

使用kettle等工具可以把MongoDB數(shù)據(jù)庫遷移到HBase。也可以使用MapReduce處理,速度遠(yuǎn)快于Java API和Thrift。

參考文獻(xiàn):

胡爭,范欣欣.HBase原理與實(shí)踐M.北京:機(jī)械工業(yè)出版社,2019

O’Neil, P., Cheng, E., Gawlick, D., & O’Neil, E. (1996). The log-structured merge-tree (LSM-tree). Acta Informatica, 33(4), 351-385.

標(biāo)簽:

上一篇:今日鞋怎么洗白_鞋怎么組詞
下一篇:最后一頁
產(chǎn)品
更多
概念
平臺
應(yīng)用