訂閱
糾錯(cuò)
加入自媒體

HBase 知識(shí)體系吐血總結(jié)

2021-11-17 11:37
園陌
關(guān)注

HBase 涉及的知識(shí)點(diǎn)如下圖所示,本文將逐一講解:

本文目錄如上圖

本文檔參考了關(guān)于 HBase 的官網(wǎng)及其他眾多資料整理而成,為了整潔的排版及舒適的閱讀,對(duì)于模糊不清晰的圖片及黑白圖片進(jìn)行重新繪制成了高清彩圖。

一、HBase 基礎(chǔ)1. HBase 基本介紹

簡(jiǎn)介

HBase 是 BigTable 的開(kāi)源 Java 版本。是建立在 HDFS 之上,提供高可靠性、高性能、列存儲(chǔ)、可伸縮、實(shí)時(shí)讀寫(xiě) NoSql 的數(shù)據(jù)庫(kù)系統(tǒng)。

它介于 NoSql 和 RDBMS 之間,僅能通過(guò)主鍵(row key)和主鍵的 range 來(lái)檢索數(shù)據(jù),僅支持單行事務(wù)(可通過(guò) hive 支持來(lái)實(shí)現(xiàn)多表 join 等復(fù)雜操作)。

主要用來(lái)存儲(chǔ)結(jié)構(gòu)化和半結(jié)構(gòu)化的松散數(shù)據(jù)。

Hbase 查詢(xún)數(shù)據(jù)功能很簡(jiǎn)單,不支持 join 等復(fù)雜操作,不支持復(fù)雜的事務(wù)(行級(jí)的事務(wù))Hbase 中支持的數(shù)據(jù)類(lèi)型:byte[]與 hadoop 一樣,Hbase 目標(biāo)主要依靠橫向擴(kuò)展,通過(guò)不斷增加廉價(jià)的商用服務(wù)器,來(lái)增加計(jì)算和存儲(chǔ)能力。

HBase 中的表一般有這樣的特點(diǎn):

大:一個(gè)表可以有上十億行,上百萬(wàn)列面向列:面向列(族)的存儲(chǔ)和權(quán)限控制,列(族)獨(dú)立檢索。稀疏:對(duì)于為空(null)的列,并不占用存儲(chǔ)空間,因此,表可以設(shè)計(jì)的非常稀疏。

HBase 的發(fā)展歷程

HBase 的原型是 Google 的 BigTable 論文,受到了該論文思想的啟發(fā),目前作為 Hadoop 的子項(xiàng)目來(lái)開(kāi)發(fā)維護(hù),用于支持結(jié)構(gòu)化的數(shù)據(jù)存儲(chǔ)。

2006 年 Google 發(fā)表 BigTable 白皮書(shū)2006 年開(kāi)始開(kāi)發(fā) HBase2008 HBase 成為了 Hadoop 的子項(xiàng)目2010 年 HBase 成為 Apache 頂級(jí)項(xiàng)目2. HBase 與 Hadoop 的關(guān)系

HDFS

為分布式存儲(chǔ)提供文件系統(tǒng)針對(duì)存儲(chǔ)大尺寸的文件進(jìn)行優(yōu)化,不需要對(duì) HDFS 上的文件進(jìn)行隨機(jī)讀寫(xiě)直接使用文件數(shù)據(jù)模型不靈活使用文件系統(tǒng)和處理框架優(yōu)化一次寫(xiě)入,多次讀取的方式

HBase

提供表狀的面向列的數(shù)據(jù)存儲(chǔ)針對(duì)表狀數(shù)據(jù)的隨機(jī)讀寫(xiě)進(jìn)行優(yōu)化使用 key-value 操作數(shù)據(jù)提供靈活的數(shù)據(jù)模型使用表狀存儲(chǔ),支持 MapReduce,依賴(lài) HDFS優(yōu)化了多次讀,以及多次寫(xiě)3. RDBMS 與 HBase 的對(duì)比

關(guān)系型數(shù)據(jù)庫(kù)

結(jié)構(gòu):

數(shù)據(jù)庫(kù)以表的形式存在支持 FAT、NTFS、EXT、文件系統(tǒng)使用 Commit log 存儲(chǔ)日志參考系統(tǒng)是坐標(biāo)系統(tǒng)使用主鍵(PK)支持分區(qū)使用行、列、單元格

功能:

支持向上擴(kuò)展使用 SQL 查詢(xún)面向行,即每一行都是一個(gè)連續(xù)單元數(shù)據(jù)總量依賴(lài)于服務(wù)器配置具有 ACID 支持適合結(jié)構(gòu)化數(shù)據(jù)傳統(tǒng)關(guān)系型數(shù)據(jù)庫(kù)一般都是中心化的支持事務(wù)支持 Join

HBase

結(jié)構(gòu):

數(shù)據(jù)庫(kù)以 region 的形式存在支持 HDFS 文件系統(tǒng)使用 WAL(Write-Ahead Logs)存儲(chǔ)日志參考系統(tǒng)是 Zookeeper使用行鍵(row key)支持分片使用行、列、列族和單元格

功能:

支持向外擴(kuò)展使用 API 和 MapReduce 來(lái)訪(fǎng)問(wèn) HBase 表數(shù)據(jù)面向列,即每一列都是一個(gè)連續(xù)的單元數(shù)據(jù)總量不依賴(lài)具體某臺(tái)機(jī)器,而取決于機(jī)器數(shù)量HBase 不支持 ACID(Atomicity、Consistency、Isolation、Durability)適合結(jié)構(gòu)化數(shù)據(jù)和非結(jié)構(gòu)化數(shù)據(jù)一般都是分布式的HBase 不支持事務(wù)不支持 Join4. HBase 特征簡(jiǎn)要海量存儲(chǔ)

Hbase 適合存儲(chǔ) PB 級(jí)別的海量數(shù)據(jù),在 PB 級(jí)別的數(shù)據(jù)以及采用廉價(jià) PC 存儲(chǔ)的情況下,能在幾十到百毫秒內(nèi)返回?cái)?shù)據(jù)。這與 Hbase 的極易擴(kuò)展性息息相關(guān)。正式因?yàn)?Hbase 良好的擴(kuò)展性,才為海量數(shù)據(jù)的存儲(chǔ)提供了便利。

列式存儲(chǔ)

這里的列式存儲(chǔ)其實(shí)說(shuō)的是列族存儲(chǔ),Hbase 是根據(jù)列族來(lái)存儲(chǔ)數(shù)據(jù)的。列族下面可以有非常多的列,列族在創(chuàng)建表的時(shí)候就必須指定。

極易擴(kuò)展

Hbase 的擴(kuò)展性主要體現(xiàn)在兩個(gè)方面,一個(gè)是基于上層處理能力(RegionServer)的擴(kuò)展,一個(gè)是基于存儲(chǔ)的擴(kuò)展(HDFS)。通過(guò)橫向添加 RegionSever 的機(jī)器,進(jìn)行水平擴(kuò)展,提升 Hbase 上層的處理能力,提升 Hbsae 服務(wù)更多 Region 的能力。備注:RegionServer 的作用是管理 region、承接業(yè)務(wù)的訪(fǎng)問(wèn),這個(gè)后面會(huì)詳細(xì)的介紹通過(guò)橫向添加 Datanode 的機(jī)器,進(jìn)行存儲(chǔ)層擴(kuò)容,提升 Hbase 的數(shù)據(jù)存儲(chǔ)能力和提升后端存儲(chǔ)的讀寫(xiě)能力。

高并發(fā)

由于目前大部分使用 Hbase 的架構(gòu),都是采用的廉價(jià) PC,因此單個(gè) IO 的延遲其實(shí)并不小,一般在幾十到上百 ms 之間。這里說(shuō)的高并發(fā),主要是在并發(fā)的情況下,Hbase 的單個(gè) IO 延遲下降并不多。能獲得高并發(fā)、低延遲的服務(wù)。

稀疏

稀疏主要是針對(duì) Hbase 列的靈活性,在列族中,你可以指定任意多的列,在列數(shù)據(jù)為空的情況下,是不會(huì)占用存儲(chǔ)空間的。

二、HBase 基礎(chǔ)架構(gòu)

HMaster

功能:

監(jiān)控 RegionServer處理 RegionServer 故障轉(zhuǎn)移處理元數(shù)據(jù)的變更處理 region 的分配或移除在空閑時(shí)間進(jìn)行數(shù)據(jù)的負(fù)載均衡通過(guò) Zookeeper 發(fā)布自己的位置給客戶(hù)端RegionServer

功能:

負(fù)責(zé)存儲(chǔ) HBase 的實(shí)際數(shù)據(jù)處理分配給它的 Region刷新緩存到 HDFS維護(hù) HLog執(zhí)行壓縮負(fù)責(zé)處理 Region 分片

組件:

Write-Ahead logs

HBase 的修改記錄,當(dāng)對(duì) HBase 讀寫(xiě)數(shù)據(jù)的時(shí)候,數(shù)據(jù)不是直接寫(xiě)進(jìn)磁盤(pán),它會(huì)在內(nèi)存中保留一段時(shí)間(時(shí)間以及數(shù)據(jù)量閾值可以設(shè)定)。但把數(shù)據(jù)保存在內(nèi)存中可能有更高的概率引起數(shù)據(jù)丟失,為了解決這個(gè)問(wèn)題,數(shù)據(jù)會(huì)先寫(xiě)在一個(gè)叫做 Write-Ahead logfile 的文件中,然后再寫(xiě)入內(nèi)存中。所以在系統(tǒng)出現(xiàn)故障的時(shí)候,數(shù)據(jù)可以通過(guò)這個(gè)日志文件重建。

HFile

這是在磁盤(pán)上保存原始數(shù)據(jù)的實(shí)際的物理文件,是實(shí)際的存儲(chǔ)文件。

Store

HFile 存儲(chǔ)在 Store 中,一個(gè) Store 對(duì)應(yīng) HBase 表中的一個(gè)列族。

MemStore

顧名思義,就是內(nèi)存存儲(chǔ),位于內(nèi)存中,用來(lái)保存當(dāng)前的數(shù)據(jù)操作,所以當(dāng)數(shù)據(jù)保存在 WAL 中之后,RegsionServer 會(huì)在內(nèi)存中存儲(chǔ)鍵值對(duì)。

Region

Hbase 表的分片,HBase 表會(huì)根據(jù) RowKey 值被切分成不同的 region 存儲(chǔ)在 RegionServer 中,在一個(gè) RegionServer 中可以有多個(gè)不同的 region。

三、HBase 常用 shell 操作1) 添加操作進(jìn)入 HBase 客戶(hù)端命令操作界面$ bin/hbase shell

查看幫助命令hbase(main):001:0> help

查看當(dāng)前數(shù)據(jù)庫(kù)中有哪些表hbase(main):002:0> list

創(chuàng)建一張表

創(chuàng)建 user 表,包含 info、data 兩個(gè)列族

hbase(main):010:0> create 'user', 'info', 'data'

或者

hbase(main):010:0> create 'user', {NAME => 'info', VERSIONS => '3'},{NAME => 'data'}
添加數(shù)據(jù)操作

向 user 表中插入信息,row key 為 rk0001,列族 info 中添加 name 列標(biāo)示符,值為 zhangsan

hbase(main):011:0> put 'user', 'rk0001', 'info:name', 'zhangsan'

向 user 表中插入信息,row key 為 rk0001,列族 info 中添加 gender 列標(biāo)示符,值為 female

hbase(main):012:0> put 'user', 'rk0001', 'info:gender', 'female'

向 user 表中插入信息,row key 為 rk0001,列族 info 中添加 age 列標(biāo)示符,值為 20

hbase(main):013:0> put 'user', 'rk0001', 'info:age', 20

向 user 表中插入信息,row key 為 rk0001,列族 data 中添加 pic 列標(biāo)示符,值為 picture

hbase(main):014:0> put 'user', 'rk0001', 'data:pic', 'picture'

2) 查詢(xún)操作通過(guò) rowkey 進(jìn)行查詢(xún)

獲取 user 表中 row key 為 rk0001 的所有信息

hbase(main):015:0> get 'user', 'rk0001'

查看 rowkey 下面的某個(gè)列族的信息

獲取 user 表中 row key 為 rk0001,info 列族的所有信息

hbase(main):016:0> get 'user', 'rk0001', 'info'

查看 rowkey 指定列族指定字段的值

獲取 user 表中 row key 為 rk0001,info 列族的 name、age 列標(biāo)示符的信息

hbase(main):017:0> get 'user', 'rk0001', 'info:name', 'info:age'

查看 rowkey 指定多個(gè)列族的信息

獲取 user 表中 row key 為 rk0001,info、data 列族的信息

hbase(main):018:0> get 'user', 'rk0001', 'info', 'data'

或者這樣寫(xiě)

hbase(main):019:0> get 'user', 'rk0001', {COLUMN => ['info', 'data']}

或者這樣寫(xiě)

hbase(main):020:0> get 'user', 'rk0001', {COLUMN => ['info:name', 'data:pic']}

指定 rowkey 與列值查詢(xún)

獲取 user 表中 row key 為 rk0001,cell 的值為 zhangsan 的信息

hbase(main):030:0> get 'user', 'rk0001', {FILTER => "ValueFilter(=, 'binary:zhangsan')"}

指定 rowkey 與列值模糊查詢(xún)

獲取 user 表中 row key 為 rk0001,列標(biāo)示符中含有 a 的信息

hbase(main):031:0> get 'user', 'rk0001', {FILTER => "(QualifierFilter(=,'substring:a'))"}

繼續(xù)插入一批數(shù)據(jù)

hbase(main):032:0> put 'user', 'rk0002', 'info:name', 'fanbingbing'

hbase(main):033:0> put 'user', 'rk0002', 'info:gender', 'female'

hbase(main):034:0> put 'user', 'rk0002', 'info:nationality', '中國(guó)'

hbase(main):035:0> get 'user', 'rk0002', {FILTER => "ValueFilter(=, 'binary:中國(guó)')"}

查詢(xún)所有數(shù)據(jù)

查詢(xún) user 表中的所有信息

scan 'user'

列族查詢(xún)

查詢(xún) user 表中列族為 info 的信息

scan 'user', {COLUMNS => 'info'}

scan 'user', {COLUMNS => 'info', RAW => true, VERSIONS => 5}

scan 'user', {COLUMNS => 'info', RAW => true, VERSIONS => 3}

多列族查詢(xún)

查詢(xún) user 表中列族為 info 和 data 的信息

scan 'user', {COLUMNS => ['info', 'data']}

scan 'user', {COLUMNS => ['info:name', 'data:pic']}

指定列族與某個(gè)列名查詢(xún)

查詢(xún) user 表中列族為 info、列標(biāo)示符為 name 的信息

scan 'user', {COLUMNS => 'info:name'}

指定列族與列名以及限定版本查詢(xún)

查詢(xún) user 表中列族為 info、列標(biāo)示符為 name 的信息,并且版本最新的 5 個(gè)

scan 'user', {COLUMNS => 'info:name', VERSIONS => 5}

指定多個(gè)列族與按照數(shù)據(jù)值模糊查詢(xún)

查詢(xún) user 表中列族為 info 和 data 且列標(biāo)示符中含有 a 字符的信息

scan 'user', {COLUMNS => ['info', 'data'], FILTER => "(QualifierFilter(=,'substring:a'))"}

rowkey 的范圍值查詢(xún)

查詢(xún) user 表中列族為 info,rk 范圍是(rk0001, rk0003)的數(shù)據(jù)

scan 'user', {COLUMNS => 'info', STARTROW => 'rk0001', ENDROW => 'rk0003'}

指定 rowkey 模糊查詢(xún)

查詢(xún) user 表中 row key 以 rk 字符開(kāi)頭的

scan 'user',{FILTER=>"PrefixFilter('rk')"}

指定數(shù)據(jù)范圍值查詢(xún)

查詢(xún) user 表中指定范圍的數(shù)據(jù)

scan 'user', {TIMERANGE => [1392368783980, 1392380169184]}

統(tǒng)計(jì)一張表有多少行數(shù)據(jù)count 'user'

3) 更新操作更新數(shù)據(jù)值

更新操作同插入操作一模一樣,只不過(guò)有數(shù)據(jù)就更新,沒(méi)數(shù)據(jù)就添加。

更新版本號(hào)

將 user 表的 f1 列族版本號(hào)改為 5

hbase(main):050:0> alter 'user', NAME => 'info', VERSIONS => 5

4) 刪除操作指定 rowkey 以及列名進(jìn)行刪除

刪除 user 表 row key 為 rk0001,列標(biāo)示符為 info:name 的數(shù)據(jù)

hbase(main):045:0> delete 'user', 'rk0001', 'info:name'

指定 rowkey,列名以及字段值進(jìn)行刪除

刪除 user 表 row key 為 rk0001,列標(biāo)示符為 info:name,timestamp 為 1392383705316 的數(shù)據(jù)

delete 'user', 'rk0001', 'info:name', 1392383705316

刪除一個(gè)列族

刪除一個(gè)列族

alter 'user', NAME => 'info', METHOD => 'delete'

或者

alter 'user', NAME => 'info', METHOD => 'delete'

清空表數(shù)據(jù)hbase(main):017:0> truncate 'user'

刪除表

首先需要先讓該表為 disable 狀態(tài),使用命令:

hbase(main):049:0> disable 'user

然后才能 drop 這個(gè)表,使用命令:

hbase(main):050:0> drop 'user'

注意:如果直接 drop 表,會(huì)報(bào)錯(cuò):Drop the named table. Table must first be disabled

四、HBase 的高級(jí) shell 管理命令status

例如:顯示服務(wù)器狀態(tài)

hbase(main):058:0> status 'node01'

whoami

顯示 HBase 當(dāng)前用戶(hù),例如:

hbase> whoami

list

顯示當(dāng)前所有的表

hbase> list

count

統(tǒng)計(jì)指定表的記錄數(shù),例如:

hbase> count 'user'

describe

展示表結(jié)構(gòu)信息

hbase> describe 'user'

exists

檢查表是否存在,適用于表量特別多的情況

hbase> exists 'user'

is_enabled、is_disabled

檢查表是否啟用或禁用

hbase> is_enabled 'user'

alter

該命令可以改變表和列族的模式,例如:

為當(dāng)前表增加列族:

hbase> alter 'user', NAME => 'CF2', VERSIONS => 2

為當(dāng)前表刪除列族:

hbase(main):002:0>  alter 'user', 'delete' => 'CF2'

disable/enable

禁用一張表/啟用一張表

drop

刪除一張表,記得在刪除表之前必須先禁用

truncate

清空表

圖片標(biāo)題

圖片標(biāo)題

圖片標(biāo)題

圖片標(biāo)題

圖片標(biāo)題

圖片標(biāo)題

圖片標(biāo)題

圖片標(biāo)題

圖片標(biāo)題

         

圖片標(biāo)題

圖片標(biāo)題

2. 過(guò)濾器查詢(xún)

過(guò)濾器的類(lèi)型很多,但是可以分為兩大類(lèi)——比較過(guò)濾器,專(zhuān)用過(guò)濾器。

過(guò)濾器的作用是在服務(wù)端判斷數(shù)據(jù)是否滿(mǎn)足條件,然后只將滿(mǎn)足條件的數(shù)據(jù)返回給客戶(hù)端;

hbase 過(guò)濾器的比較運(yùn)算符:

LESS  <

LESS_OR_EQUAL <=

EQUAL =

NOT_EQUAL <>

GREATER_OR_EQUAL >=

GREATER >

NO_OP 排除所有

Hbase 過(guò)濾器的比較器(指定比較機(jī)制):

BinaryComparator  按字節(jié)索引順序比較指定字節(jié)數(shù)組,采用Bytes.compareTo(byte[])

BinaryPrefixComparator 跟前面相同,只是比較左端的數(shù)據(jù)是否相同

NullComparator 判斷給定的是否為空

BitComparator 按位比較

RegexStringComparator 提供一個(gè)正則的比較器,僅支持 EQUAL 和非EQUAL

SubstringComparator 判斷提供的子串是否出現(xiàn)在value中。

1) 比較過(guò)濾器rowKey 過(guò)濾器 RowFilter

通過(guò) RowFilter 過(guò)濾比 rowKey 0003 小的所有值出來(lái)

@Test

public  void rowKeyFilter() throws IOException {
 

圖片標(biāo)題

列族過(guò)濾器 FamilyFilter

查詢(xún)比 f2 列族小的所有的列族內(nèi)的數(shù)據(jù)

@Test

public  void familyFilter() throws IOException {

圖片標(biāo)題

列過(guò)濾器 QualifierFilter

只查詢(xún) name 列的值

@Test

public  void qualifierFilter() throws IOException {

圖片標(biāo)題

列值過(guò)濾器 ValueFilter

查詢(xún)所有列當(dāng)中包含 8 的數(shù)據(jù)

@Test

圖片標(biāo)題

2) 專(zhuān)用過(guò)濾器單列值過(guò)濾器 SingleColumnValueFilter

SingleColumnValueFilter 會(huì)返回滿(mǎn)足條件的整列值的所有字段

@Test

圖片標(biāo)題

myuser.close();


列值排除過(guò)濾器 SingleColumnValueExcludeFilter

與 SingleColumnValueFilter 相反,會(huì)排除掉指定的列,其他的列全部返回

rowkey 前綴過(guò)濾器 PrefixFilter

查詢(xún)以 00 開(kāi)頭的所有前綴的 rowkey

@Test

圖片標(biāo)題

分頁(yè)過(guò)濾器 PageFilter

分頁(yè)過(guò)濾器 PageFilter

@Test

圖片標(biāo)題

圖片標(biāo)題

圖片標(biāo)題

3) 多過(guò)濾器綜合查詢(xún) FilterList

需求:使用 SingleColumnValueFilter 查詢(xún) f1 列族,name 為劉備的數(shù)據(jù),并且同時(shí)滿(mǎn)足 rowkey 的前綴以 00 開(kāi)頭的數(shù)據(jù)(PrefixFilter)

圖片標(biāo)題

圖片標(biāo)題

圖片標(biāo)題

六、HBase 底層原理1. 系統(tǒng)架構(gòu)

HBase系統(tǒng)架構(gòu)

根據(jù)這幅圖,解釋下HBase中各個(gè)組件

1) Client包含訪(fǎng)問(wèn)hbase的接口,Client維護(hù)著一些cache來(lái)加快對(duì)hbase的訪(fǎng)問(wèn),比如regione的位置信息.2) Zookeeper

HBase可以使用內(nèi)置的Zookeeper,也可以使用外置的,在實(shí)際生產(chǎn)環(huán)境,為了保持統(tǒng)一性,一般使用外置Zookeeper。

Zookeeper在HBase中的作用:

保證任何時(shí)候,集群中只有一個(gè)master存貯所有Region的尋址入口實(shí)時(shí)監(jiān)控Region Server的狀態(tài),將Region server的上線(xiàn)和下線(xiàn)信息實(shí)時(shí)通知給Master3) HMaster為Region server分配region負(fù)責(zé)region server的負(fù)載均衡發(fā)現(xiàn)失效的region server并重新分配其上的regionHDFS上的垃圾文件回收處理schema更新請(qǐng)求4) HRegion ServerHRegion server維護(hù)HMaster分配給它的region,處理對(duì)這些region的IO請(qǐng)求HRegion server負(fù)責(zé)切分在運(yùn)行過(guò)程中變得過(guò)大的region從圖中可以看到,Client訪(fǎng)問(wèn)HBase上數(shù)據(jù)的過(guò)程并不需要HMaster參與(尋址訪(fǎng)問(wèn)Zookeeper和HRegion server,數(shù)據(jù)讀寫(xiě)訪(fǎng)問(wèn)HRegione server)

HMaster僅僅維護(hù)者table和HRegion的元數(shù)據(jù)信息,負(fù)載很低。

2. HBase的表數(shù)據(jù)模型

HBase的表結(jié)構(gòu)1) 行鍵 Row Key

與nosql數(shù)據(jù)庫(kù)一樣,row key是用來(lái)檢索記錄的主鍵。訪(fǎng)問(wèn)hbase table中的行,只有三種方式:

通過(guò)單個(gè)row key訪(fǎng)問(wèn)通過(guò)row key的range全表掃描

Row Key 行鍵可以是任意字符串(最大長(zhǎng)度是 64KB,實(shí)際應(yīng)用中長(zhǎng)度一般為 10-100bytes),在hbase內(nèi)部,row key保存為字節(jié)數(shù)組。

Hbase會(huì)對(duì)表中的數(shù)據(jù)按照rowkey排序(字典順序)

存儲(chǔ)時(shí),數(shù)據(jù)按照Row key的字典序(byte order)排序存儲(chǔ)。設(shè)計(jì)key時(shí),要充分排序存儲(chǔ)這個(gè)特性,將經(jīng)常一起讀取的行存儲(chǔ)放到一起。(位置相關(guān)性)。

注意:字典序?qū)nt排序的結(jié)果是1,10,100,11,12,13,14,15,16,17,18,19,2,20,21 ... 。要保持整形的自然序,行鍵必須用0作左填充。

行的一次讀寫(xiě)是原子操作 (不論一次讀寫(xiě)多少列)。這個(gè)設(shè)計(jì)決策能夠使用戶(hù)很容易的理解程序在對(duì)同一個(gè)行進(jìn)行并發(fā)更新操作時(shí)的行為。

2) 列族 Column Family

HBase表中的每個(gè)列,都?xì)w屬于某個(gè)列族。列族是表的schema的一部分(而列不是),必須在使用表之前定義。

列名都以列族作為前綴。例如 courses:history ,  courses:math 都屬于 courses 這個(gè)列族。

訪(fǎng)問(wèn)控制、磁盤(pán)和內(nèi)存的使用統(tǒng)計(jì)都是在列族層面進(jìn)行的。列族越多,在取一行數(shù)據(jù)時(shí)所要參與IO、搜尋的文件就越多,所以,如果沒(méi)有必要,不要設(shè)置太多的列族。

3) 列 Column

列族下面的具體列,屬于某一個(gè)ColumnFamily,類(lèi)似于在mysql當(dāng)中創(chuàng)建的具體的列。

4) 時(shí)間戳 Timestamp

HBase中通過(guò)row和columns確定的為一個(gè)存貯單元稱(chēng)為cell。每個(gè) cell都保存著同一份數(shù)據(jù)的多個(gè)版本。版本通過(guò)時(shí)間戳來(lái)索引。時(shí)間戳的類(lèi)型是 64位整型。時(shí)間戳可以由hbase(在數(shù)據(jù)寫(xiě)入時(shí)自動(dòng) )賦值,此時(shí)時(shí)間戳是精確到毫秒的當(dāng)前系統(tǒng)時(shí)間。時(shí)間戳也可以由客戶(hù)顯式賦值。如果應(yīng)用程序要避免數(shù)據(jù)版本沖突,就必須自己生成具有唯一性的時(shí)間戳。每個(gè) cell中,不同版本的數(shù)據(jù)按照時(shí)間倒序排序,即最新的數(shù)據(jù)排在最前面。

為了避免數(shù)據(jù)存在過(guò)多版本造成的的管理 (包括存貯和索引)負(fù)擔(dān),hbase提供了兩種數(shù)據(jù)版本回收方式:

保存數(shù)據(jù)的最后n個(gè)版本保存最近一段時(shí)間內(nèi)的版本(設(shè)置數(shù)據(jù)的生命周期TTL)。

用戶(hù)可以針對(duì)每個(gè)列族進(jìn)行設(shè)置。

5) 單元 Cell

由{row key, column( =<family> + <label>), version} 唯一確定的單元。cell中的數(shù)據(jù)是沒(méi)有類(lèi)型的,全部是字節(jié)碼形式存貯。

6) 版本號(hào) VersionNum

數(shù)據(jù)的版本號(hào),每條數(shù)據(jù)可以有多個(gè)版本號(hào),默認(rèn)值為系統(tǒng)時(shí)間戳,類(lèi)型為L(zhǎng)ong。

3. 物理存儲(chǔ)1) 整體結(jié)構(gòu)

HBase 整體結(jié)構(gòu)

Table 中的所有行都按照 Row Key 的字典序排列。

Table 在行的方向上分割為多個(gè) HRegion。

HRegion按大小分割的(默認(rèn)10G),每個(gè)表一開(kāi)始只有一 個(gè)HRegion,隨著數(shù)據(jù)不斷插入表,HRegion不斷增大,當(dāng)增大到一個(gè)閥值的時(shí)候,HRegion就會(huì)等分會(huì)兩個(gè)新的HRegion。當(dāng)Table 中的行不斷增多,就會(huì)有越來(lái)越多的 HRegion。

HRegion 是 HBase 中分布式存儲(chǔ)和負(fù)載均衡的最小單元。最小單元就表示不同的 HRegion 可以分布在不同的 HRegion Server 上。但一個(gè) HRegion 是不會(huì)拆分到多個(gè) Server 上的。

HRegion 雖然是負(fù)載均衡的最小單元,但并不是物理存儲(chǔ)的最小單元。事實(shí)上,HRegion 由一個(gè)或者多個(gè) Store 組成,每個(gè) Store 保存一個(gè) Column Family。每個(gè) Strore 又由一個(gè) MemStore 和0至多個(gè) StoreFile 組成。如上圖。

2) StoreFile 和 HFile 結(jié)構(gòu)

StoreFile以HFile格式保存在HDFS上。

HFile的格式為:

HFile 格式

首先HFile文件是不定長(zhǎng)的,長(zhǎng)度固定的只有其中的兩塊:Trailer和FileInfo。正如圖中所示的,Trailer中有指針指向其他數(shù) 據(jù)塊的起始點(diǎn)。

File Info中記錄了文件的一些Meta信息,例如:AVG_KEY_LEN, AVG_VALUE_LEN, LAST_KEY, COMPARATOR, MAX_SEQ_ID_KEY等。

Data Index和Meta Index塊記錄了每個(gè)Data塊和Meta塊的起始點(diǎn)。

Data Block是HBase I/O的基本單元,為了提高效率,HRegionServer中有基于LRU的Block Cache機(jī)制。每個(gè)Data塊的大小可以在創(chuàng)建一個(gè)Table的時(shí)候通過(guò)參數(shù)指定,大號(hào)的Block有利于順序Scan,小號(hào)Block利于隨機(jī)查詢(xún)。每個(gè)Data塊除了開(kāi)頭的Magic以外就是一個(gè)個(gè)KeyValue對(duì)拼接而成, Magic內(nèi)容就是一些隨機(jī)數(shù)字,目的是防止數(shù)據(jù)損壞。

HFile里面的每個(gè)KeyValue對(duì)就是一個(gè)簡(jiǎn)單的byte數(shù)組。但是這個(gè)byte數(shù)組里面包含了很多項(xiàng),并且有固定的結(jié)構(gòu)。我們來(lái)看看里面的具體結(jié)構(gòu):

HFile 具體結(jié)構(gòu)

開(kāi)始是兩個(gè)固定長(zhǎng)度的數(shù)值,分別表示Key的長(zhǎng)度和Value的長(zhǎng)度。緊接著是Key,開(kāi)始是固定長(zhǎng)度的數(shù)值,表示RowKey的長(zhǎng)度,緊接著是 RowKey,然后是固定長(zhǎng)度的數(shù)值,表示Family的長(zhǎng)度,然后是Family,接著是Qualifier,然后是兩個(gè)固定長(zhǎng)度的數(shù)值,表示Time Stamp和Key Type(Put/Delete)。Value部分沒(méi)有這么復(fù)雜的結(jié)構(gòu),就是純粹的二進(jìn)制數(shù)據(jù)了。

HFile分為六個(gè)部分:

Data Block 段–保存表中的數(shù)據(jù),這部分可以被壓縮.

Meta Block 段 (可選的)–保存用戶(hù)自定義的kv對(duì),可以被壓縮。

File Info 段–Hfile的元信息,不被壓縮,用戶(hù)也可以在這一部分添加自己的元信息。

Data Block Index 段–Data Block的索引。每條索引的key是被索引的block的第一條記錄的key。

Meta Block Index段 (可選的)–Meta Block的索引。

Trailer–這一段是定長(zhǎng)的。保存了每一段的偏移量,讀取一個(gè)HFile時(shí),會(huì)首先讀取Trailer,Trailer保存了每個(gè)段的起始位置(段的Magic Number用來(lái)做安全check),然后,DataBlock Index會(huì)被讀取到內(nèi)存中,這樣,當(dāng)檢索某個(gè)key時(shí),不需要掃描整個(gè)HFile,而只需從內(nèi)存中找到key所在的block,通過(guò)一次磁盤(pán)io將整個(gè) block讀取到內(nèi)存中,再找到需要的key。DataBlock Index采用LRU機(jī)制淘汰。

HFile的Data Block,Meta Block通常采用壓縮方式存儲(chǔ),壓縮之后可以大大減少網(wǎng)絡(luò)IO和磁盤(pán)IO,隨之而來(lái)的開(kāi)銷(xiāo)當(dāng)然是需要花費(fèi)cpu進(jìn)行壓縮和解壓縮。目前HFile的壓縮支持兩種方式:Gzip,Lzo。

3) Memstore與StoreFile

一個(gè) HRegion 由多個(gè) Store 組成,每個(gè) Store 包含一個(gè)列族的所有數(shù)據(jù)Store 包括位于內(nèi)存的 Memstore 和位于硬盤(pán)的 StoreFile。

寫(xiě)操作先寫(xiě)入 Memstore,當(dāng) Memstore 中的數(shù)據(jù)量達(dá)到某個(gè)閾值,HRegionServer 啟動(dòng) FlashCache 進(jìn)程寫(xiě)入 StoreFile,每次寫(xiě)入形成單獨(dú)一個(gè) StoreFile

當(dāng) StoreFile 大小超過(guò)一定閾值后,會(huì)把當(dāng)前的 HRegion 分割成兩個(gè),并由 HMaster 分配給相應(yīng)的 HRegion 服務(wù)器,實(shí)現(xiàn)負(fù)載均衡

客戶(hù)端檢索數(shù)據(jù)時(shí),先在memstore找,找不到再找storefile。

4) HLog(WAL log)

WAL 意為Write ahead log,類(lèi)似 mysql 中的 binlog,用來(lái) 做災(zāi)難恢復(fù)時(shí)用,Hlog記錄數(shù)據(jù)的所有變更,一旦數(shù)據(jù)修改,就可以從log中進(jìn)行恢復(fù)。

每個(gè)Region Server維護(hù)一個(gè)Hlog,而不是每個(gè)Region一個(gè)。這樣不同region(來(lái)自不同table)的日志會(huì)混在一起,這樣做的目的是不斷追加單個(gè)文件相對(duì)于同時(shí)寫(xiě)多個(gè)文件而言,可以減少磁盤(pán)尋址次數(shù),因此可以提高對(duì)table的寫(xiě)性能。帶來(lái)的麻煩是,如果一臺(tái)region server下線(xiàn),為了恢復(fù)其上的region,需要將region server上的log進(jìn)行拆分,然后分發(fā)到其它region server上進(jìn)行恢復(fù)。

HLog文件就是一個(gè)普通的Hadoop Sequence File:

HLog Sequence File 的Key是HLogKey對(duì)象,HLogKey中記錄了寫(xiě)入數(shù)據(jù)的歸屬信息,除了table和region名字外,同時(shí)還包括 sequence number和timestamp,timestamp是”寫(xiě)入時(shí)間”,sequence number的起始值為0,或者是最近一次存入文件系統(tǒng)中sequence number。HLog Sequece File的Value是HBase的KeyValue對(duì)象,即對(duì)應(yīng)HFile中的KeyValue,可參見(jiàn)上文描述。4. 讀寫(xiě)過(guò)程

1) 讀請(qǐng)求過(guò)程:

HRegionServer保存著meta表以及表數(shù)據(jù),要訪(fǎng)問(wèn)表數(shù)據(jù),首先Client先去訪(fǎng)問(wèn)zookeeper,從zookeeper里面獲取meta表所在的位置信息,即找到這個(gè)meta表在哪個(gè)HRegionServer上保存著。

接著Client通過(guò)剛才獲取到的HRegionServer的IP來(lái)訪(fǎng)問(wèn)Meta表所在的HRegionServer,從而讀取到Meta,進(jìn)而獲取到Meta表中存放的元數(shù)據(jù)。

Client通過(guò)元數(shù)據(jù)中存儲(chǔ)的信息,訪(fǎng)問(wèn)對(duì)應(yīng)的HRegionServer,然后掃描所在HRegionServer的Memstore和Storefile來(lái)查詢(xún)數(shù)據(jù)。

最后HRegionServer把查詢(xún)到的數(shù)據(jù)響應(yīng)給Client。

查看meta表信息

hbase(main):011:0> scan 'hbase:meta'

2) 寫(xiě)請(qǐng)求過(guò)程:

Client也是先訪(fǎng)問(wèn)zookeeper,找到Meta表,并獲取Meta表元數(shù)據(jù)。

確定當(dāng)前將要寫(xiě)入的數(shù)據(jù)所對(duì)應(yīng)的HRegion和HRegionServer服務(wù)器。

Client向該HRegionServer服務(wù)器發(fā)起寫(xiě)入數(shù)據(jù)請(qǐng)求,然后HRegionServer收到請(qǐng)求并響應(yīng)。

Client先把數(shù)據(jù)寫(xiě)入到HLog,以防止數(shù)據(jù)丟失。

然后將數(shù)據(jù)寫(xiě)入到Memstore。

如果HLog和Memstore均寫(xiě)入成功,則這條數(shù)據(jù)寫(xiě)入成功

如果Memstore達(dá)到閾值,會(huì)把Memstore中的數(shù)據(jù)flush到Storefile中。

當(dāng)Storefile越來(lái)越多,會(huì)觸發(fā)Compact合并操作,把過(guò)多的Storefile合并成一個(gè)大的Storefile。

當(dāng)Storefile越來(lái)越大,Region也會(huì)越來(lái)越大,達(dá)到閾值后,會(huì)觸發(fā)Split操作,將Region一分為二。

細(xì)節(jié)描述:

HBase使用MemStore和StoreFile存儲(chǔ)對(duì)表的更新。數(shù)據(jù)在更新時(shí)首先寫(xiě)入Log(WAL log)和內(nèi)存(MemStore)中,MemStore中的數(shù)據(jù)是排序的,當(dāng)MemStore累計(jì)到一定閾值時(shí),就會(huì)創(chuàng)建一個(gè)新的MemStore,并且將老的MemStore添加到flush隊(duì)列,由單獨(dú)的線(xiàn)程flush到磁盤(pán)上,成為一個(gè)StoreFile。于此同時(shí),系統(tǒng)會(huì)在zookeeper中記錄一個(gè)redo point,表示這個(gè)時(shí)刻之前的變更已經(jīng)持久化了。當(dāng)系統(tǒng)出現(xiàn)意外時(shí),可能導(dǎo)致內(nèi)存(MemStore)中的數(shù)據(jù)丟失,此時(shí)使用Log(WAL log)來(lái)恢復(fù)checkpoint之后的數(shù)據(jù)。

StoreFile是只讀的,一旦創(chuàng)建后就不可以再修改。因此HBase的更新其實(shí)是不斷追加的操作。當(dāng)一個(gè)Store中的StoreFile達(dá)到一定的閾值后,就會(huì)進(jìn)行一次合并(minor_compact, major_compact),將對(duì)同一個(gè)key的修改合并到一起,形成一個(gè)大的StoreFile,當(dāng)StoreFile的大小達(dá)到一定閾值后,又會(huì)對(duì) StoreFile進(jìn)行split,等分為兩個(gè)StoreFile。

由于對(duì)表的更新是不斷追加的,compact時(shí),需要訪(fǎng)問(wèn)Store中全部的 StoreFile和MemStore,將他們按row key進(jìn)行合并,由于StoreFile和MemStore都是經(jīng)過(guò)排序的,并且StoreFile帶有內(nèi)存中索引,合并的過(guò)程還是比較快。

5. HRegion管理1) HRegion分配

任何時(shí)刻,一個(gè)HRegion只能分配給一個(gè)HRegion Server。HMaster記錄了當(dāng)前有哪些可用的HRegion Server。以及當(dāng)前哪些HRegion分配給了哪些HRegion Server,哪些HRegion還沒(méi)有分配。當(dāng)需要分配的新的HRegion,并且有一個(gè)HRegion Server上有可用空間時(shí),HMaster就給這個(gè)HRegion Server發(fā)送一個(gè)裝載請(qǐng)求,把HRegion分配給這個(gè)HRegion Server。HRegion Server得到請(qǐng)求后,就開(kāi)始對(duì)此HRegion提供服務(wù)。

2) HRegion Server上線(xiàn)

HMaster使用zookeeper來(lái)跟蹤HRegion Server狀態(tài)。當(dāng)某個(gè)HRegion Server啟動(dòng)時(shí),會(huì)首先在zookeeper上的server目錄下建立代表自己的znode。由于HMaster訂閱了server目錄上的變更消息,當(dāng)server目錄下的文件出現(xiàn)新增或刪除操作時(shí),HMaster可以得到來(lái)自zookeeper的實(shí)時(shí)通知。因此一旦HRegion Server上線(xiàn),HMaster能馬上得到消息。

3) HRegion Server下線(xiàn)

當(dāng)HRegion Server下線(xiàn)時(shí),它和zookeeper的會(huì)話(huà)斷開(kāi),zookeeper而自動(dòng)釋放代表這臺(tái)server的文件上的獨(dú)占鎖。HMaster就可以確定:

HRegion Server和zookeeper之間的網(wǎng)絡(luò)斷開(kāi)了。HRegion Server掛了。

無(wú)論哪種情況,HRegion Server都無(wú)法繼續(xù)為它的HRegion提供服務(wù)了,此時(shí)HMaster會(huì)刪除server目錄下代表這臺(tái)HRegion Server的znode數(shù)據(jù),并將這臺(tái)HRegion Server的HRegion分配給其它還活著的節(jié)點(diǎn)。

6. HMaster工作機(jī)制1) master上線(xiàn)

master啟動(dòng)進(jìn)行以下步驟:

從zookeeper上獲取唯一一個(gè)代表active master的鎖,用來(lái)阻止其它HMaster成為master。掃描zookeeper上的server父節(jié)點(diǎn),獲得當(dāng)前可用的HRegion Server列表。和每個(gè)HRegion Server通信,獲得當(dāng)前已分配的HRegion和HRegion Server的對(duì)應(yīng)關(guān)系。掃描.META.region的集合,計(jì)算得到當(dāng)前還未分配的HRegion,將他們放入待分配HRegion列表。2) master下線(xiàn)

由于HMaster只維護(hù)表和region的元數(shù)據(jù),而不參與表數(shù)據(jù)IO的過(guò)程,HMaster下線(xiàn)僅導(dǎo)致所有元數(shù)據(jù)的修改被凍結(jié)(無(wú)法創(chuàng)建刪除表,無(wú)法修改表的schema,無(wú)法進(jìn)行HRegion的負(fù)載均衡,無(wú)法處理HRegion 上下線(xiàn),無(wú)法進(jìn)行HRegion的合并,唯一例外的是HRegion的split可以正常進(jìn)行,因?yàn)橹挥蠬Region Server參與),表的數(shù)據(jù)讀寫(xiě)還可以正常進(jìn)行。因此HMaster下線(xiàn)短時(shí)間內(nèi)對(duì)整個(gè)HBase集群沒(méi)有影響。

從上線(xiàn)過(guò)程可以看到,HMaster保存的信息全是可以冗余信息(都可以從系統(tǒng)其它地方收集到或者計(jì)算出來(lái))

因此,一般HBase集群中總是有一個(gè)HMaster在提供服務(wù),還有一個(gè)以上的‘HMaster’在等待時(shí)機(jī)搶占它的位置。

7. HBase三個(gè)重要機(jī)制1) flush機(jī)制

1.(hbase.regionserver.global.memstore.size)默認(rèn);堆大小的40%regionServer的全局memstore的大小,超過(guò)該大小會(huì)觸發(fā)flush到磁盤(pán)的操作,默認(rèn)是堆大小的40%,而且regionserver級(jí)別的flush會(huì)阻塞客戶(hù)端讀寫(xiě)

2.(hbase.hregion.memstore.flush.size)默認(rèn):128M單個(gè)region里memstore的緩存大小,超過(guò)那么整個(gè)HRegion就會(huì)flush,

3.(hbase.regionserver.optionalcacheflushinterval)默認(rèn):1h內(nèi)存中的文件在自動(dòng)刷新之前能夠存活的最長(zhǎng)時(shí)間

4.(hbase.regionserver.global.memstore.size.lower.limit)默認(rèn):堆大小 * 0.4 * 0.95有時(shí)候集群的“寫(xiě)負(fù)載”非常高,寫(xiě)入量一直超過(guò)flush的量,這時(shí),我們就希望memstore不要超過(guò)一定的安全設(shè)置。在這種情況下,寫(xiě)操作就要被阻塞一直到memstore恢復(fù)到一個(gè)“可管理”的大小, 這個(gè)大小就是默認(rèn)值是堆大小 * 0.4 * 0.95,也就是當(dāng)regionserver級(jí)別的flush操作發(fā)送后,會(huì)阻塞客戶(hù)端寫(xiě),一直阻塞到整個(gè)regionserver級(jí)別的memstore的大小為 堆大小 * 0.4 *0.95為止

5.(hbase.hregion.preclose.flush.size)默認(rèn)為:5M當(dāng)一個(gè) region 中的 memstore 的大小大于這個(gè)值的時(shí)候,我們又觸發(fā)了region的 close時(shí),會(huì)先運(yùn)行“pre-flush”操作,清理這個(gè)需要關(guān)閉的memstore,然后 將這個(gè) region 下線(xiàn)。當(dāng)一個(gè) region 下線(xiàn)了,我們無(wú)法再進(jìn)行任何寫(xiě)操作。如果一個(gè) memstore 很大的時(shí)候,flush  操作會(huì)消耗很多時(shí)間。"pre-flush" 操作意味著在 region 下線(xiàn)之前,會(huì)先把 memstore 清空。這樣在最終執(zhí)行 close 操作的時(shí)候,flush 操作會(huì)很快。

6.(hbase.hstore.compactionThreshold)默認(rèn):超過(guò)3個(gè)一個(gè)store里面允許存的hfile的個(gè)數(shù),超過(guò)這個(gè)個(gè)數(shù)會(huì)被寫(xiě)到新的一個(gè)hfile里面 也即是每個(gè)region的每個(gè)列族對(duì)應(yīng)的memstore在flush為hfile的時(shí)候,默認(rèn)情況下當(dāng)超過(guò)3個(gè)hfile的時(shí)候就會(huì)對(duì)這些文件進(jìn)行合并重寫(xiě)為一個(gè)新文件,設(shè)置個(gè)數(shù)越大可以減少觸發(fā)合并的時(shí)間,但是每次合并的時(shí)間就會(huì)越長(zhǎng)

2) compact機(jī)制

把小的storeFile文件合并成大的HFile文件。清理過(guò)期的數(shù)據(jù),包括刪除的數(shù)據(jù)將數(shù)據(jù)的版本號(hào)保存為1個(gè)。

3) split機(jī)制

當(dāng)HRegion達(dá)到閾值,會(huì)把過(guò)大的HRegion一分為二。默認(rèn)一個(gè)HFile達(dá)到10Gb的時(shí)候就會(huì)進(jìn)行切分。

七、HBase 與 MapReduce 的集成

HBase 當(dāng)中的數(shù)據(jù)最終都是存儲(chǔ)在 HDFS 上面的,HBase 天生的支持 MR 的操作,我們可以通過(guò) MR 直接處理 HBase 當(dāng)中的數(shù)據(jù),并且 MR 可以將處理后的結(jié)果直接存儲(chǔ)到 HBase 當(dāng)中去。

需求:讀取 HBase 當(dāng)中一張表的數(shù)據(jù),然后將數(shù)據(jù)寫(xiě)入到 HBase 當(dāng)中的另外一張表當(dāng)中去。

注意:我們可以使用 TableMapper 與 TableReducer 來(lái)實(shí)現(xiàn)從 HBase 當(dāng)中讀取與寫(xiě)入數(shù)據(jù)。

這里我們將 myuser 這張表當(dāng)中 f1 列族的 name 和 age 字段寫(xiě)入到 myuser2 這張表的 f1 列族當(dāng)中去。

需求一:讀取 myuser 這張表當(dāng)中的數(shù)據(jù)寫(xiě)入到 HBase 的另外一張表當(dāng)中去:

第一步:創(chuàng)建 myuser2 這張表

注意:列族的名字要與 myuser 表的列族名字相同

hbase(main):010:0> create 'myuser2','f1'

第二步:開(kāi)發(fā) MR 的程序

圖片標(biāo)題

圖片標(biāo)題

圖片標(biāo)題

圖片標(biāo)題

第三步:打包運(yùn)行

將我們打好的 jar 包放到服務(wù)器上執(zhí)行:

yarn jar hbaseStudy-1.0-SNAPSHOT.jar  cn.yuan_more.hbasemr.HBaseMR

需求二:讀取 HDFS 文件,寫(xiě)入到 HBase 表當(dāng)中去

第一步:準(zhǔn)備數(shù)據(jù)文件

準(zhǔn)備數(shù)據(jù)文件,并將數(shù)據(jù)文件上傳到 HDFS 上面去。

第二步:開(kāi)發(fā) MR 程序

圖片標(biāo)題

     

圖片標(biāo)題

需求四:通過(guò) bulkload 的方式批量加載數(shù)據(jù)到 HBase 當(dāng)中去

加載數(shù)據(jù)到 HBase 當(dāng)中去的方式多種多樣,我們可以使用 HBase 的 javaAPI 或者使用 sqoop 將我們的數(shù)據(jù)寫(xiě)入或者導(dǎo)入到 HBase 當(dāng)中去,但是這些方式不是慢就是在導(dǎo)入的過(guò)程的占用 Region 資料導(dǎo)致效率低下,我們也可以通過(guò) MR 的程序,將我們的數(shù)據(jù)直接轉(zhuǎn)換成 HBase 的最終存儲(chǔ)格式 HFile,然后直接 load 數(shù)據(jù)到 HBase 當(dāng)中去即可。

HBase 中每張 Table 在根目錄(/HBase)下用一個(gè)文件夾存儲(chǔ),Table 名為文件夾名,在 Table 文件夾下每個(gè) Region 同樣用一個(gè)文件夾存儲(chǔ),每個(gè) Region 文件夾下的每個(gè)列族也用文件夾存儲(chǔ),而每個(gè)列族下存儲(chǔ)的就是一些 HFile 文件,HFile 就是 HBase 數(shù)據(jù)在 HFDS 下存儲(chǔ)格式,所以 HBase 存儲(chǔ)文件最終在 hdfs 上面的表現(xiàn)形式就是 HFile,如果我們可以直接將數(shù)據(jù)轉(zhuǎn)換為 HFile 的格式,那么我們的 HBase 就可以直接讀取加載 HFile 格式的文件,就可以直接讀取了。

優(yōu)點(diǎn):

導(dǎo)入過(guò)程不占用 Region 資源

能快速導(dǎo)入海量的數(shù)據(jù)

節(jié)省內(nèi)存

第一步:定義 mapper 類(lèi)

圖片標(biāo)題

圖片標(biāo)題

第三步:將代碼打成 jar 包然后運(yùn)行

yarn jar original-h(huán)baseStudy-1.0-SNAPSHOT.jar  cn.yuan_more.hbasemr.HBaseLoad

第四步:開(kāi)發(fā)代碼,加載數(shù)據(jù)

將輸出路徑下面的 HFile 文件,加載到 hbase 表當(dāng)中去

public class LoadData {
   public static void main(String[] args) throws Exception {
       Configuration configuration = HBaseConfiguration.create();
       configuration.set("hbase.zookeeper.property.clientPort", "2181");
       configuration.set("hbase.zookeeper.quorum", "node01,node02,node03");
       Connection connection =  ConnectionFactory.createConnection(configuration);
       Admin admin = connection.getAdmin();
       Table table = connection.getTable(TableName.valueOf("myuser2"));
       LoadIncrementalHFiles load = new LoadIncrementalHFiles(configuration);
       load.doBulkLoad(new Path("hdfs://node01:8020/hbase/output_h(yuǎn)file"), admin,table,connection.getRegionLocator(TableName.valueOf("myuser2")));
   }

或者我們也可以通過(guò)命令行來(lái)進(jìn)行加載數(shù)據(jù)。

先將 hbase 的 jar 包添加到 hadoop 的 classpath 路徑下

export HADOOP_CLASSPATH=`${HBASE_HOME}/bin/hbase mapredcp`

然后執(zhí)行以下命令,將 hbase 的 HFile 直接導(dǎo)入到表 myuser2 當(dāng)中來(lái)

yarn jar /servers/hbase/lib/hbase-server-1.2.0.jar completebulkload /hbase/output_h(yuǎn)file myuser2
八、HBase 的預(yù)分區(qū)1. 為何要預(yù)分區(qū)?增加數(shù)據(jù)讀寫(xiě)效率負(fù)載均衡,防止數(shù)據(jù)傾斜方便集群容災(zāi)調(diào)度 region優(yōu)化 Map 數(shù)量2. 如何預(yù)分區(qū)?

每一個(gè) region 維護(hù)著 startRow 與 endRowKey,如果加入的數(shù)據(jù)符合某個(gè) region 維護(hù)的 rowKey 范圍,則該數(shù)據(jù)交給這個(gè) region 維護(hù)。

3. 如何設(shè)定預(yù)分區(qū)?1) 手動(dòng)指定預(yù)分區(qū)hbase(main):001:0> create 'staff','info','partition1',SPLITS => ['1000','2000','3000','4000']

完成后如圖:

2) 使用 16 進(jìn)制算法生成預(yù)分區(qū)hbase(main):003:0> create 'staff2','info','partition2',{NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}

完成后如圖:

3) 分區(qū)規(guī)則創(chuàng)建于文件中

創(chuàng)建 splits.txt 文件內(nèi)容如下:

vim splits.txt

aaaa

bbbb

cccc

dddd

然后執(zhí)行:

然后執(zhí)行:
hbase(main):004:0> create 'staff3','partition2',SPLITS_FILE => '/export/servers/splits.txt'

完成后如圖:

4) 使用 JavaAPI 創(chuàng)建預(yù)分區(qū)

代碼如下:

@Test
   public void hbaseSplit() throws IOException {
       //獲取連接
       Configuration configuration = HBaseConfiguration.create();
       configuration.set("hbase.zookeeper.quorum", "node01:2181,node02:2181,node03:2181");
       Connection connection = ConnectionFactory.createConnection(configuration);
       Admin admin = connection.getAdmin();
       //自定義算法,產(chǎn)生一系列Hash散列值存儲(chǔ)在二維數(shù)組中
       byte[][] splitKeys = {{1,2,3,4,5},{'a','b','c','d','e'}};
       //通過(guò)HTableDescriptor來(lái)實(shí)現(xiàn)我們表的參數(shù)設(shè)置,包括表名,列族等等
       HTableDescriptor hTableDescriptor = new HTableDescriptor(TableName.valueOf("stuff4"));
       //添加列族
       hTableDescriptor.a(chǎn)ddFamily(new HColumnDescriptor("f1"));
       //添加列族
       hTableDescriptor.a(chǎn)ddFamily(new HColumnDescriptor("f2"));
       admin.createTable(hTableDescriptor,splitKeys);
       admin.close();
   }
九、HBase 的 rowKey 設(shè)計(jì)技巧

HBase 是三維有序存儲(chǔ)的,通過(guò) rowkey(行鍵),column key(column family 和 qualifier)和 TimeStamp(時(shí)間戳)這個(gè)三個(gè)維度可以對(duì) HBase 中的數(shù)據(jù)進(jìn)行快速定位。

HBase 中 rowkey 可以唯一標(biāo)識(shí)一行記錄,在 HBase 查詢(xún)的時(shí)候,有以下幾種方式:

通過(guò) get 方式,指定 rowkey 獲取唯一一條記錄;通過(guò) scan 方式,設(shè)置 startRow 和 stopRow 參數(shù)進(jìn)行范圍匹配;全表掃描,即直接掃描整張表中所有行記錄。1. rowkey 長(zhǎng)度原則

rowkey 是一個(gè)二進(jìn)制碼流,可以是任意字符串,最大長(zhǎng)度 64kb,實(shí)際應(yīng)用中一般為 10-100bytes,以 byte[]形式保存,一般設(shè)計(jì)成定長(zhǎng)。

建議越短越好,不要超過(guò) 16 個(gè)字節(jié),原因如下:

數(shù)據(jù)的持久化文件 HFile 中是按照 KeyValue 存儲(chǔ)的,如果 rowkey 過(guò)長(zhǎng),比如超過(guò) 100 字節(jié),1000w 行數(shù)據(jù),光 rowkey 就要占用 100*1000w=10 億個(gè)字節(jié),將近 1G 數(shù)據(jù),這樣會(huì)極大影響 HFile 的存儲(chǔ)效率;

MemStore 將緩存部分?jǐn)?shù)據(jù)到內(nèi)存,如果 rowkey 字段過(guò)長(zhǎng),內(nèi)存的有效利用率就會(huì)降低,系統(tǒng)不能緩存更多的數(shù)據(jù),這樣會(huì)降低檢索效率。

2. rowkey 散列原則

如果 rowkey 按照時(shí)間戳的方式遞增,不要將時(shí)間放在二進(jìn)制碼的前面,建議將 rowkey 的高位作為散列字段,由程序隨機(jī)生成,低位放時(shí)間字段,這樣將提高數(shù)據(jù)均衡分布在每個(gè) RegionServer,以實(shí)現(xiàn)負(fù)載均衡的幾率。

如果沒(méi)有散列字段,首字段直接是時(shí)間信息,所有的數(shù)據(jù)都會(huì)集中在一個(gè) RegionServer 上,這樣在數(shù)據(jù)檢索的時(shí)候負(fù)載會(huì)集中在個(gè)別的 RegionServer 上,造成熱點(diǎn)問(wèn)題,會(huì)降低查詢(xún)效率。

3. rowkey 唯一原則

必須在設(shè)計(jì)上保證其唯一性,rowkey 是按照字典順序排序存儲(chǔ)的,因此,設(shè)計(jì) rowkey 的時(shí)候,要充分利用這個(gè)排序的特點(diǎn),將經(jīng)常讀取的數(shù)據(jù)存儲(chǔ)到一塊,將最近可能會(huì)被訪(fǎng)問(wèn)的數(shù)據(jù)放到一塊。

4. 什么是熱點(diǎn)

HBase 中的行是按照 rowkey 的字典順序排序的,這種設(shè)計(jì)優(yōu)化了 scan 操作,可以將相關(guān)的行以及會(huì)被一起讀取的行存取在臨近位置,便于 scan。然而糟糕的 rowkey 設(shè)計(jì)是熱點(diǎn)的源頭。

熱點(diǎn)發(fā)生在大量的 client 直接訪(fǎng)問(wèn)集群的一個(gè)或極少數(shù)個(gè)節(jié)點(diǎn)(訪(fǎng)問(wèn)可能是讀,寫(xiě)或者其他操作)。大量訪(fǎng)問(wèn)會(huì)使熱點(diǎn) region 所在的單個(gè)機(jī)器超出自身承受能力,引起性能下降甚至 region 不可用,這也會(huì)影響同一個(gè) RegionServer 上的其他 region,由于主機(jī)無(wú)法服務(wù)其他 region 的請(qǐng)求。

設(shè)計(jì)良好的數(shù)據(jù)訪(fǎng)問(wèn)模式以使集群被充分,均衡的利用。為了避免寫(xiě)熱點(diǎn),設(shè)計(jì) rowkey 使得不同行在同一個(gè) region,但是在更多數(shù)據(jù)情況下,數(shù)據(jù)應(yīng)該被寫(xiě)入集群的多個(gè) region,而不是一個(gè)。

下面是一些常見(jiàn)的避免熱點(diǎn)的方法以及它們的優(yōu)缺點(diǎn):

1) 加鹽

這里所說(shuō)的加鹽不是密碼學(xué)中的加鹽,而是在 rowkey 的前面增加隨機(jī)數(shù),具體就是給 rowkey 分配一個(gè)隨機(jī)前綴以使得它和之前的 rowkey 的開(kāi)頭不同。分配的前綴種類(lèi)數(shù)量應(yīng)該和你想使用數(shù)據(jù)分散到不同的 region 的數(shù)量一致。加鹽之后的 rowkey 就會(huì)根據(jù)隨機(jī)生成的前綴分散到各個(gè) region 上,以避免熱點(diǎn)。

2) 哈希

哈希會(huì)使同一行永遠(yuǎn)用一個(gè)前綴加鹽。哈希也可以使負(fù)載分散到整個(gè)集群,但是讀卻是可以預(yù)測(cè)的。使用確定的哈?梢宰尶蛻(hù)端重構(gòu)完整的 rowkey,可以使用 get 操作準(zhǔn)確獲取某一個(gè)行數(shù)據(jù)。

3) 反轉(zhuǎn)

第三種防止熱點(diǎn)的方法時(shí)反轉(zhuǎn)固定長(zhǎng)度或者數(shù)字格式的 rowkey。這樣可以使得 rowkey 中經(jīng)常改變的部分(最沒(méi)有意義的部分)放在前面。這樣可以有效的隨機(jī) rowkey,但是犧牲了 rowkey 的有序性。

反轉(zhuǎn) rowkey 的例子以手機(jī)號(hào)為 rowkey,可以將手機(jī)號(hào)反轉(zhuǎn)后的字符串作為 rowkey,這樣的就避免了以手機(jī)號(hào)那樣比較固定開(kāi)頭導(dǎo)致熱點(diǎn)問(wèn)題。

3) 時(shí)間戳反轉(zhuǎn)

一個(gè)常見(jiàn)的數(shù)據(jù)處理問(wèn)題是快速獲取數(shù)據(jù)的最近版本,使用反轉(zhuǎn)的時(shí)間戳作為 rowkey 的一部分對(duì)這個(gè)問(wèn)題十分有用,可以用  Long.Max_Value - timestamp  追加到 key 的末尾,例如  [key][reverse_timestamp] , [key]  的最新值可以通過(guò) scan [key]獲得[key]的第一條記錄,因?yàn)?HBase 中 rowkey 是有序的,第一條記錄是最后錄入的數(shù)據(jù)。

其他一些建議:

盡量減少行鍵和列族的大小在 HBase 中,value 永遠(yuǎn)和它的 key 一起傳輸?shù)。?dāng)具體的值在系統(tǒng)間傳輸時(shí),它的 rowkey,列名,時(shí)間戳也會(huì)一起傳輸。如果你的 rowkey 和列名很大,這個(gè)時(shí)候它們將會(huì)占用大量的存儲(chǔ)空間。

列族盡可能越短越好,最好是一個(gè)字符。

冗長(zhǎng)的屬性名雖然可讀性好,但是更短的屬性名存儲(chǔ)在 HBase 中會(huì)更好。

十、HBase 的協(xié)處理器

http://hbase.a(chǎn)pache.org/book.html#cp

1. 起源

Hbase 作為列族數(shù)據(jù)庫(kù)最經(jīng)常被人詬病的特性包括:無(wú)法輕易建立“二級(jí)索引”,難以執(zhí)行求和、計(jì)數(shù)、排序等操作。

比如,在舊版本的(<0.92)Hbase 中,統(tǒng)計(jì)數(shù)據(jù)表的總行數(shù),需要使用 Counter 方法,執(zhí)行一次 MapReduce Job 才能得到。

雖然 HBase 在數(shù)據(jù)存儲(chǔ)層中集成了 MapReduce,能夠有效用于數(shù)據(jù)表的分布式計(jì)算。然而在很多情況下,做一些簡(jiǎn)單的相加或者聚合計(jì)算的時(shí)候, 如果直接將計(jì)算過(guò)程放置在 server 端,能夠減少通訊開(kāi)銷(xiāo),從而獲得很好的性能提升。于是, HBase 在 0.92 之后引入了協(xié)處理器(coprocessors),實(shí)現(xiàn)一些激動(dòng)人心的新特性:能夠輕易建立二次索引、復(fù)雜過(guò)濾器(謂詞下推)以及訪(fǎng)問(wèn)控制等。

2. 協(xié)處理器有兩種:observer 和 endpoint1) observer 協(xié)處理器

Observer 類(lèi)似于傳統(tǒng)數(shù)據(jù)庫(kù)中的觸發(fā)器,當(dāng)發(fā)生某些事件的時(shí)候這類(lèi)協(xié)處理器會(huì)被 Server 端調(diào)用。

Observer Coprocessor 就是一些散布在 HBase Server 端代碼中的 hook 鉤子,在固定的事件發(fā)生時(shí)被調(diào)用。

比如:put 操作之前有鉤子函數(shù) prePut,該函數(shù)在 put 操作執(zhí)行前會(huì)被 Region Server 調(diào)用;在 put 操作之后則有 postPut 鉤子函數(shù)。

以 HBase0.92 版本為例,它提供了三種觀(guān)察者接口:

RegionObserver:提供客戶(hù)端的數(shù)據(jù)操縱事件鉤子:Get、 Put、 Delete、 Scan 等。WALObserver:提供 WAL 相關(guān)操作鉤子。MasterObserver:提供 DDL-類(lèi)型的操作鉤子。如創(chuàng)建、刪除、修改數(shù)據(jù)表等。

到 0.96 版本又新增一個(gè) RegionServerObserver

下圖是以 RegionObserver 為例子講解 Observer 這種協(xié)處理器的原理:

2) endpoint 協(xié)處理器

Endpoint 協(xié)處理器類(lèi)似傳統(tǒng)數(shù)據(jù)庫(kù)中的存儲(chǔ)過(guò)程,客戶(hù)端可以調(diào)用這些 Endpoint 協(xié)處理器執(zhí)行一段 Server 端代碼,并將 Server 端代碼的結(jié)果返回給客戶(hù)端進(jìn)一步處理,最常見(jiàn)的用法就是進(jìn)行聚集操作。

如果沒(méi)有協(xié)處理器,當(dāng)用戶(hù)需要找出一張表中的最大數(shù)據(jù),即 max 聚合操作,就必須進(jìn)行全表掃描,在客戶(hù)端代碼內(nèi)遍歷掃描結(jié)果,并執(zhí)行求最大值的操作。這樣的方法無(wú)法利用底層集群的并發(fā)能力,而將所有計(jì)算都集中到 Client 端統(tǒng)一執(zhí)行,勢(shì)必效率低下。

利用 Coprocessor,用戶(hù)可以將求最大值的代碼部署到 HBase Server 端,HBase 將利用底層 cluster 的多個(gè)節(jié)點(diǎn)并發(fā)執(zhí)行求最大值的操作。即在每個(gè) Region 范圍內(nèi) 執(zhí)行求最大值的代碼,將每個(gè) Region 的最大值在 Region Server 端計(jì)算出,僅僅將該 max 值返回給客戶(hù)端。在客戶(hù)端進(jìn)一步將多個(gè) Region 的最大值進(jìn)一步處理而找到其中的最大值。這樣整體的執(zhí)行效率就會(huì)提高很多。

下圖是 EndPoint 的工作原理:

3. 協(xié)處理器加載方式

協(xié)處理器的加載方式有兩種,我們稱(chēng)之為靜態(tài)加載方式( Static Load)和動(dòng)態(tài)加載方式( Dynamic Load)。

靜態(tài)加載的協(xié)處理器稱(chēng)之為 System Coprocessor

動(dòng)態(tài)加載的協(xié)處理器稱(chēng)之為 Table Coprocessor。

1) 靜態(tài)加載

通過(guò)修改 hbase-site.xml 這個(gè)文件來(lái)實(shí)現(xiàn), 啟動(dòng)全局 aggregation,能過(guò)操縱所有的表上的數(shù)據(jù)。只需要添加如下代碼:

<property>

<name>hbase.coprocessor.user.region.classes</name>

<value>org.a(chǎn)pache.hadoop.hbase.coprocessor.AggregateImplementation</value>

</property>

2) 動(dòng)態(tài)加載

啟用表 aggregation,只對(duì)特定的表生效。通過(guò) HBase Shell 來(lái)實(shí)現(xiàn)。

disable 指定表

hbase> disable 'mytable'

添加 aggregation

hbase> alter 'mytable', METHOD => 'table_att','coprocessor'=>
'|org.a(chǎn)pache.Hadoop.hbase.coprocessor.AggregateImplementation||'

重啟指定表

hbase> enable 'mytable'

協(xié)處理器卸載

disable 'mytable'

alter 'mytable', METHOD => 'table_att_unset',NAME=>'coprocessor$1'

enable 'test'

十一、HBase當(dāng)中的二級(jí)索引的簡(jiǎn)要介紹

由于HBase的查詢(xún)比較弱,如果需要實(shí)現(xiàn)類(lèi)似于 select name,salary,count(1),max(salary) from user group by name,salary order by salary 等這樣的復(fù)雜性的統(tǒng)計(jì)需求,基本上不可能,或者說(shuō)比較困難,所以我們?cè)谑褂肏Base的時(shí)候,一般都會(huì)借助二級(jí)索引的方案來(lái)進(jìn)行實(shí)現(xiàn)。

HBase的一級(jí)索引就是rowkey,我們只能通過(guò)rowkey進(jìn)行檢索。如果我們相對(duì)hbase里面列族的列列進(jìn)行一些組合查詢(xún),就需要采用HBase的二級(jí)索引方案來(lái)進(jìn)行多條件的查詢(xún)。

1. MapReduce方案 2. ITHBASE(Indexed-Transanctional HBase)方案 3. IHBASE(Index HBase)方案 4. Hbase Coprocessor(協(xié)處理器)方案 5. Solr+hbase方案6. CCIndex(complementalclustering index)方案

常見(jiàn)的二級(jí)索引我們一般可以借助各種其他的方式來(lái)實(shí)現(xiàn),例如Phoenix或者solr或者ES等。

十二、HBase 調(diào)優(yōu)1. 通用優(yōu)化

NameNode的元數(shù)據(jù)備份使用SSD。

定時(shí)備份NameNode上的元數(shù)據(jù),每小時(shí)或者每天備份,如果數(shù)據(jù)極其重要,可以5~10分鐘備份一次。備份可以通過(guò)定時(shí)任務(wù)復(fù)制元數(shù)據(jù)目錄即可。

為NameNode指定多個(gè)元數(shù)據(jù)目錄,使用dfs.name.dir或者dfs.namenode.name.dir指定。一個(gè)指定本地磁盤(pán),一個(gè)指定網(wǎng)絡(luò)磁盤(pán)。這樣可以提供元數(shù)據(jù)的冗余和健壯性,以免發(fā)生故障。

設(shè)置dfs.namenode.name.dir.restore為true,允許嘗試恢復(fù)之前失敗的dfs.namenode.name.dir目錄,在創(chuàng)建checkpoint時(shí)做此嘗試,如果設(shè)置了多個(gè)磁盤(pán),建議允許。

NameNode節(jié)點(diǎn)必須配置為RAID1(鏡像盤(pán))結(jié)構(gòu)。

保持NameNode日志目錄有足夠的空間,這些日志有助于幫助你發(fā)現(xiàn)問(wèn)題。

因?yàn)镠adoop是IO密集型框架,所以盡量提升存儲(chǔ)的速度和吞吐量(類(lèi)似位寬)。

2. Linux優(yōu)化開(kāi)啟文件系統(tǒng)的預(yù)讀緩存可以提高讀取速度

$ sudo blockdev --setra 32768 /dev/sda

提示:ra是readahead的縮寫(xiě)

關(guān)閉進(jìn)程睡眠池

$ sudo sysctl -w vm.swappiness=0

調(diào)整ulimit上限,默認(rèn)值為比較小的數(shù)字

$ ulimit -n 查看允許最大進(jìn)程數(shù)

$ ulimit -u 查看允許打開(kāi)最大文件數(shù)

修改:

$ sudo vi /etc/security/limits.conf 修改打開(kāi)文件數(shù)限制

末尾添加:

*                soft    nofile          1024000

*                hard    nofile          1024000

Hive             -       nofile          1024000
hive             -       nproc           1024000

$ sudo vi /etc/security/limits.d/20-nproc.conf 修改用戶(hù)打開(kāi)進(jìn)程數(shù)限制

修改為:

#*          soft    nproc     4096

#root       soft    nproc     unlimited

*          soft    nproc     40960

root       soft    nproc     unlimited

開(kāi)啟集群的時(shí)間同步NTP。

更新系統(tǒng)補(bǔ)。ㄌ崾荆焊卵a(bǔ)丁前,請(qǐng)先測(cè)試新版本補(bǔ)丁對(duì)集群節(jié)點(diǎn)的兼容性)

3. HDFS優(yōu)化(hdfs-site.xml)保證RPC調(diào)用會(huì)有較多的線(xiàn)程數(shù)

屬性:dfs.namenode.handler.count

解釋?zhuān)涸搶傩允荖ameNode服務(wù)默認(rèn)線(xiàn)程數(shù),的默認(rèn)值是10,根據(jù)機(jī)器的可用內(nèi)存可以調(diào)整為50~100

屬性:dfs.datanode.handler.count

解釋?zhuān)涸搶傩阅J(rèn)值為10,是DataNode的處理線(xiàn)程數(shù),如果HDFS客戶(hù)端程序讀寫(xiě)請(qǐng)求比較多,可以調(diào)高到15~20,設(shè)置的值越大,內(nèi)存消耗越多,不要調(diào)整的過(guò)高,一般業(yè)務(wù)中,5~10即可。

副本數(shù)的調(diào)整

屬性:dfs.replication

解釋?zhuān)喝绻麛?shù)據(jù)量巨大,且不是非常之重要,可以調(diào)整為2~3,如果數(shù)據(jù)非常之重要,可以調(diào)整為3~5。

文件塊大小的調(diào)整

屬性:dfs.blocksize

解釋?zhuān)簤K大小定義,該屬性應(yīng)該根據(jù)存儲(chǔ)的大量的單個(gè)文件大小來(lái)設(shè)置,如果大量的單個(gè)文件都小于100M,建議設(shè)置成64M塊大小,對(duì)于大于100M或者達(dá)到GB的這種情況,建議設(shè)置成256M,一般設(shè)置范圍波動(dòng)在64M~256M之間。

4. MapReduce優(yōu)化(mapred-site.xml)Job任務(wù)服務(wù)線(xiàn)程數(shù)調(diào)整

mapreduce.jobtracker.handler.count

該屬性是Job任務(wù)線(xiàn)程數(shù),默認(rèn)值是10,根據(jù)機(jī)器的可用內(nèi)存可以調(diào)整為50~100

Http服務(wù)器工作線(xiàn)程數(shù)

屬性:mapreduce.tasktracker.http.threads

解釋?zhuān)憾xHTTP服務(wù)器工作線(xiàn)程數(shù),默認(rèn)值為40,對(duì)于大集群可以調(diào)整到80~100

文件排序合并優(yōu)化

屬性:mapreduce.task.io.sort.factor

解釋?zhuān)何募判驎r(shí)同時(shí)合并的數(shù)據(jù)流的數(shù)量,這也定義了同時(shí)打開(kāi)文件的個(gè)數(shù),默認(rèn)值為10,如果調(diào)高該參數(shù),可以明顯減少磁盤(pán)IO,即減少文件讀取的次數(shù)。

設(shè)置任務(wù)并發(fā)

屬性:mapreduce.map.speculative

解釋?zhuān)涸搶傩钥梢栽O(shè)置任務(wù)是否可以并發(fā)執(zhí)行,如果任務(wù)多而小,該屬性設(shè)置為true可以明顯加快任務(wù)執(zhí)行效率,但是對(duì)于延遲非常高的任務(wù),建議改為false,這就類(lèi)似于迅雷下載。

MR輸出數(shù)據(jù)的壓縮

屬性:mapreduce.map.output.compress、mapreduce.output.fileoutputformat.compress

解釋?zhuān)簩?duì)于大集群而言,建議設(shè)置Map-Reduce的輸出為壓縮的數(shù)據(jù),而對(duì)于小集群,則不需要。

優(yōu)化Mapper和Reducer的個(gè)數(shù)

屬性:

mapreduce.tasktracker.map.tasks.maximum

mapreduce.tasktracker.reduce.tasks.maximum

解釋?zhuān)阂陨蟽蓚(gè)屬性分別為一個(gè)單獨(dú)的Job任務(wù)可以同時(shí)運(yùn)行的Map和Reduce的數(shù)量。

設(shè)置上面兩個(gè)參數(shù)時(shí),需要考慮CPU核數(shù)、磁盤(pán)和內(nèi)存容量。假設(shè)一個(gè)8核的CPU,業(yè)務(wù)內(nèi)容非常消耗CPU,那么可以設(shè)置map數(shù)量

4,如果該業(yè)務(wù)不是特別消耗CPU類(lèi)型的,那么可以設(shè)置map數(shù)量為40,reduce數(shù)量為20。這些參數(shù)的值修改完成之后,一定要觀(guān)察是否有較長(zhǎng)等待的任務(wù),如果有的話(huà),可以減少數(shù)量以加快任務(wù)執(zhí)行,如果設(shè)置一個(gè)很大的值,會(huì)引起大量的上下文切換,以及內(nèi)存與磁盤(pán)之間的數(shù)據(jù)交換,這里沒(méi)有標(biāo)準(zhǔn)的配置數(shù)值,需要根據(jù)業(yè)務(wù)和硬件配置以及經(jīng)驗(yàn)來(lái)做出選擇。

在同一時(shí)刻,不要同時(shí)運(yùn)行太多的MapReduce,這樣會(huì)消耗過(guò)多的內(nèi)存,任務(wù)會(huì)執(zhí)行的非常緩慢,我們需要根據(jù)CPU核數(shù),內(nèi)存容量設(shè)置一個(gè)MR任務(wù)并發(fā)的最大值,使固定數(shù)據(jù)量的任務(wù)完全加載到內(nèi)存中,避免頻繁的內(nèi)存和磁盤(pán)數(shù)據(jù)交換,從而降低磁盤(pán)IO,提高性能。

大概估算公式:map = 2 + 2/3cpu_core

reduce = 2 + 1/3cpu_core

5. HBase優(yōu)化在HDFS的文件中追加內(nèi)容

HDFS 不是不允許追加內(nèi)容么?沒(méi)錯(cuò),請(qǐng)看背景故事:

屬性:dfs.support.a(chǎn)ppend

文件:hdfs-site.xml、hbase-site.xml

解釋?zhuān)洪_(kāi)啟HDFS追加同步,可以?xún)?yōu)秀的配合HBase的數(shù)據(jù)同步和持久化。默認(rèn)值為true。

優(yōu)化DataNode允許的最大文件打開(kāi)數(shù)

屬性:dfs.datanode.max.transfer.threads

文件:hdfs-site.xml

解釋?zhuān)篐Base一般都會(huì)同一時(shí)間操作大量的文件,根據(jù)集群的數(shù)量和規(guī)模以及數(shù)據(jù)動(dòng)作,設(shè)置為4096或者更高。默認(rèn)值:4096

**優(yōu)化延遲高的數(shù)據(jù)操作的等待時(shí)間

屬性:dfs.image.transfer.timeout

文件:hdfs-site.xml

解釋?zhuān)喝绻麑?duì)于某一次數(shù)據(jù)操作來(lái)講,延遲非常高,socket需要等待更長(zhǎng)的時(shí)間,建議把該值設(shè)置為更大的值(默認(rèn)60000毫秒),以確保socket不會(huì)被timeout掉。

優(yōu)化數(shù)據(jù)的寫(xiě)入效率

屬性:

mapreduce.map.output.compress

mapreduce.map.output.compress.codec

文件:mapred-site.xml

解釋?zhuān)洪_(kāi)啟這兩個(gè)數(shù)據(jù)可以大大提高文件的寫(xiě)入效率,減少寫(xiě)入時(shí)間。第一個(gè)屬性值修改為true,第二個(gè)屬性值修改為:org.a(chǎn)pache.hadoop.io.compress.GzipCodec

優(yōu)化DataNode存儲(chǔ)

屬性:dfs.datanode.failed.volumes.tolerated

文件:hdfs-site.xml

解釋?zhuān)耗J(rèn)為0,意思是當(dāng)DataNode中有一個(gè)磁盤(pán)出現(xiàn)故障,則會(huì)認(rèn)為該DataNode shutdown了。如果修改為1,則一個(gè)磁盤(pán)出現(xiàn)故障時(shí),數(shù)據(jù)會(huì)被復(fù)制到其他正常的DataNode上,當(dāng)前的DataNode繼續(xù)工作。

設(shè)置RPC監(jiān)聽(tīng)數(shù)量

屬性:hbase.regionserver.handler.count

文件:hbase-site.xml

解釋?zhuān)耗J(rèn)值為30,用于指定RPC監(jiān)聽(tīng)的數(shù)量,可以根據(jù)客戶(hù)端的請(qǐng)求數(shù)進(jìn)行調(diào)整,讀寫(xiě)請(qǐng)求較多時(shí),增加此值。

優(yōu)化HStore文件大小

屬性:hbase.hregion.max.filesize

文件:hbase-site.xml

解釋?zhuān)耗J(rèn)值10737418240(10GB),如果需要運(yùn)行HBase的MR任務(wù),可以減小此值,因?yàn)橐粋(gè)region對(duì)應(yīng)一個(gè)map任務(wù),如果單個(gè)region過(guò)大,會(huì)導(dǎo)致map任務(wù)執(zhí)行時(shí)間過(guò)長(zhǎng)。該值的意思就是,如果HFile的大小達(dá)到這個(gè)數(shù)值,則這個(gè)region會(huì)被切分為兩個(gè)Hfile。

優(yōu)化hbase客戶(hù)端緩存

屬性:hbase.client.write.buffer

文件:hbase-site.xml

解釋?zhuān)河糜谥付℉Base客戶(hù)端緩存,增大該值可以減少RPC調(diào)用次數(shù),但是會(huì)消耗更多內(nèi)存,反之則反之。一般我們需要設(shè)定一定的緩存大小,以達(dá)到減少RPC次數(shù)的目的。

指定scan.next掃描HBase所獲取的行數(shù)

屬性:hbase.client.scanner.caching

文件:hbase-site.xml

解釋?zhuān)河糜谥付╯can.next方法獲取的默認(rèn)行數(shù),值越大,消耗內(nèi)存越大。

6. 內(nèi)存優(yōu)化

HBase操作過(guò)程中需要大量的內(nèi)存開(kāi)銷(xiāo),畢竟Table是可以緩存在內(nèi)存中的,一般會(huì)分配整個(gè)可用內(nèi)存的70%給HBase的Java堆。但是不建議分配非常大的堆內(nèi)存,因?yàn)镚C過(guò)程持續(xù)太久會(huì)導(dǎo)致RegionServer處于長(zhǎng)期不可用狀態(tài),一般16~48G內(nèi)存就可以了,如果因?yàn)榭蚣苷加脙?nèi)存過(guò)高導(dǎo)致系統(tǒng)內(nèi)存不足,框架一樣會(huì)被系統(tǒng)服務(wù)拖死。

7. JVM優(yōu)化

涉及文件:hbase-env.sh

并行GC

參數(shù):·-XX:+UseParallelGC·

解釋?zhuān)洪_(kāi)啟并行GC

同時(shí)處理垃圾回收的線(xiàn)程數(shù)

參數(shù):-XX:ParallelGCThreads=cpu_core – 1

解釋?zhuān)涸搶傩栽O(shè)置了同時(shí)處理垃圾回收的線(xiàn)程數(shù)。

禁用手動(dòng)GC

參數(shù):-XX:DisableExplicitGC

解釋?zhuān)悍乐归_(kāi)發(fā)人員手動(dòng)調(diào)用GC

8. Zookeeper優(yōu)化優(yōu)化Zookeeper會(huì)話(huà)超時(shí)時(shí)間

參數(shù):zookeeper.session.timeout

文件:hbase-site.xml

解釋?zhuān)篒n hbase-site.xml, set zookeeper.session.timeout to 30 seconds or less to bound failure detection (20-30 seconds is a good start)。

該值會(huì)直接關(guān)系到master發(fā)現(xiàn)服務(wù)器宕機(jī)的最大周期,默認(rèn)值為30秒,如果該值過(guò)小,會(huì)在HBase在寫(xiě)入大量數(shù)據(jù)發(fā)生而GC時(shí),導(dǎo)致RegionServer短暫的不可用,從而沒(méi)有向ZK發(fā)送心跳包,最終導(dǎo)致認(rèn)為從節(jié)點(diǎn)shutdown。一般20臺(tái)左右的集群需要配置5臺(tái)zookeeper。

十三、HBase 大廠(chǎng)面試題解析1. Hbase是怎么寫(xiě)數(shù)據(jù)的?

Client寫(xiě)入 -> 存入MemStore,一直到MemStore滿(mǎn) -> Flush成一個(gè)StoreFile,直至增長(zhǎng)到一定閾值 -> 觸發(fā)Compact合并操作 -> 多個(gè)StoreFile合并成一個(gè)StoreFile,同時(shí)進(jìn)行版本合并和數(shù)據(jù)刪除 -> 當(dāng)StoreFiles Compact后,逐步形成越來(lái)越大的StoreFile -> 單個(gè)StoreFile大小超過(guò)一定閾值后(默認(rèn)10G),觸發(fā)Split操作,把當(dāng)前Region Split成2個(gè)Region,Region會(huì)下線(xiàn),新Split出的2個(gè)孩子Region會(huì)被HMaster分配到相應(yīng)的HRegionServer 上,使得原先1個(gè)Region的壓力得以分流到2個(gè)Region上

由此過(guò)程可知,HBase只是增加數(shù)據(jù),沒(méi)有更新和刪除操作,用戶(hù)的更新和刪除都是邏輯層面的,在物理層面,更新只是追加操作,刪除只是標(biāo)記操作。

用戶(hù)寫(xiě)操作只需要進(jìn)入到內(nèi)存即可立即返回,從而保證I/O高性能。

2. HDFS和HBase各自使用場(chǎng)景

首先一點(diǎn)需要明白:Hbase是基于HDFS來(lái)存儲(chǔ)的。

HDFS:

一次性寫(xiě)入,多次讀取。

保證數(shù)據(jù)的一致性。

主要是可以部署在許多廉價(jià)機(jī)器中,通過(guò)多副本提高可靠性,提供了容錯(cuò)和恢復(fù)機(jī)制。

HBase:

瞬間寫(xiě)入量很大,數(shù)據(jù)庫(kù)不好支撐或需要很高成本支撐的場(chǎng)景。

數(shù)據(jù)需要長(zhǎng)久保存,且量會(huì)持久增長(zhǎng)到比較大的場(chǎng)景。

HBase不適用與有 join,多級(jí)索引,表關(guān)系復(fù)雜的數(shù)據(jù)模型。

大數(shù)據(jù)量(100s TB級(jí)數(shù)據(jù))且有快速隨機(jī)訪(fǎng)問(wèn)的需求。如:淘寶的交易歷史記錄。數(shù)據(jù)量巨大無(wú)容置疑,面向普通用戶(hù)的請(qǐng)求必然要即時(shí)響應(yīng)。

業(yè)務(wù)場(chǎng)景簡(jiǎn)單,不需要關(guān)系數(shù)據(jù)庫(kù)中很多特性(例如交叉列、交叉表,事務(wù),連接等等)。

3. Hbase的存儲(chǔ)結(jié)構(gòu)

Hbase 中的每張表都通過(guò)行鍵(rowkey)按照一定的范圍被分割成多個(gè)子表(HRegion),默認(rèn)一個(gè)HRegion 超過(guò)256M 就要被分割成兩個(gè),由HRegionServer管理,管理哪些 HRegion 由 Hmaster 分配。HRegion 存取一個(gè)子表時(shí),會(huì)創(chuàng)建一個(gè) HRegion 對(duì)象,然后對(duì)表的每個(gè)列族(Column Family)創(chuàng)建一個(gè) store 實(shí)例, 每個(gè) store 都會(huì)有 0 個(gè)或多個(gè) StoreFile 與之對(duì)應(yīng),每個(gè) StoreFile 都會(huì)對(duì)應(yīng)一個(gè)HFile,HFile 就是實(shí)際的存儲(chǔ)文件,一個(gè) HRegion 還擁有一個(gè) MemStore實(shí)例。

4. 熱點(diǎn)現(xiàn)象(數(shù)據(jù)傾斜)怎么產(chǎn)生的,以及解決方法有哪些

熱點(diǎn)現(xiàn)象:

某個(gè)小的時(shí)段內(nèi),對(duì)HBase的讀寫(xiě)請(qǐng)求集中到極少數(shù)的Region上,導(dǎo)致這些region所在的RegionServer處理請(qǐng)求量驟增,負(fù)載量明顯偏大,而其他的RgionServer明顯空閑。

熱點(diǎn)現(xiàn)象出現(xiàn)的原因:

HBase中的行是按照rowkey的字典順序排序的,這種設(shè)計(jì)優(yōu)化了scan操作,可以將相關(guān)的行以及會(huì)被一起讀取的行存取在臨近位置,便于scan。然而糟糕的rowkey設(shè)計(jì)是熱點(diǎn)的源頭。

熱點(diǎn)發(fā)生在大量的client直接訪(fǎng)問(wèn)集群的一個(gè)或極少數(shù)個(gè)節(jié)點(diǎn)(訪(fǎng)問(wèn)可能是讀,寫(xiě)或者其他操作)。大量訪(fǎng)問(wèn)會(huì)使熱點(diǎn)region所在的單個(gè)機(jī)器超出自身承受能力,引起性能下降甚至region不可用,這也會(huì)影響同一個(gè)RegionServer上的其他region,由于主機(jī)無(wú)法服務(wù)其他region的請(qǐng)求。

熱點(diǎn)現(xiàn)象解決辦法:

為了避免寫(xiě)熱點(diǎn),設(shè)計(jì)rowkey使得不同行在同一個(gè)region,但是在更多數(shù)據(jù)情況下,數(shù)據(jù)應(yīng)該被寫(xiě)入集群的多個(gè)region,而不是一個(gè)。常見(jiàn)的方法有以下這些:

加鹽:在rowkey的前面增加隨機(jī)數(shù),使得它和之前的rowkey的開(kāi)頭不同。分配的前綴種類(lèi)數(shù)量應(yīng)該和你想使用數(shù)據(jù)分散到不同的region的數(shù)量一致。加鹽之后的rowkey就會(huì)根據(jù)隨機(jī)生成的前綴分散到各個(gè)region上,以避免熱點(diǎn)。

哈希:哈希可以使負(fù)載分散到整個(gè)集群,但是讀卻是可以預(yù)測(cè)的。使用確定的哈?梢宰尶蛻(hù)端重構(gòu)完整的rowkey,可以使用get操作準(zhǔn)確獲取某一個(gè)行數(shù)據(jù)

反轉(zhuǎn):第三種防止熱點(diǎn)的方法時(shí)反轉(zhuǎn)固定長(zhǎng)度或者數(shù)字格式的rowkey。這樣可以使得rowkey中經(jīng)常改變的部分(最沒(méi)有意義的部分)放在前面。這樣可以有效的隨機(jī)rowkey,但是犧牲了rowkey的有序性。反轉(zhuǎn)rowkey的例子以手機(jī)號(hào)為rowkey,可以將手機(jī)號(hào)反轉(zhuǎn)后的字符串作為rowkey,這樣的就避免了以手機(jī)號(hào)那樣比較固定開(kāi)頭導(dǎo)致熱點(diǎn)問(wèn)題

時(shí)間戳反轉(zhuǎn):一個(gè)常見(jiàn)的數(shù)據(jù)處理問(wèn)題是快速獲取數(shù)據(jù)的最近版本,使用反轉(zhuǎn)的時(shí)間戳作為rowkey的一部分對(duì)這個(gè)問(wèn)題十分有用,可以用 Long.Max_Value - timestamp 追加到key的末尾,例如[key][reverse_timestamp],[key]的最新值可以通過(guò)scan [key]獲得[key]的第一條記錄,因?yàn)镠Base中rowkey是有序的,第一條記錄是最后錄入的數(shù)據(jù)。

比如需要保存一個(gè)用戶(hù)的操作記錄,按照操作時(shí)間倒序排序,在設(shè)計(jì)rowkey的時(shí)候,可以這樣設(shè)計(jì)[userId反轉(zhuǎn)][Long.Max_Value - timestamp],在查詢(xún)用戶(hù)的所有操作記錄數(shù)據(jù)的時(shí)候,直接指定反轉(zhuǎn)后的userId,startRow是[userId反轉(zhuǎn)][000000000000],stopRow是[userId反轉(zhuǎn)][Long.Max_Value - timestamp]

如果需要查詢(xún)某段時(shí)間的操作記錄,startRow是[user反轉(zhuǎn)][Long.Max_Value - 起始時(shí)間],stopRow是[userId反轉(zhuǎn)][Long.Max_Value - 結(jié)束時(shí)間]

HBase建表預(yù)分區(qū):創(chuàng)建HBase表時(shí),就預(yù)先根據(jù)可能的RowKey劃分出多個(gè)region而不是默認(rèn)的一個(gè),從而可以將后續(xù)的讀寫(xiě)操作負(fù)載均衡到不同的region上,避免熱點(diǎn)現(xiàn)象。

5. HBase的 rowkey 設(shè)計(jì)原則

長(zhǎng)度原則:100字節(jié)以?xún)?nèi),8的倍數(shù)最好,可能的情況下越短越好。因?yàn)镠File是按照 keyvalue 存儲(chǔ)的,過(guò)長(zhǎng)的rowkey會(huì)影響存儲(chǔ)效率;其次,過(guò)長(zhǎng)的rowkey在memstore中較大,影響緩沖效果,降低檢索效率。最后,操作系統(tǒng)大多為64位,8的倍數(shù),充分利用操作系統(tǒng)的最佳性能。

散列原則:高位散列,低位時(shí)間字段。避免熱點(diǎn)問(wèn)題。

唯一原則:分利用這個(gè)排序的特點(diǎn),將經(jīng)常讀取的數(shù)據(jù)存儲(chǔ)到一塊,將最近可能會(huì)被訪(fǎng)問(wèn) 的數(shù)據(jù)放到一塊。

6. HBase的列簇設(shè)計(jì)

原則:在合理范圍內(nèi)能盡量少的減少列簇就盡量減少列簇,因?yàn)榱写厥枪蚕韗egion的,每個(gè)列簇?cái)?shù)據(jù)相差太大導(dǎo)致查詢(xún)效率低下。

最優(yōu):將所有相關(guān)性很強(qiáng)的 key-value 都放在同一個(gè)列簇下,這樣既能做到查詢(xún)效率最高,也能保持盡可能少的訪(fǎng)問(wèn)不同的磁盤(pán)文件。以用戶(hù)信息為例,可以將必須的基本信息存放在一個(gè)列族,而一些附加的額外信息可以放在另一列族。

7. HBase 中 compact 用途是什么,什么時(shí)候觸發(fā),分為哪兩種,有什么區(qū)別

在 hbase 中每當(dāng)有 memstore 數(shù)據(jù) flush 到磁盤(pán)之后,就形成一個(gè) storefile,當(dāng) storeFile的數(shù)量達(dá)到一定程度后,就需要將 storefile 文件來(lái)進(jìn)行 compaction 操作。

Compact 的作用:

合并文件

清除過(guò)期,多余版本的數(shù)據(jù)

提高讀寫(xiě)數(shù)據(jù)的效率4HBase 中實(shí)現(xiàn)了兩種 compaction 的方式:minor and major. 這兩種 compaction 方式的區(qū)別是:

Minor 操作只用來(lái)做部分文件的合并操作以及包括 minVersion=0 并且設(shè)置 ttl 的過(guò)期版本清理,不做任何刪除數(shù)據(jù)、多版本數(shù)據(jù)的清理工作。

Major 操作是對(duì) Region 下的 HStore 下的所有 StoreFile 執(zhí)行合并操作,最終的結(jié)果是整理合并出一個(gè)文件。

聲明: 本文由入駐維科號(hào)的作者撰寫(xiě),觀(guān)點(diǎn)僅代表作者本人,不代表OFweek立場(chǎng)。如有侵權(quán)或其他問(wèn)題,請(qǐng)聯(lián)系舉報(bào)。

發(fā)表評(píng)論

0條評(píng)論,0人參與

請(qǐng)輸入評(píng)論內(nèi)容...

請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字

您提交的評(píng)論過(guò)于頻繁,請(qǐng)輸入驗(yàn)證碼繼續(xù)

  • 看不清,點(diǎn)擊換一張  刷新

暫無(wú)評(píng)論

暫無(wú)評(píng)論

人工智能 獵頭職位 更多
掃碼關(guān)注公眾號(hào)
OFweek人工智能網(wǎng)
獲取更多精彩內(nèi)容
文章糾錯(cuò)
x
*文字標(biāo)題:
*糾錯(cuò)內(nèi)容:
聯(lián)系郵箱:
*驗(yàn) 證 碼:

粵公網(wǎng)安備 44030502002758號(hào)