HBase使用總結(jié)

原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明原作地址:http://www.itdecent.cn/p/0f9578df7fbc

一. 架構(gòu)


1. 數(shù)據(jù)模型

1.1 基礎(chǔ)概念
  • 表(table):列式存儲(chǔ),支持高表&寬表(上億行,上百萬列)
  • 行(row):每一行由唯一的行鍵確定
  • 列族(columnFamily):每一行包含一個(gè)或多個(gè)列族,是列的集合
  • 列(column):列式存儲(chǔ),列是最基本單位,可能有多個(gè)版本的值
  • 時(shí)間戳(Timestamp):列的不同版本之間用時(shí)間戳區(qū)分
  • 單元格(cell):列的每一個(gè)版本是一個(gè)單元格,是存儲(chǔ)的基本單位

HBase最基本的單位是列(column),一列或者多列形成一行(row),若干行數(shù)據(jù)組成了一張表(table)。聽起來是一個(gè)非常普通的列式存儲(chǔ)數(shù)據(jù)庫,但是,它和傳統(tǒng)數(shù)據(jù)庫有很大的不同。

1.2 與傳統(tǒng)數(shù)據(jù)庫的區(qū)別
a. HBase的每一行由唯一的行鍵確定

在某種程度上,行鍵相當(dāng)于傳統(tǒng)數(shù)據(jù)庫的primary key,區(qū)別在于,primary key是可選的,而HBase的每張表都必然會(huì)有行鍵。除了行鍵之外,HBase表不能對(duì)列添加索引。HBase是一個(gè)<key, value>形式的數(shù)據(jù)庫,行鍵就是它的key。

b. HBase引入了列族(columnFamily)的概念
  • HBase是一個(gè)列式存儲(chǔ)的數(shù)據(jù)庫,因此列的使用是非常靈活的,不必在表定義的時(shí)候就定好列名,但是必須在建表的時(shí)候定義好列族名字。
  • 一張HBase表存儲(chǔ)的列的數(shù)量可以是無限的,但是列族的數(shù)量最好控制在2-3個(gè)(原因在備注中[1]
  • 列必須屬于某個(gè)列族,不同列族之間可以有同名列
  • 列族的作用是,將那些數(shù)據(jù)量和屬性相似的列聚集在一起,以便我們給這些列定義一些共同的存儲(chǔ)方式屬性(e.g. 數(shù)據(jù)壓縮,保存到讀緩存中)
c. HBase的列值可以有多版本

在HBase表中,行鍵、列族、列名和時(shí)間戳才能唯一確定一個(gè)值。每個(gè)值是一個(gè)單元格(cell),是存儲(chǔ)的基本單位。每一行數(shù)據(jù)的每一列,都可以存儲(chǔ)多個(gè)值,每個(gè)版本的值之間通過時(shí)間戳確定,在存儲(chǔ)的時(shí)候,這些值也按照時(shí)間戳逆序排列,保證客戶端永遠(yuǎn)讀到最新的數(shù)據(jù)。但是,每個(gè)列族可以存儲(chǔ)的最大版本數(shù)是確定的,并且是在建表的時(shí)候就定義好的。

另外,單元格的時(shí)間戳是可以由用戶自行指定的,如果不指定,服務(wù)器就會(huì)將接收到寫請(qǐng)求的服務(wù)器時(shí)間作為單元格的時(shí)間戳。通常情況下,最好不要自己指定時(shí)間戳,因?yàn)榭蛻舳丝偸请y以保證,指定的時(shí)間戳是按照寫順序遞增的。

d. 反范式化

HBase是一個(gè)NoSQL(Not-only-SQL)數(shù)據(jù)庫,不提供復(fù)雜的查詢方式,包括join。另外,相對(duì)于MySQL,HBase的可擴(kuò)展性很好,存儲(chǔ)資源要廉價(jià)很多。因此,在設(shè)計(jì)數(shù)據(jù)庫的時(shí)候,我們總是傾向于反范式化,以方便后期的數(shù)據(jù)查詢

1.3 數(shù)據(jù)模型抽象

HBase實(shí)際上是按照谷歌的bigtable實(shí)現(xiàn)的,而谷歌在bigtable論文的開篇就介紹了bigtable的特點(diǎn):A Bigtable is a sparse, distributed, persistent multidimensional sorted map。所以HBase在本質(zhì)上,是一張有序的多維map,數(shù)據(jù)模型可以抽象成:

<rowKey : columnFamily : qualifier : timestamp, value>

這樣的優(yōu)點(diǎn)是,HBase只存儲(chǔ)有值的單元格,對(duì)于一張稀疏表來說,可以節(jié)省很多存儲(chǔ)空間;但是,為每個(gè)cell都存儲(chǔ)了rowKey, columnFamily, qualifier,因此cf的名字不要太長(zhǎng)。

2. 存儲(chǔ)模型

存儲(chǔ)模型
2.1 存儲(chǔ)概覽
a. 數(shù)據(jù)分片存儲(chǔ)

在HBase中,一張表的數(shù)據(jù)會(huì)被分成幾份,每一份數(shù)據(jù)為一個(gè)region;每個(gè)region內(nèi)存儲(chǔ)的key是連續(xù)范圍內(nèi)的,不同region存儲(chǔ)的key范圍不重合;這些region可能被存儲(chǔ)在同一臺(tái)機(jī)器上,也可能存儲(chǔ)在不同的機(jī)器上。HBase作為一個(gè)分布式數(shù)據(jù)庫,對(duì)數(shù)據(jù)進(jìn)行分片,可以提升吞吐量。

b. HLog:Write-Ahead-Log,寫操作先寫日志

HLog的作用是,當(dāng)一臺(tái)regionServer crash了,可以利用HLog來恢復(fù)內(nèi)存中未持久化到硬盤中的數(shù)據(jù)。需要注意的是,同一臺(tái)server上的所有region共用一個(gè)HLog實(shí)例,因?yàn)榧偃缑總€(gè)region擁有一個(gè)獨(dú)立的HLog,服務(wù)器會(huì)花費(fèi)很多時(shí)間在磁盤尋道上。

c. MemStore:寫緩存,每個(gè)store擁有獨(dú)立的寫緩存

在HBase中,所有的寫操作全部寫到內(nèi)存中,當(dāng)寫緩存(MemStore)寫滿,再刷寫(flush)到磁盤中[2],形成一個(gè)新的文件。這樣做的目的,是為了高速響應(yīng)那些寫請(qǐng)求。

d. HFile:磁盤文件

在存儲(chǔ)上,HBase完全依賴HDFS,磁盤操作是直接調(diào)用HDFS的API(HDFS在維持data locality這一點(diǎn)上足夠智能)。另外,之前提過HBase定義列族的一個(gè)原因是為了方便存儲(chǔ),事實(shí)上,同一列族的數(shù)據(jù)會(huì)被寫到同一文件,因?yàn)榇鎯?chǔ)特性本來就是按照列族定義的。HBase的數(shù)據(jù)在底層文件中時(shí)以KeyValue鍵值對(duì)的形式存儲(chǔ)的,HBase沒有數(shù)據(jù)類型,HFile中存儲(chǔ)的是字節(jié),這些字節(jié)按字典序排列。

e. 讀緩存:同一server上所有region共用

既然HBase有寫緩存,相對(duì)應(yīng)的應(yīng)該有讀緩存。與寫緩存不同的是,HBase的讀緩存是同一server上的所有region共用的。當(dāng)HBase讀取磁盤上某一條數(shù)據(jù)時(shí),HBase會(huì)將整個(gè)HFile block[3]讀到cache中[4]。因此,當(dāng)client請(qǐng)求臨近的數(shù)據(jù)時(shí),因?yàn)榕R近數(shù)據(jù)已經(jīng)被緩存到內(nèi)存中,HBase的響應(yīng)會(huì)更快,也就是說,HBase鼓勵(lì)將那些相似的,會(huì)被一起查找的數(shù)據(jù)存放在一起。另外,當(dāng)我們?cè)谧鋈頀呙钑r(shí),為了不刷走讀緩存中的熱數(shù)據(jù),千萬記得關(guān)閉讀緩存的功能。

2.2 行鍵的索引
a. 行數(shù)據(jù)查找步驟
  • hbase:meta表查找,獲取數(shù)據(jù)所在的region id
  • 根據(jù)region id,到對(duì)應(yīng)的region server上查找,在server上查找對(duì)應(yīng)記錄時(shí),有三種方式
    (1) 掃描緩存
    (2) 塊索引
    (3) 布隆過濾器
b. rowKey索引:hbase:meta表

client會(huì)首先獲取hbase:meta表的位置,再到對(duì)應(yīng)的region server上讀取這張表的內(nèi)容(hbase:meta表其實(shí)就是一張HBase表)。讀到這張hbase:meta表之后,client會(huì)緩存這張表,這張之后的查找就可以復(fù)用了。hbase:meta表的內(nèi)容如下:

| key                                                               | value                                                                               |
| ----------------------------------------------------------------- | ------------------------------------------------------------------------------------|
|                                                                   | info:regioninfo (serialized HRegionInfo instance for this region)                   |
| Region key of the format ([table],[region start key],[region id]) | info:server (server:port of the RegionServer containing this region)                |
|                                                                   | info:serverstartcode (start-time of the RegionServer process containing this region)|

因此,通過查找hbase:meta表,client可以得知對(duì)應(yīng)的數(shù)據(jù)存儲(chǔ)在哪臺(tái)server的那個(gè)region上,接下來就要到對(duì)應(yīng)的server上查找相關(guān)數(shù)據(jù)了。

c. region server上的數(shù)據(jù)查找

當(dāng)接收到一個(gè)讀請(qǐng)求,server會(huì)初始化一個(gè)scanner查找內(nèi)存中是否有相關(guān)數(shù)據(jù);一個(gè)scanner查找硬盤文件中是否存儲(chǔ)了相關(guān)數(shù)據(jù)。查找硬盤文件是一件相當(dāng)繁重的體力活,為了加快文件查找,HBase借助了兩個(gè)工具:塊索引和布隆過濾器。

塊索引和布隆過濾器
d. rowKey索引:塊索引

塊索引存儲(chǔ)在HFile文件中的末端,當(dāng)HBase在查找文件中是否保存了目標(biāo)數(shù)據(jù)時(shí),首先會(huì)將塊索引讀入內(nèi)存。因?yàn)镠File中的KeyValue字節(jié)數(shù)據(jù),是按照字典序排列的,而塊索引存儲(chǔ)了文件中所有塊(HFile block)的起始key,因此可以根據(jù)塊索引迅速定位需要查找的塊,只將可能保存了目標(biāo)數(shù)據(jù)的塊讀到內(nèi)存中,能加快查找速度。

e. rowKey索引:布隆過濾器

雖然塊索引幫助減少了需要讀到內(nèi)存中的數(shù)據(jù),我們依然需要查找每個(gè)文件中的一個(gè)塊,才能完成磁盤數(shù)據(jù)查找,而布隆過濾器則可以幫助我們跳過那些顯然不包含目標(biāo)數(shù)據(jù)的文件。因?yàn)椴悸∵^濾器的特點(diǎn)是,能迅速判斷一個(gè)數(shù)據(jù)集合中包不包含目標(biāo)數(shù)據(jù),判斷結(jié)果有兩種,不包含和可能包含。如下圖所示,布隆過濾器能幫助跳過一些肯定不包含目標(biāo)數(shù)據(jù)的文件。

布隆過濾器

和塊索引一樣,布隆過濾器也被存儲(chǔ)在文件末端,會(huì)被優(yōu)先加載到內(nèi)存中。另外,布隆過濾器分行式和列式兩種,列式需要更多的存儲(chǔ)空間,因此如果是按行讀取數(shù)據(jù),沒必要使用列式的布隆過濾器。布隆過濾器和塊索引的對(duì)比如下:

塊索引 布隆過濾器
快速定位記錄在文件中可能的位置 快速判斷文件中是否包含相應(yīng)記錄
2.3 將隨機(jī)寫轉(zhuǎn)化成順序?qū)?/h5>

HBase的存儲(chǔ)是完全基于HDFS的,而HDFS的特點(diǎn)是不能對(duì)磁盤文件進(jìn)行隨機(jī)修改。因此,HBase無法對(duì)已寫入磁盤文件的表記錄進(jìn)行隨機(jī)修改,但是對(duì)于數(shù)據(jù)庫來說,支持對(duì)表記錄進(jìn)行隨機(jī)修改是基本功能。為此,HBase的方法是將隨機(jī)寫的操作轉(zhuǎn)化成順序?qū)憽?/p>

首先,隨機(jī)的寫操作轉(zhuǎn)化為文件追加操作,按照時(shí)間順序排列,client讀數(shù)據(jù)時(shí)總是優(yōu)先讀到最新的修改。而刪除操作則轉(zhuǎn)化為寫入一個(gè)tombstone標(biāo)記,標(biāo)記著早于這個(gè)tombstone時(shí)間戳的對(duì)應(yīng)行所有記錄作廢。

顯然,因?yàn)镠Base總是進(jìn)行文件追加,隨著時(shí)間積累,文件膨脹很快。major compact的一個(gè)作用就是,真正刪除所有無效的過時(shí)數(shù)據(jù)。

2.4 HBase Compaction和Region Split
a. HBase Compaction

前面已經(jīng)提到過,HBase數(shù)據(jù)寫入的時(shí)候,總是先寫入到寫緩存(MemStore)中,當(dāng)寫緩存寫滿,則flush到磁盤形成一個(gè)新的磁盤文件。可以想象的是,隨著時(shí)間增長(zhǎng),磁盤上這樣的小文件會(huì)越來越多,HBase查找數(shù)據(jù)也需要越來越長(zhǎng)的時(shí)間。為了避免這樣的問題,HBase會(huì)做compaction,合并HFile文件,減少每次查找數(shù)據(jù)的磁盤尋道時(shí)間。compaction分為major compact和minor compact兩種:

  • Minor compact:將多個(gè)小文件簡(jiǎn)單合并成一個(gè)大文件
  • Major compact:將同一列族的所有文件合并成一個(gè)大文件,并且刪除過期無效的數(shù)據(jù)和tombstone標(biāo)記[5]
b. Region Split

client不斷向HBase寫入數(shù)據(jù),region管理的數(shù)據(jù)量不斷膨脹。當(dāng)一個(gè)region內(nèi)存儲(chǔ)的數(shù)據(jù)量到達(dá)閾值,則會(huì)觸發(fā)HBase的region split操作,將老的region拆分成兩個(gè)新的子region。拆分的原則是數(shù)據(jù)量對(duì)半分。為了避免region拆分導(dǎo)致的IO瞬時(shí)上升,region拆分并不會(huì)立刻將拆分重寫所有的磁盤文件文件,而是為每個(gè)子region創(chuàng)建reference文件,這些文件指向了舊的磁盤文件中對(duì)應(yīng)記錄的起始和終止位置。等到子region的compact操作被觸發(fā),在重寫文件的時(shí)候,HBase才會(huì)為每個(gè)子region生成獨(dú)立的磁盤文件。

3. 物理模型

物理模型

HBase的架構(gòu)是一個(gè)典型的master-slave模型,HBase的master節(jié)點(diǎn)叫HMaster,slave節(jié)點(diǎn)就是RegionServer。

3.1 Master的職責(zé)

處理集群相關(guān)的請(qǐng)求(來自client或者其他server節(jié)點(diǎn))

  • 建表或者表變更的操作
  • 打開或者關(guān)閉一個(gè)region
  • metadata元數(shù)據(jù)的管理

集群監(jiān)控(依賴Zookeeper)

  • 監(jiān)控regionServer的狀態(tài)以及負(fù)載均衡等
  • 跟蹤hbase:meta表的位置
  • 后備master節(jié)點(diǎn)需要監(jiān)控當(dāng)前master節(jié)點(diǎn)是否活躍
3.2 RegionServer的職責(zé)

集群初始化過程中

當(dāng)一個(gè)HBase集群起來之后,HMaster會(huì)在對(duì)應(yīng)的regionServer上起一個(gè)HRegionServer進(jìn)程。HRegionServer負(fù)責(zé)打開對(duì)應(yīng)的region,并創(chuàng)建對(duì)應(yīng)的HRegion實(shí)例。當(dāng)HRegion打開之后,它會(huì)為每個(gè)表的HColumnFamily創(chuàng)建一個(gè)Store實(shí)例,ColumnFamily是用戶在創(chuàng)建表時(shí)定義好的,ColumnFamily在每個(gè)region中和Store實(shí)例一一對(duì)應(yīng)。每個(gè)Store實(shí)例包含一個(gè)或者多個(gè)StoreFile實(shí)例,StoreFile是對(duì)實(shí)際存儲(chǔ)數(shù)據(jù)文件HFile的輕量級(jí)封裝。每個(gè)Store對(duì)應(yīng)一個(gè)MemStore。一個(gè)HRegionServer共享一個(gè)HLog實(shí)例。

集群運(yùn)行過程中

  • compaction和split是由RegionServer獨(dú)立判斷決定是否執(zhí)行的,但過程中包含一些必要的和master、ZK的通信
  • client端發(fā)起的讀寫請(qǐng)求,也直接由對(duì)應(yīng)RegionServer處理(master不處理)[6],流程如下:
    (1) client端向ZK請(qǐng)求hbase:meta表位置,取得表內(nèi)容
    (2) 查詢meta表得知數(shù)據(jù)存在哪臺(tái)RegionServer上
    (3)直接與RegionServer通信,進(jìn)行讀寫操作

注:
[1] 同一張表的column family數(shù)量不能超過2-3個(gè)。因?yàn)槟壳埃琭lush和compaction操作是基于region進(jìn)行的,當(dāng)一個(gè)column family觸發(fā)了MemStore flush操作,相鄰的column family都會(huì)被刷寫到磁盤,即使它們MemStore內(nèi)的數(shù)據(jù)量還很小。因此,如果同一張表內(nèi)column family的數(shù)量過多,flush和compaction將會(huì)帶來更多不必要的I/O負(fù)載(當(dāng)然這個(gè)問題可以通過,將flush和compaction改成列族之間互不影響來解決)。通常情況下,定義表的時(shí)候盡量使用單列族,除非列與列的查詢是相對(duì)獨(dú)立的,再考慮使用多個(gè)列族,比如client并不會(huì)同時(shí)請(qǐng)求兩個(gè)列族的數(shù)據(jù)。
當(dāng)同一張內(nèi)有多個(gè)列族時(shí),注意一些列族間的數(shù)據(jù)量是否一致,假如列族A和列族B的數(shù)據(jù)量相差懸殊,列族A的大數(shù)據(jù)量會(huì)導(dǎo)致表數(shù)據(jù)被分片到很多個(gè)機(jī)器上,此時(shí)再對(duì)列族B的數(shù)據(jù)做掃描,效率會(huì)很低。

[2] 能觸發(fā)MemStore flush操作的有三種情形:

  • 當(dāng)一個(gè)MemStore的數(shù)據(jù)量達(dá)到hbase.hregion.memstore.flush.size,同一region的所有MemStore的數(shù)據(jù)都會(huì)被刷寫道磁盤
  • 當(dāng)全部的MemStore的數(shù)據(jù)量達(dá)到hbase.regionserver.global.memstore.upperLimit,同一RegionServer的多個(gè)region的MemStore的數(shù)據(jù)會(huì)被刷寫到磁盤。按照每region的MemStore大小,從大到小刷寫到磁盤,直到總的MemStore大小下降到hbase.regionserver.global.memstore.upperLimit
  • 當(dāng)region server的WAL的log數(shù)量達(dá)到hbase.regionserver.max.logs,該server上多個(gè)region的MemStore會(huì)被刷寫到磁盤(按照時(shí)間順序),以降低WAL的大小。

[3] HFile block:HFile塊和Hadoop塊是兩個(gè)獨(dú)立的概念。HFile塊的默認(rèn)大小是64KB,而Hadoop塊的默認(rèn)大小為64MB。另外,如果有需要的話,用戶還可以自行定義HFile塊大小。一般情況下,如果客戶端都是順序訪問表記錄,在讀緩存的作用下,建議使用較大的HFile塊;如果客戶端都是隨機(jī)訪問表記錄,建議使用較小的HFile塊,不過也需要更多的內(nèi)存來存儲(chǔ)塊索引(塊索引會(huì)優(yōu)先存放在cache中),并且創(chuàng)建過程也會(huì)變得更慢,因?yàn)槲覀儽仨氃诿總€(gè)數(shù)據(jù)塊結(jié)束的時(shí)候刷寫壓縮流,導(dǎo)致一個(gè)FS I/O刷寫。

[4] 關(guān)于讀緩存的更詳細(xì)資料:http://zh.hortonworks.com/blog/hbase-blockcache-101/

[5] HBase默認(rèn)每7天對(duì)HBase做一輪major compact,在0.96的版本之前,這個(gè)周期是1天。

[6] 正因?yàn)閏lient讀寫數(shù)據(jù)的過程沒有master節(jié)點(diǎn)的參與,如果master failover了,hbase集群仍然可以穩(wěn)定運(yùn)行一段時(shí)間,只是像region分裂,RegionServer failover處理等需要master節(jié)點(diǎn)參與的工作,無法完成了。

未完待續(xù)...

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

相關(guān)閱讀更多精彩內(nèi)容

  • HBase存儲(chǔ)架構(gòu)圖 HBase Master 為Region server分配region 負(fù)責(zé)Region s...
    kimibob閱讀 5,749評(píng)論 0 52
  • HBase Architectural Components(HBase架構(gòu)組件) HBase架構(gòu)也是主從架構(gòu),由...
    陌上疏影涼閱讀 2,601評(píng)論 0 7
  • 簡(jiǎn)介 [HBase]——Hadoop Database的簡(jiǎn)稱,Google BigTable的另一種開源實(shí)現(xiàn)方式,...
    高廣超閱讀 2,542評(píng)論 1 27
  • 1. HBase介紹,Hbase是什么? HBase -- Hadoop Database ,是一個(gè)高可靠、高性能...
    奉先閱讀 3,952評(píng)論 1 36
  • 最近在逐步跟進(jìn)Hbase的相關(guān)工作,由于之前對(duì)Hbase并不怎么了解,因此系統(tǒng)地學(xué)習(xí)了下Hbase,為了加深對(duì)Hb...
    飛鴻無痕閱讀 50,568評(píng)論 19 272

友情鏈接更多精彩內(nèi)容