免费久久国产&夜夜毛片&亚洲最大无码中文字幕&国产成人无码免费视频之奶水&吴家丽查理三级做爰&国产日本亚欧在线观看

訂閱
糾錯
加入自媒體

HBase 知識體系吐血總結

2021-11-17 11:37
園陌
關注

HBase 涉及的知識點如下圖所示,本文將逐一講解:

本文目錄如上圖

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

一、HBase 基礎1. HBase 基本介紹

簡介

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

它介于 NoSql 和 RDBMS 之間,僅能通過主鍵(row key)和主鍵的 range 來檢索數據,僅支持單行事務(可通過 hive 支持來實現多表 join 等復雜操作)。

主要用來存儲結構化和半結構化的松散數據。

Hbase 查詢數據功能很簡單,不支持 join 等復雜操作,不支持復雜的事務(行級的事務)Hbase 中支持的數據類型:byte[]與 hadoop 一樣,Hbase 目標主要依靠橫向擴展,通過不斷增加廉價的商用服務器,來增加計算和存儲能力。

HBase 中的表一般有這樣的特點:

大:一個表可以有上十億行,上百萬列面向列:面向列(族)的存儲和權限控制,列(族)獨立檢索。稀疏:對于為空(null)的列,并不占用存儲空間,因此,表可以設計的非常稀疏。

HBase 的發(fā)展歷程

HBase 的原型是 Google 的 BigTable 論文,受到了該論文思想的啟發(fā),目前作為 Hadoop 的子項目來開發(fā)維護,用于支持結構化的數據存儲。

2006 年 Google 發(fā)表 BigTable 白皮書2006 年開始開發(fā) HBase2008 HBase 成為了 Hadoop 的子項目2010 年 HBase 成為 Apache 頂級項目2. HBase 與 Hadoop 的關系

HDFS

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

HBase

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

關系型數據庫

結構:

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

功能:

支持向上擴展使用 SQL 查詢面向行,即每一行都是一個連續(xù)單元數據總量依賴于服務器配置具有 ACID 支持適合結構化數據傳統(tǒng)關系型數據庫一般都是中心化的支持事務支持 Join

HBase

結構:

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

功能:

支持向外擴展使用 API 和 MapReduce 來訪問 HBase 表數據面向列,即每一列都是一個連續(xù)的單元數據總量不依賴具體某臺機器,而取決于機器數量HBase 不支持 ACID(Atomicity、Consistency、Isolation、Durability)適合結構化數據和非結構化數據一般都是分布式的HBase 不支持事務不支持 Join4. HBase 特征簡要海量存儲

Hbase 適合存儲 PB 級別的海量數據,在 PB 級別的數據以及采用廉價 PC 存儲的情況下,能在幾十到百毫秒內返回數據。這與 Hbase 的極易擴展性息息相關。正式因為 Hbase 良好的擴展性,才為海量數據的存儲提供了便利。

列式存儲

這里的列式存儲其實說的是列族存儲,Hbase 是根據列族來存儲數據的。列族下面可以有非常多的列,列族在創(chuàng)建表的時候就必須指定。

極易擴展

Hbase 的擴展性主要體現在兩個方面,一個是基于上層處理能力(RegionServer)的擴展,一個是基于存儲的擴展(HDFS)。通過橫向添加 RegionSever 的機器,進行水平擴展,提升 Hbase 上層的處理能力,提升 Hbsae 服務更多 Region 的能力。備注:RegionServer 的作用是管理 region、承接業(yè)務的訪問,這個后面會詳細的介紹通過橫向添加 Datanode 的機器,進行存儲層擴容,提升 Hbase 的數據存儲能力和提升后端存儲的讀寫能力。

高并發(fā)

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

稀疏

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

二、HBase 基礎架構

HMaster

功能:

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

功能:

負責存儲 HBase 的實際數據處理分配給它的 Region刷新緩存到 HDFS維護 HLog執(zhí)行壓縮負責處理 Region 分片

組件:

Write-Ahead logs

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

HFile

這是在磁盤上保存原始數據的實際的物理文件,是實際的存儲文件。

Store

HFile 存儲在 Store 中,一個 Store 對應 HBase 表中的一個列族。

MemStore

顧名思義,就是內存存儲,位于內存中,用來保存當前的數據操作,所以當數據保存在 WAL 中之后,RegsionServer 會在內存中存儲鍵值對。

Region

Hbase 表的分片,HBase 表會根據 RowKey 值被切分成不同的 region 存儲在 RegionServer 中,在一個 RegionServer 中可以有多個不同的 region。

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

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

查看當前數據庫中有哪些表hbase(main):002:0> list

創(chuàng)建一張表

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

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

或者

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

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

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

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

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

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

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

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

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

2) 查詢操作通過 rowkey 進行查詢

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

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

查看 rowkey 下面的某個列族的信息

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

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

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

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

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

查看 rowkey 指定多個列族的信息

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

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

或者這樣寫

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

或者這樣寫

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

指定 rowkey 與列值查詢

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

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

指定 rowkey 與列值模糊查詢

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

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

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

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', '中國'

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

查詢所有數據

查詢 user 表中的所有信息

scan 'user'

列族查詢

查詢 user 表中列族為 info 的信息

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

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

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

多列族查詢

查詢 user 表中列族為 info 和 data 的信息

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

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

指定列族與某個列名查詢

查詢 user 表中列族為 info、列標示符為 name 的信息

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

指定列族與列名以及限定版本查詢

查詢 user 表中列族為 info、列標示符為 name 的信息,并且版本最新的 5 個

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

指定多個列族與按照數據值模糊查詢

查詢 user 表中列族為 info 和 data 且列標示符中含有 a 字符的信息

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

rowkey 的范圍值查詢

查詢 user 表中列族為 info,rk 范圍是(rk0001, rk0003)的數據

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

指定 rowkey 模糊查詢

查詢 user 表中 row key 以 rk 字符開頭的

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

指定數據范圍值查詢

查詢 user 表中指定范圍的數據

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

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

3) 更新操作更新數據值

更新操作同插入操作一模一樣,只不過有數據就更新,沒數據就添加。

更新版本號

將 user 表的 f1 列族版本號改為 5

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

4) 刪除操作指定 rowkey 以及列名進行刪除

刪除 user 表 row key 為 rk0001,列標示符為 info:name 的數據

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

指定 rowkey,列名以及字段值進行刪除

刪除 user 表 row key 為 rk0001,列標示符為 info:name,timestamp 為 1392383705316 的數據

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

刪除一個列族

刪除一個列族

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

或者

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

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

刪除表

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

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

然后才能 drop 這個表,使用命令:

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

注意:如果直接 drop 表,會報錯:Drop the named table. Table must first be disabled

四、HBase 的高級 shell 管理命令status

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

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

whoami

顯示 HBase 當前用戶,例如:

hbase> whoami

list

顯示當前所有的表

hbase> list

count

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

hbase> count 'user'

describe

展示表結構信息

hbase> describe 'user'

exists

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

hbase> exists 'user'

is_enabled、is_disabled

檢查表是否啟用或禁用

hbase> is_enabled 'user'

alter

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

為當前表增加列族:

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

為當前表刪除列族:

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

disable/enable

禁用一張表/啟用一張表

drop

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

truncate

清空表

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

         

圖片標題

圖片標題

2. 過濾器查詢

過濾器的類型很多,但是可以分為兩大類——比較過濾器,專用過濾器。

過濾器的作用是在服務端判斷數據是否滿足條件,然后只將滿足條件的數據返回給客戶端;

hbase 過濾器的比較運算符:

LESS  <

LESS_OR_EQUAL <=

EQUAL =

NOT_EQUAL <>

GREATER_OR_EQUAL >=

GREATER >

NO_OP 排除所有

Hbase 過濾器的比較器(指定比較機制):

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

BinaryPrefixComparator 跟前面相同,只是比較左端的數據是否相同

NullComparator 判斷給定的是否為空

BitComparator 按位比較

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

SubstringComparator 判斷提供的子串是否出現在value中。

1) 比較過濾器rowKey 過濾器 RowFilter

通過 RowFilter 過濾比 rowKey 0003 小的所有值出來

@Test

public  void rowKeyFilter() throws IOException {
 

圖片標題

列族過濾器 FamilyFilter

查詢比 f2 列族小的所有的列族內的數據

@Test

public  void familyFilter() throws IOException {

圖片標題

列過濾器 QualifierFilter

只查詢 name 列的值

@Test

public  void qualifierFilter() throws IOException {

圖片標題

列值過濾器 ValueFilter

查詢所有列當中包含 8 的數據

@Test

圖片標題

2) 專用過濾器單列值過濾器 SingleColumnValueFilter

SingleColumnValueFilter 會返回滿足條件的整列值的所有字段

@Test

圖片標題

myuser.close();


列值排除過濾器 SingleColumnValueExcludeFilter

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

rowkey 前綴過濾器 PrefixFilter

查詢以 00 開頭的所有前綴的 rowkey

@Test

圖片標題

分頁過濾器 PageFilter

分頁過濾器 PageFilter

@Test

圖片標題

圖片標題

圖片標題

3) 多過濾器綜合查詢 FilterList

需求:使用 SingleColumnValueFilter 查詢 f1 列族,name 為劉備的數據,并且同時滿足 rowkey 的前綴以 00 開頭的數據(PrefixFilter)

圖片標題

圖片標題

圖片標題

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

HBase系統(tǒng)架構

根據這幅圖,解釋下HBase中各個組件

1) Client包含訪問hbase的接口,Client維護著一些cache來加快對hbase的訪問,比如regione的位置信息.2) Zookeeper

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

Zookeeper在HBase中的作用:

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

HMaster僅僅維護者table和HRegion的元數據信息,負載很低。

2. HBase的表數據模型

HBase的表結構1) 行鍵 Row Key

與nosql數據庫一樣,row key是用來檢索記錄的主鍵。訪問hbase table中的行,只有三種方式:

通過單個row key訪問通過row key的range全表掃描

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

Hbase會對表中的數據按照rowkey排序(字典順序)

存儲時,數據按照Row key的字典序(byte order)排序存儲。設計key時,要充分排序存儲這個特性,將經常一起讀取的行存儲放到一起。(位置相關性)。

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

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

2) 列族 Column Family

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

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

訪問控制、磁盤和內存的使用統(tǒng)計都是在列族層面進行的。列族越多,在取一行數據時所要參與IO、搜尋的文件就越多,所以,如果沒有必要,不要設置太多的列族。

3) 列 Column

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

4) 時間戳 Timestamp

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

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

保存數據的最后n個版本保存最近一段時間內的版本(設置數據的生命周期TTL)。

用戶可以針對每個列族進行設置。

5) 單元 Cell

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

6) 版本號 VersionNum

數據的版本號,每條數據可以有多個版本號,默認值為系統(tǒng)時間戳,類型為Long。

3. 物理存儲1) 整體結構

HBase 整體結構

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

Table 在行的方向上分割為多個 HRegion。

HRegion按大小分割的(默認10G),每個表一開始只有一 個HRegion,隨著數據不斷插入表,HRegion不斷增大,當增大到一個閥值的時候,HRegion就會等分會兩個新的HRegion。當Table 中的行不斷增多,就會有越來越多的 HRegion。

HRegion 是 HBase 中分布式存儲和負載均衡的最小單元。最小單元就表示不同的 HRegion 可以分布在不同的 HRegion Server 上。但一個 HRegion 是不會拆分到多個 Server 上的。

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

2) StoreFile 和 HFile 結構

StoreFile以HFile格式保存在HDFS上。

HFile的格式為:

HFile 格式

首先HFile文件是不定長的,長度固定的只有其中的兩塊:Trailer和FileInfo。正如圖中所示的,Trailer中有指針指向其他數 據塊的起始點。

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

Data Index和Meta Index塊記錄了每個Data塊和Meta塊的起始點。

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

HFile里面的每個KeyValue對就是一個簡單的byte數組。但是這個byte數組里面包含了很多項,并且有固定的結構。我們來看看里面的具體結構:

HFile 具體結構

開始是兩個固定長度的數值,分別表示Key的長度和Value的長度。緊接著是Key,開始是固定長度的數值,表示RowKey的長度,緊接著是 RowKey,然后是固定長度的數值,表示Family的長度,然后是Family,接著是Qualifier,然后是兩個固定長度的數值,表示Time Stamp和Key Type(Put/Delete)。Value部分沒有這么復雜的結構,就是純粹的二進制數據了。

HFile分為六個部分:

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

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

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

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

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

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

HFile的Data Block,Meta Block通常采用壓縮方式存儲,壓縮之后可以大大減少網絡IO和磁盤IO,隨之而來的開銷當然是需要花費cpu進行壓縮和解壓縮。目前HFile的壓縮支持兩種方式:Gzip,Lzo。

3) Memstore與StoreFile

一個 HRegion 由多個 Store 組成,每個 Store 包含一個列族的所有數據Store 包括位于內存的 Memstore 和位于硬盤的 StoreFile。

寫操作先寫入 Memstore,當 Memstore 中的數據量達到某個閾值,HRegionServer 啟動 FlashCache 進程寫入 StoreFile,每次寫入形成單獨一個 StoreFile

當 StoreFile 大小超過一定閾值后,會把當前的 HRegion 分割成兩個,并由 HMaster 分配給相應的 HRegion 服務器,實現負載均衡

客戶端檢索數據時,先在memstore找,找不到再找storefile。

4) HLog(WAL log)

WAL 意為Write ahead log,類似 mysql 中的 binlog,用來 做災難恢復時用,Hlog記錄數據的所有變更,一旦數據修改,就可以從log中進行恢復。

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

HLog文件就是一個普通的Hadoop Sequence File:

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

1) 讀請求過程:

HRegionServer保存著meta表以及表數據,要訪問表數據,首先Client先去訪問zookeeper,從zookeeper里面獲取meta表所在的位置信息,即找到這個meta表在哪個HRegionServer上保存著。

接著Client通過剛才獲取到的HRegionServer的IP來訪問Meta表所在的HRegionServer,從而讀取到Meta,進而獲取到Meta表中存放的元數據。

Client通過元數據中存儲的信息,訪問對應的HRegionServer,然后掃描所在HRegionServer的Memstore和Storefile來查詢數據。

最后HRegionServer把查詢到的數據響應給Client。

查看meta表信息

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

2) 寫請求過程:

Client也是先訪問zookeeper,找到Meta表,并獲取Meta表元數據。

確定當前將要寫入的數據所對應的HRegion和HRegionServer服務器。

Client向該HRegionServer服務器發(fā)起寫入數據請求,然后HRegionServer收到請求并響應。

Client先把數據寫入到HLog,以防止數據丟失。

然后將數據寫入到Memstore。

如果HLog和Memstore均寫入成功,則這條數據寫入成功

如果Memstore達到閾值,會把Memstore中的數據flush到Storefile中。

當Storefile越來越多,會觸發(fā)Compact合并操作,把過多的Storefile合并成一個大的Storefile。

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

細節(jié)描述:

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

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

由于對表的更新是不斷追加的,compact時,需要訪問Store中全部的 StoreFile和MemStore,將他們按row key進行合并,由于StoreFile和MemStore都是經過排序的,并且StoreFile帶有內存中索引,合并的過程還是比較快。

5. HRegion管理1) HRegion分配

任何時刻,一個HRegion只能分配給一個HRegion Server。HMaster記錄了當前有哪些可用的HRegion Server。以及當前哪些HRegion分配給了哪些HRegion Server,哪些HRegion還沒有分配。當需要分配的新的HRegion,并且有一個HRegion Server上有可用空間時,HMaster就給這個HRegion Server發(fā)送一個裝載請求,把HRegion分配給這個HRegion Server。HRegion Server得到請求后,就開始對此HRegion提供服務。

2) HRegion Server上線

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

3) HRegion Server下線

當HRegion Server下線時,它和zookeeper的會話斷開,zookeeper而自動釋放代表這臺server的文件上的獨占鎖。HMaster就可以確定:

HRegion Server和zookeeper之間的網絡斷開了。HRegion Server掛了。

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

6. HMaster工作機制1) master上

master啟動進行以下步驟:

從zookeeper上獲取唯一一個代表active master的鎖,用來阻止其它HMaster成為master。掃描zookeeper上的server父節(jié)點,獲得當前可用的HRegion Server列表。和每個HRegion Server通信,獲得當前已分配的HRegion和HRegion Server的對應關系。掃描.META.region的集合,計算得到當前還未分配的HRegion,將他們放入待分配HRegion列表。2) master下線

由于HMaster只維護表和region的元數據,而不參與表數據IO的過程,HMaster下線僅導致所有元數據的修改被凍結(無法創(chuàng)建刪除表,無法修改表的schema,無法進行HRegion的負載均衡,無法處理HRegion 上下線,無法進行HRegion的合并,唯一例外的是HRegion的split可以正常進行,因為只有HRegion Server參與),表的數據讀寫還可以正常進行。因此HMaster下線短時間內對整個HBase集群沒有影響。

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

因此,一般HBase集群中總是有一個HMaster在提供服務,還有一個以上的‘HMaster’在等待時機搶占它的位置。

7. HBase三個重要機制1) flush機制

1.(hbase.regionserver.global.memstore.size)默認;堆大小的40%regionServer的全局memstore的大小,超過該大小會觸發(fā)flush到磁盤的操作,默認是堆大小的40%,而且regionserver級別的flush會阻塞客戶端讀寫

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

3.(hbase.regionserver.optionalcacheflushinterval)默認:1h內存中的文件在自動刷新之前能夠存活的最長時間

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

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

6.(hbase.hstore.compactionThreshold)默認:超過3個一個store里面允許存的hfile的個數,超過這個個數會被寫到新的一個hfile里面 也即是每個region的每個列族對應的memstore在flush為hfile的時候,默認情況下當超過3個hfile的時候就會對這些文件進行合并重寫為一個新文件,設置個數越大可以減少觸發(fā)合并的時間,但是每次合并的時間就會越長

2) compact機制

把小的storeFile文件合并成大的HFile文件。清理過期的數據,包括刪除的數據將數據的版本號保存為1個。

3) split機制

當HRegion達到閾值,會把過大的HRegion一分為二。默認一個HFile達到10Gb的時候就會進行切分。

七、HBase 與 MapReduce 的集成

HBase 當中的數據最終都是存儲在 HDFS 上面的,HBase 天生的支持 MR 的操作,我們可以通過 MR 直接處理 HBase 當中的數據,并且 MR 可以將處理后的結果直接存儲到 HBase 當中去。

需求:讀取 HBase 當中一張表的數據,然后將數據寫入到 HBase 當中的另外一張表當中去。

注意:我們可以使用 TableMapper 與 TableReducer 來實現從 HBase 當中讀取與寫入數據。

這里我們將 myuser 這張表當中 f1 列族的 name 和 age 字段寫入到 myuser2 這張表的 f1 列族當中去。

需求一:讀取 myuser 這張表當中的數據寫入到 HBase 的另外一張表當中去:

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

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

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

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

圖片標題

圖片標題

圖片標題

圖片標題

第三步:打包運行

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

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

需求二:讀取 HDFS 文件,寫入到 HBase 表當中去

第一步:準備數據文件

準備數據文件,并將數據文件上傳到 HDFS 上面去。

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

圖片標題

     

圖片標題

需求四:通過 bulkload 的方式批量加載數據到 HBase 當中去

加載數據到 HBase 當中去的方式多種多樣,我們可以使用 HBase 的 javaAPI 或者使用 sqoop 將我們的數據寫入或者導入到 HBase 當中去,但是這些方式不是慢就是在導入的過程的占用 Region 資料導致效率低下,我們也可以通過 MR 的程序,將我們的數據直接轉換成 HBase 的最終存儲格式 HFile,然后直接 load 數據到 HBase 當中去即可。

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

優(yōu)點:

導入過程不占用 Region 資源

能快速導入海量的數據

節(jié)省內存

第一步:定義 mapper 類

圖片標題

圖片標題

第三步:將代碼打成 jar 包然后運行

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

第四步:開發(fā)代碼,加載數據

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

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_hfile"), admin,table,connection.getRegionLocator(TableName.valueOf("myuser2")));
   }

或者我們也可以通過命令行來進行加載數據。

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

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

然后執(zhí)行以下命令,將 hbase 的 HFile 直接導入到表 myuser2 當中來

yarn jar /servers/hbase/lib/hbase-server-1.2.0.jar completebulkload /hbase/output_hfile myuser2
八、HBase 的預分區(qū)1. 為何要預分區(qū)?增加數據讀寫效率負載均衡,防止數據傾斜方便集群容災調度 region優(yōu)化 Map 數量2. 如何預分區(qū)?

每一個 region 維護著 startRow 與 endRowKey,如果加入的數據符合某個 region 維護的 rowKey 范圍,則該數據交給這個 region 維護。

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

完成后如圖:

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

完成后如圖:

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

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

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)建預分區(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();
       //自定義算法,產生一系列Hash散列值存儲在二維數組中
       byte[][] splitKeys = {{1,2,3,4,5},{'a','b','c','d','e'}};
       //通過HTableDescriptor來實現我們表的參數設置,包括表名,列族等等
       HTableDescriptor hTableDescriptor = new HTableDescriptor(TableName.valueOf("stuff4"));
       //添加列族
       hTableDescriptor.addFamily(new HColumnDescriptor("f1"));
       //添加列族
       hTableDescriptor.addFamily(new HColumnDescriptor("f2"));
       admin.createTable(hTableDescriptor,splitKeys);
       admin.close();
   }
九、HBase 的 rowKey 設計技巧

HBase 是三維有序存儲的,通過 rowkey(行鍵),column key(column family 和 qualifier)和 TimeStamp(時間戳)這個三個維度可以對 HBase 中的數據進行快速定位。

HBase 中 rowkey 可以唯一標識一行記錄,在 HBase 查詢的時候,有以下幾種方式:

通過 get 方式,指定 rowkey 獲取唯一一條記錄;通過 scan 方式,設置 startRow 和 stopRow 參數進行范圍匹配;全表掃描,即直接掃描整張表中所有行記錄。1. rowkey 長度原則

rowkey 是一個二進制碼流,可以是任意字符串,最大長度 64kb,實際應用中一般為 10-100bytes,以 byte[]形式保存,一般設計成定長。

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

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

MemStore 將緩存部分數據到內存,如果 rowkey 字段過長,內存的有效利用率就會降低,系統(tǒng)不能緩存更多的數據,這樣會降低檢索效率。

2. rowkey 散列原則

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

如果沒有散列字段,首字段直接是時間信息,所有的數據都會集中在一個 RegionServer 上,這樣在數據檢索的時候負載會集中在個別的 RegionServer 上,造成熱點問題,會降低查詢效率。

3. rowkey 唯一原則

必須在設計上保證其唯一性,rowkey 是按照字典順序排序存儲的,因此,設計 rowkey 的時候,要充分利用這個排序的特點,將經常讀取的數據存儲到一塊,將最近可能會被訪問的數據放到一塊。

4. 什么是熱點

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

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

設計良好的數據訪問模式以使集群被充分,均衡的利用。為了避免寫熱點,設計 rowkey 使得不同行在同一個 region,但是在更多數據情況下,數據應該被寫入集群的多個 region,而不是一個。

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

1) 加鹽

這里所說的加鹽不是密碼學中的加鹽,而是在 rowkey 的前面增加隨機數,具體就是給 rowkey 分配一個隨機前綴以使得它和之前的 rowkey 的開頭不同。分配的前綴種類數量應該和你想使用數據分散到不同的 region 的數量一致。加鹽之后的 rowkey 就會根據隨機生成的前綴分散到各個 region 上,以避免熱點。

2) 哈希

哈希會使同一行永遠用一個前綴加鹽。哈希也可以使負載分散到整個集群,但是讀卻是可以預測的。使用確定的哈?梢宰尶蛻舳酥貥嬐暾 rowkey,可以使用 get 操作準確獲取某一個行數據。

3) 反轉

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

反轉 rowkey 的例子以手機號為 rowkey,可以將手機號反轉后的字符串作為 rowkey,這樣的就避免了以手機號那樣比較固定開頭導致熱點問題。

3) 時間戳反轉

一個常見的數據處理問題是快速獲取數據的最近版本,使用反轉的時間戳作為 rowkey 的一部分對這個問題十分有用,可以用  Long.Max_Value - timestamp  追加到 key 的末尾,例如  [key][reverse_timestamp] , [key]  的最新值可以通過 scan [key]獲得[key]的第一條記錄,因為 HBase 中 rowkey 是有序的,第一條記錄是最后錄入的數據。

其他一些建議:

盡量減少行鍵和列族的大小在 HBase 中,value 永遠和它的 key 一起傳輸的。當具體的值在系統(tǒng)間傳輸時,它的 rowkey,列名,時間戳也會一起傳輸。如果你的 rowkey 和列名很大,這個時候它們將會占用大量的存儲空間。

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

冗長的屬性名雖然可讀性好,但是更短的屬性名存儲在 HBase 中會更好。

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

http://hbase.apache.org/book.html#cp

1. 起源

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

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

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

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

Observer 類似于傳統(tǒng)數據庫中的觸發(fā)器,當發(fā)生某些事件的時候這類協(xié)處理器會被 Server 端調用。

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

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

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

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

到 0.96 版本又新增一個 RegionServerObserver

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

2) endpoint 協(xié)處理器

Endpoint 協(xié)處理器類似傳統(tǒng)數據庫中的存儲過程,客戶端可以調用這些 Endpoint 協(xié)處理器執(zhí)行一段 Server 端代碼,并將 Server 端代碼的結果返回給客戶端進一步處理,最常見的用法就是進行聚集操作。

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

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

下圖是 EndPoint 的工作原理:

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

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

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

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

1) 靜態(tài)加載

通過修改 hbase-site.xml 這個文件來實現, 啟動全局 aggregation,能過操縱所有的表上的數據。只需要添加如下代碼:

<property>

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

<value>org.apache.hadoop.hbase.coprocessor.AggregateImplementation</value>

</property>

2) 動態(tài)加載

啟用表 aggregation,只對特定的表生效。通過 HBase Shell 來實現。

disable 指定表

hbase> disable 'mytable'

添加 aggregation

hbase> alter 'mytable', METHOD => 'table_att','coprocessor'=>
'|org.apache.Hadoop.hbase.coprocessor.AggregateImplementation||'

重啟指定表

hbase> enable 'mytable'

協(xié)處理器卸載

disable 'mytable'

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

enable 'test'

十一、HBase當中的二級索引的簡要介紹

由于HBase的查詢比較弱,如果需要實現類似于 select name,salary,count(1),max(salary) from user group by name,salary order by salary 等這樣的復雜性的統(tǒng)計需求,基本上不可能,或者說比較困難,所以我們在使用HBase的時候,一般都會借助二級索引的方案來進行實現。

HBase的一級索引就是rowkey,我們只能通過rowkey進行檢索。如果我們相對hbase里面列族的列列進行一些組合查詢,就需要采用HBase的二級索引方案來進行多條件的查詢。

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

常見的二級索引我們一般可以借助各種其他的方式來實現,例如Phoenix或者solr或者ES等。

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

NameNode的元數據備份使用SSD。

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

為NameNode指定多個元數據目錄,使用dfs.name.dir或者dfs.namenode.name.dir指定。一個指定本地磁盤,一個指定網絡磁盤。這樣可以提供元數據的冗余和健壯性,以免發(fā)生故障。

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

NameNode節(jié)點必須配置為RAID1(鏡像盤)結構。

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

因為Hadoop是IO密集型框架,所以盡量提升存儲的速度和吞吐量(類似位寬)。

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

$ sudo blockdev --setra 32768 /dev/sda

提示:ra是readahead的縮寫

關閉進程睡眠池

$ sudo sysctl -w vm.swappiness=0

調整ulimit上限,默認值為比較小的數字

$ ulimit -n 查看允許最大進程數

$ ulimit -u 查看允許打開最大文件數

修改:

$ sudo vi /etc/security/limits.conf 修改打開文件數限制

末尾添加:

*                soft    nofile          1024000

*                hard    nofile          1024000

Hive             -       nofile          1024000
hive             -       nproc           1024000

$ sudo vi /etc/security/limits.d/20-nproc.conf 修改用戶打開進程數限制

修改為:

#*          soft    nproc     4096

#root       soft    nproc     unlimited

*          soft    nproc     40960

root       soft    nproc     unlimited

開啟集群的時間同步NTP。

更新系統(tǒng)補丁(提示:更新補丁前,請先測試新版本補丁對集群節(jié)點的兼容性)

3. HDFS優(yōu)化(hdfs-site.xml)保證RPC調用會有較多的線程數

屬性:dfs.namenode.handler.count

解釋:該屬性是NameNode服務默認線程數,的默認值是10,根據機器的可用內存可以調整為50~100

屬性:dfs.datanode.handler.count

解釋:該屬性默認值為10,是DataNode的處理線程數,如果HDFS客戶端程序讀寫請求比較多,可以調高到15~20,設置的值越大,內存消耗越多,不要調整的過高,一般業(yè)務中,5~10即可。

副本數的調整

屬性:dfs.replication

解釋:如果數據量巨大,且不是非常之重要,可以調整為2~3,如果數據非常之重要,可以調整為3~5。

文件塊大小的調整

屬性:dfs.blocksize

解釋:塊大小定義,該屬性應該根據存儲的大量的單個文件大小來設置,如果大量的單個文件都小于100M,建議設置成64M塊大小,對于大于100M或者達到GB的這種情況,建議設置成256M,一般設置范圍波動在64M~256M之間。

4. MapReduce優(yōu)化(mapred-site.xml)Job任務服務線程數調整

mapreduce.jobtracker.handler.count

該屬性是Job任務線程數,默認值是10,根據機器的可用內存可以調整為50~100

Http服務器工作線程數

屬性:mapreduce.tasktracker.http.threads

解釋:定義HTTP服務器工作線程數,默認值為40,對于大集群可以調整到80~100

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

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

解釋:文件排序時同時合并的數據流的數量,這也定義了同時打開文件的個數,默認值為10,如果調高該參數,可以明顯減少磁盤IO,即減少文件讀取的次數。

設置任務并發(fā)

屬性:mapreduce.map.speculative

解釋:該屬性可以設置任務是否可以并發(fā)執(zhí)行,如果任務多而小,該屬性設置為true可以明顯加快任務執(zhí)行效率,但是對于延遲非常高的任務,建議改為false,這就類似于迅雷下載。

MR輸出數據的壓縮

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

解釋:對于大集群而言,建議設置Map-Reduce的輸出為壓縮的數據,而對于小集群,則不需要。

優(yōu)化Mapper和Reducer的個數

屬性:

mapreduce.tasktracker.map.tasks.maximum

mapreduce.tasktracker.reduce.tasks.maximum

解釋:以上兩個屬性分別為一個單獨的Job任務可以同時運行的Map和Reduce的數量。

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

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

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

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

reduce = 2 + 1/3cpu_core

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

HDFS 不是不允許追加內容么?沒錯,請看背景故事:

屬性:dfs.support.append

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

解釋:開啟HDFS追加同步,可以優(yōu)秀的配合HBase的數據同步和持久化。默認值為true。

優(yōu)化DataNode允許的最大文件打開數

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

文件:hdfs-site.xml

解釋:HBase一般都會同一時間操作大量的文件,根據集群的數量和規(guī)模以及數據動作,設置為4096或者更高。默認值:4096

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

屬性:dfs.image.transfer.timeout

文件:hdfs-site.xml

解釋:如果對于某一次數據操作來講,延遲非常高,socket需要等待更長的時間,建議把該值設置為更大的值(默認60000毫秒),以確保socket不會被timeout掉。

優(yōu)化數據的寫入效率

屬性:

mapreduce.map.output.compress

mapreduce.map.output.compress.codec

文件:mapred-site.xml

解釋:開啟這兩個數據可以大大提高文件的寫入效率,減少寫入時間。第一個屬性值修改為true,第二個屬性值修改為:org.apache.hadoop.io.compress.GzipCodec

優(yōu)化DataNode存儲

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

文件:hdfs-site.xml

解釋:默認為0,意思是當DataNode中有一個磁盤出現故障,則會認為該DataNode shutdown了。如果修改為1,則一個磁盤出現故障時,數據會被復制到其他正常的DataNode上,當前的DataNode繼續(xù)工作。

設置RPC監(jiān)聽數量

屬性:hbase.regionserver.handler.count

文件:hbase-site.xml

解釋:默認值為30,用于指定RPC監(jiān)聽的數量,可以根據客戶端的請求數進行調整,讀寫請求較多時,增加此值。

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

屬性:hbase.hregion.max.filesize

文件:hbase-site.xml

解釋:默認值10737418240(10GB),如果需要運行HBase的MR任務,可以減小此值,因為一個region對應一個map任務,如果單個region過大,會導致map任務執(zhí)行時間過長。該值的意思就是,如果HFile的大小達到這個數值,則這個region會被切分為兩個Hfile。

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

屬性:hbase.client.write.buffer

文件:hbase-site.xml

解釋:用于指定HBase客戶端緩存,增大該值可以減少RPC調用次數,但是會消耗更多內存,反之則反之。一般我們需要設定一定的緩存大小,以達到減少RPC次數的目的。

指定scan.next掃描HBase所獲取的行數

屬性:hbase.client.scanner.caching

文件:hbase-site.xml

解釋:用于指定scan.next方法獲取的默認行數,值越大,消耗內存越大。

6. 內存優(yōu)化

HBase操作過程中需要大量的內存開銷,畢竟Table是可以緩存在內存中的,一般會分配整個可用內存的70%給HBase的Java堆。但是不建議分配非常大的堆內存,因為GC過程持續(xù)太久會導致RegionServer處于長期不可用狀態(tài),一般16~48G內存就可以了,如果因為框架占用內存過高導致系統(tǒng)內存不足,框架一樣會被系統(tǒng)服務拖死。

7. JVM優(yōu)化

涉及文件:hbase-env.sh

并行GC

參數:·-XX:+UseParallelGC·

解釋:開啟并行GC

同時處理垃圾回收的線程數

參數:-XX:ParallelGCThreads=cpu_core – 1

解釋:該屬性設置了同時處理垃圾回收的線程數。

禁用手動GC

參數:-XX:DisableExplicitGC

解釋:防止開發(fā)人員手動調用GC

8. Zookeeper優(yōu)化優(yōu)化Zookeeper會話超時時間

參數:zookeeper.session.timeout

文件:hbase-site.xml

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

該值會直接關系到master發(fā)現服務器宕機的最大周期,默認值為30秒,如果該值過小,會在HBase在寫入大量數據發(fā)生而GC時,導致RegionServer短暫的不可用,從而沒有向ZK發(fā)送心跳包,最終導致認為從節(jié)點shutdown。一般20臺左右的集群需要配置5臺zookeeper。

十三、HBase 大廠面試題解析1. Hbase是怎么寫數據的?

Client寫入 -> 存入MemStore,一直到MemStore滿 -> Flush成一個StoreFile,直至增長到一定閾值 -> 觸發(fā)Compact合并操作 -> 多個StoreFile合并成一個StoreFile,同時進行版本合并和數據刪除 -> 當StoreFiles Compact后,逐步形成越來越大的StoreFile -> 單個StoreFile大小超過一定閾值后(默認10G),觸發(fā)Split操作,把當前Region Split成2個Region,Region會下線,新Split出的2個孩子Region會被HMaster分配到相應的HRegionServer 上,使得原先1個Region的壓力得以分流到2個Region上

由此過程可知,HBase只是增加數據,沒有更新和刪除操作,用戶的更新和刪除都是邏輯層面的,在物理層面,更新只是追加操作,刪除只是標記操作。

用戶寫操作只需要進入到內存即可立即返回,從而保證I/O高性能。

2. HDFS和HBase各自使用場景

首先一點需要明白:Hbase是基于HDFS來存儲的。

HDFS:

一次性寫入,多次讀取。

保證數據的一致性。

主要是可以部署在許多廉價機器中,通過多副本提高可靠性,提供了容錯和恢復機制。

HBase:

瞬間寫入量很大,數據庫不好支撐或需要很高成本支撐的場景。

數據需要長久保存,且量會持久增長到比較大的場景。

HBase不適用與有 join,多級索引,表關系復雜的數據模型。

大數據量(100s TB級數據)且有快速隨機訪問的需求。如:淘寶的交易歷史記錄。數據量巨大無容置疑,面向普通用戶的請求必然要即時響應。

業(yè)務場景簡單,不需要關系數據庫中很多特性(例如交叉列、交叉表,事務,連接等等)。

3. Hbase的存儲結構

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

4. 熱點現象(數據傾斜)怎么產生的,以及解決方法有哪些

熱點現象:

某個小的時段內,對HBase的讀寫請求集中到極少數的Region上,導致這些region所在的RegionServer處理請求量驟增,負載量明顯偏大,而其他的RgionServer明顯空閑。

熱點現象出現的原因:

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

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

熱點現象解決辦法:

為了避免寫熱點,設計rowkey使得不同行在同一個region,但是在更多數據情況下,數據應該被寫入集群的多個region,而不是一個。常見的方法有以下這些:

加鹽:在rowkey的前面增加隨機數,使得它和之前的rowkey的開頭不同。分配的前綴種類數量應該和你想使用數據分散到不同的region的數量一致。加鹽之后的rowkey就會根據隨機生成的前綴分散到各個region上,以避免熱點。

哈希:哈希可以使負載分散到整個集群,但是讀卻是可以預測的。使用確定的哈希可以讓客戶端重構完整的rowkey,可以使用get操作準確獲取某一個行數據

反轉:第三種防止熱點的方法時反轉固定長度或者數字格式的rowkey。這樣可以使得rowkey中經常改變的部分(最沒有意義的部分)放在前面。這樣可以有效的隨機rowkey,但是犧牲了rowkey的有序性。反轉rowkey的例子以手機號為rowkey,可以將手機號反轉后的字符串作為rowkey,這樣的就避免了以手機號那樣比較固定開頭導致熱點問題

時間戳反轉:一個常見的數據處理問題是快速獲取數據的最近版本,使用反轉的時間戳作為rowkey的一部分對這個問題十分有用,可以用 Long.Max_Value - timestamp 追加到key的末尾,例如[key][reverse_timestamp],[key]的最新值可以通過scan [key]獲得[key]的第一條記錄,因為HBase中rowkey是有序的,第一條記錄是最后錄入的數據。

比如需要保存一個用戶的操作記錄,按照操作時間倒序排序,在設計rowkey的時候,可以這樣設計[userId反轉][Long.Max_Value - timestamp],在查詢用戶的所有操作記錄數據的時候,直接指定反轉后的userId,startRow是[userId反轉][000000000000],stopRow是[userId反轉][Long.Max_Value - timestamp]

如果需要查詢某段時間的操作記錄,startRow是[user反轉][Long.Max_Value - 起始時間],stopRow是[userId反轉][Long.Max_Value - 結束時間]

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

5. HBase的 rowkey 設計原則

長度原則:100字節(jié)以內,8的倍數最好,可能的情況下越短越好。因為HFile是按照 keyvalue 存儲的,過長的rowkey會影響存儲效率;其次,過長的rowkey在memstore中較大,影響緩沖效果,降低檢索效率。最后,操作系統(tǒng)大多為64位,8的倍數,充分利用操作系統(tǒng)的最佳性能。

散列原則:高位散列,低位時間字段。避免熱點問題。

唯一原則:分利用這個排序的特點,將經常讀取的數據存儲到一塊,將最近可能會被訪問 的數據放到一塊。

6. HBase的列簇設計

原則:在合理范圍內能盡量少的減少列簇就盡量減少列簇,因為列簇是共享region的,每個列簇數據相差太大導致查詢效率低下。

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

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

在 hbase 中每當有 memstore 數據 flush 到磁盤之后,就形成一個 storefile,當 storeFile的數量達到一定程度后,就需要將 storefile 文件來進行 compaction 操作。

Compact 的作用:

合并文件

清除過期,多余版本的數據

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

Minor 操作只用來做部分文件的合并操作以及包括 minVersion=0 并且設置 ttl 的過期版本清理,不做任何刪除數據、多版本數據的清理工作。

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

聲明: 本文由入駐維科號的作者撰寫,觀點僅代表作者本人,不代表OFweek立場。如有侵權或其他問題,請聯(lián)系舉報。

發(fā)表評論

0條評論,0人參與

請輸入評論內容...

請輸入評論/評論長度6~500個字

您提交的評論過于頻繁,請輸入驗證碼繼續(xù)

暫無評論

暫無評論

    人工智能 獵頭職位 更多
    掃碼關注公眾號
    OFweek人工智能網
    獲取更多精彩內容
    文章糾錯
    x
    *文字標題:
    *糾錯內容:
    聯(lián)系郵箱:
    *驗 證 碼:

    粵公網安備 44030502002758號