HBase知識點總結

西柚發表於2021-11-23

一、HBase基礎

HBase 是一種建立在 Hadoop 檔案系統之上的分散式、可擴充套件、支援海量資料儲存的 NoSQL 資料庫。HBase 是 BigTable 的開源 Java 版本。是建立在 HDFS 之上,提供高可靠性、高效能、列儲存、可伸縮、實時讀寫 NoSql 的資料庫系統。

它介於 NoSql 和 RDBMS 之間,僅能通過主鍵(rowKey)和主鍵的 range 來檢索資料,僅支援單行事務(可通過 Hive 支援來實現多表 join 等複雜操作)。主要用來儲存結構化和半結構化的鬆散資料。HBase 查詢資料功能很簡單,不支援 join 等複雜操作,不支援複雜的事務(行級的事務)。

HBase 不限制儲存的資料的種類,允許動態的、靈活的資料模型,不用 SQL 語言,也不強調資料之間的關係。HBase被設計成在一個伺服器叢集上執行,可以相應地橫向擴充套件。利用 HBase 技術可在廉價 PC Server 上搭建起大規模結構化儲存叢集。

HBase 本身是一個資料模型,類似於谷歌的大表設計(BIgtable),可以提供快速隨機訪問海量結構化資料。它利用了 Hadoop 的檔案系統(HDFS)提供的容錯能力,提供對資料的隨機實時讀/寫訪問,是Hadoop檔案系統的一部分。 人們可以直接或通過 HBase 儲存 HDFS 資料,也可以使用 HBase 在 HDFS 讀取消費/隨機訪問資料。 HBase 利用 Hadoop 的 MapReduce 來處理海量資料。協同服務方面 Google Bigtable 利用 Chubby 來支援 ,HBase 的 Zookeeper 與之對應。

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

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

二、 HDFS 、Hive 、HBase 三者對比

1、HDFS 與 HBase 對比

HDFS

  • 為分散式儲存提供檔案系統
  • 針對儲存大尺寸的檔案進行優化,不需要對 HDFS 上的檔案進行隨機讀寫
  • 直接使用檔案
  • 資料模型不靈活
  • 使用檔案系統和處理框架
  • 優化一次寫入,多次讀取的方式

HBase

  • 提供表狀的面向列的資料儲存
  • 針對表狀資料的隨機讀寫進行優化
  • 使用 key-value 運算元據
  • 提供靈活的資料模型
  • 使用表狀儲存,支援 MapReduce,依賴 HDFS
  • 優化了多次讀,以及多次寫

2、Hive 與 HBase 對比

Hive

(1) 資料倉儲

Hive 的本質其實就相當於將 HDFS 中已經儲存的檔案在 Mysql 中做了一個雙射關係,以方便使用 HQL 去管理查詢。

(2) 用於資料分析、清洗

Hive 適用於離線的資料分析和清洗,延遲較高。

(3) 基於 HDFS、MapReduce

Hive 儲存的資料依舊在 DataN ode 上,編寫的 HQL 語句終將是轉換為 MapReduce 程式碼執行。

HBase

(1) 資料庫

是一種面向列族儲存的非關係型資料庫。

(2) 用於儲存結構化和非結構化的資料

適用於單表非關係型資料的儲存,不適合做關聯查詢,類似 JOIN 等操作。

(3) 基於 HDFS

資料持久化儲存的體現形式是 HFile,存放於 DataNode 中,被 ResionServer 以 region 的形式進行管理。

(4) 延遲較低,接入線上業務使用

面對大量的企業資料,HBase 可以直線單表大量資料的儲存,同時提供了高效的資料訪問速度。

三、HBase在商業專案中的能力

每天:
(1) 訊息量:傳送和接收的訊息數超過60億
(2) 將近1000億條資料的讀寫
(3) 高峰期每秒150萬左右操作
(4) 整體讀取資料佔有約55%,寫入佔有45%
(5) 超過2PB的資料,涉及冗餘共6PB資料
(6) 資料每月大概增長300千兆位元組。

四、HBase系統架構

image.png

架構角色:

(1)Region Server

Region Server 為 Region 的管理者,其實現類為 HRegionServer,主要作用如下:

  • 監控 RegionServer
  • 處理 RegionServer 故障轉移
  • 處理後設資料的變更
  • 處理 region 的分配或移除
  • 在空閒時間進行資料的負載均衡
  • 通過 Zookeeper 釋出自己的位置給客戶

(2)Master

Master 是所有 Region Server 的管理者,其實現類為 HMaster,主要作用如下:

  • 負責儲存 HBase 的實際資料
  • 處理分配給它的 Region
  • 重新整理快取到 HDFS
  • 維護 HLog
  • 執行壓縮
  • 負責處理 Region 分片

(3)Zookeeper

HBase 通過 Zookeeper 來做 Master 的高可用、RegionServer 的監控、後設資料的入口以及叢集配置的維護等工作。

image.png

(4)HDFS

HDFS 為 HBase 提供最終的底層資料儲存服務,同時為 HBase 提供高可用的支援。

(5)Client

包含訪問HBase的介面,並維護cache來加快對HBase的訪問。

HRegionServer 元件

1. Write-Ahead logs

HBase 的修改記錄。由於資料要經 MemStore 排序後才能刷寫到 HFile,但把資料儲存在記憶體中會有很高的概率導致資料丟失,為了解決這個問題,資料會先寫在一個叫做 Write-Ahead logfile 的檔案中,然後再寫入記憶體中。所以在系統出現故障的時候,資料可以通過這個日誌檔案重建。

2. HFile

這是在磁碟上儲存原始資料的實際的物理檔案,是實際的儲存檔案。

3. StoreFile

HFile 儲存在 Store 中,一個 Store 對應 HBase 表中的一個列族。儲存實際資料的物理檔案,StoreFile 以 HFile 的形式儲存在 HDFS 上。每個 Store 會有一個或多個 StoreFile(HFile),資料在每個 StoreFile 中都是有序的。

4. MemStore

寫快取,由於 HFile 中的資料要求是有序的,所以資料是先儲存在 MemStore 中,排好序後,等到達刷寫時機才會刷寫到 HFile,每次刷寫都會形成一個新的 HFile。

5. Region

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

五、HBase shell操作

1、基本操作

1.進入 HBase 客戶端命令列
bin/hbase shell
2.檢視幫助命令
hbase(main):001:0> help
3.檢視當前資料庫中有哪些表
hbase(main):002:0> list

2、表的操作

1.建立表
hbase(main):002:0> create 'student','info'
2.插入資料到表
hbase(main):003:0> put 'student','1001','info:sex','male'
hbase(main):004:0> put 'student','1001','info:age','18'
hbase(main):005:0> put 'student','1002','info:name','Janna'
hbase(main):006:0> put 'student','1002','info:sex','female'
hbase(main):007:0> put 'student','1002','info:age','20'
3.掃描檢視錶資料
hbase(main):008:0> scan 'student'
hbase(main):009:0> scan 'student',{STARTROW => '1001', STOPROW =>
'1001'}
hbase(main):010:0> scan 'student',{STARTROW => '1001'}
4.檢視錶結構
hbase(main):011:0> describe ‘student’
5.更新指定欄位的資料
hbase(main):012:0> put 'student','1001','info:name','Nick'
hbase(main):013:0> put 'student','1001','info:age','100'
6.檢視“指定行”或“指定列族:列”的資料
hbase(main):014:0> get 'student','1001'
hbase(main):015:0> get 'student','1001','info:name'
7.統計表資料行數
hbase(main):021:0> count 'student'
8.刪除資料
刪除某 rowkey 的全部資料:
hbase(main):016:0> deleteall 'student','1001'
刪除某 rowkey 的某一列資料:
hbase(main):017:0> delete 'student','1002','info:sex'
9.清空表資料
hbase(main):018:0> truncate 'student'
提示:清空表的操作順序為先 disable,然後再 truncate。
10.刪除表
首先需要先讓該表為 disable 狀態:
hbase(main):019:0> disable 'student'
然後才能 drop 這個表:
hbase(main):020:0> drop 'student'
提示:如果直接 drop 表,會報錯:ERROR: Table student is enabled. Disable it first.
11.變更表資訊
將 info 列族中的資料存放 3 個版本:
hbase(main):022:0> alter 'student',{NAME=>'info',VERSIONS=>3}
hbase(main):022:0> get
'student','1001',{COLUMN=>'info:name',VERSIONS=>3}

六、HBase使用場景

首先,HBase 是基於 HDFS 來儲存的。

HDFS

  1. 一次性寫入,多次讀取。
  2. 保證資料的一致性。
  3. 主要是可以部署在許多廉價機器中,通過多副本提高可靠性,提供了容錯和恢復機制。

HBase

  1. 瞬間寫入量很大,資料庫不好支撐或需要很高成本支撐的場景。
  2. 資料需要長久儲存,且量會持久增長到比較大的場景。
  3. HBase 不適用與有 join,多級索引,表關係複雜的資料模型。
  4. 大資料量且有快速隨機訪問的需求。如:淘寶的交易歷史記錄。資料量巨大無容置疑,面向普通使用者的請求必然要即時響應。
  5. 業務場景簡單,不需要關聯式資料庫中很多特性(例如交叉列、交叉表,事務,連線等等)。

七、HBase的表資料模型

HBase 邏輯表結構
image.png

HBase 物理儲存結構
image.png

(1)Name Space

名稱空間,類似於關係型資料庫的 DatabBase 概念,每個名稱空間下有多個表。HBase有兩個自帶的名稱空間,分別是hbase 和 default,hbase 中存放的是 HBase 內建的表,default 表是使用者預設使用的名稱空間。

(2)Region

類似於關係型資料庫的表概念。不同的是,HBase 定義表時只需要宣告列族即可,不需要宣告具體的列。這意味著,往 HBase 寫入資料時,欄位可以動態、按需指定。因此,和關係型資料庫相比,HBase 能夠輕鬆應對欄位變更的場景。

(3)rowKey

HBase 表中的每行資料都由一個 RowKey 和多個 Column(列)組成,資料是按照 RowKey的字典順序儲存的,並且查詢資料時只能根據 RowKey 進行檢索,所以 RowKey 的設計十分重要。與 nosql 資料庫一樣,rowKey 是用來檢索記錄的主鍵。訪問 hbase table 中的行,只有三種方式:

  • 通過單個 rowKey 訪問
  • 通過 rowKey 的 range
  • 全表掃描

rowKey 行鍵可以是任意字串(最大長度是 64KB,實際應用中長度一般為10-100bytes),在 hbase 內部,rowKey 儲存為位元組陣列。Hbase 會對錶中的資料按照 rowkey 排序(字典順序)儲存時,資料按照 Row key 的字典序(byte order)排序儲存。設計 key 時,要充分排序儲存這個特性,將經常一起讀取的行儲存放到一起。(位置相關性)。

(4) Column Family

HBase 表中的每個列,都歸屬於某個列族。列族是表的 schema 的一部分(而列不是),必須在使用表之前定義。列名都以列族作為字首。例如 courses:history , courses:math 都屬於courses 這個列族。訪問控制、磁碟和記憶體的使用統計都是在列族層面進行的。 列族越多,在取一行資料時所要參與 IO、搜尋的檔案就越多,所以,如果沒有必要,不要設定太多的列族。

(5)Column

HBase 中的每個列都由 Column Family(列族)和 Column Qualifier(列限定符)進行限定,例如 info:name,info:age。建表時,只需指明列族,而列限定符無需預先定義。

(6)Time Stamp

用於標識資料的不同版本(version),每條資料寫入時,如果不指定時間戳,系統會自動為其加上該欄位,其值為寫入 HBase 的時間。HBase 中通過 row 和 columns 確定的為一個存貯單元稱為 cell。每個 cell 都儲存著同一份資料的多個版本。版本通過時間戳來索引。時間戳的型別是 64 位整型。時間戳可以由 hbase(在資料寫入時自動 )賦值,此時時間戳是精確到毫秒的當前系統時間。時間戳也可以由客戶顯式賦值。如果應用程式要避免資料版本衝突,就必須自己生成具有唯一性的時間戳。每個 cell 中,不同版本的資料按照時間倒序排序,即最新的資料排在最前面。

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

  • 儲存資料的最後 n 個版本
  • 儲存最近一段時間內的版本(設定資料的生命週期 TTL)。

使用者可以針對每個列族進行設定。

(7)Cell

由{rowkey, column Family:column Qualifier, time Stamp} 唯一確定的單元。cell 中的資料是沒有型別的,全部是位元組碼形式存貯。

八、HBase讀寫過程

讀流程

image.png

(1)Client 先訪問 zookeeper,獲取 hbase:meta 表位於哪個 Region Server。
(2)訪問對應的 Region Server,獲取 hbase:meta 表,根據讀請求的 namespace:table/rowkey,查詢出目標資料位於哪個 Region Server 中的哪個 Region 中。並將該 table 的 region 資訊以及 meta 表的位置資訊快取在客戶端的 meta cache,方便下次訪問。
(3)與目標 Region Server 進行通訊。
(4)分別在 Block Cache(讀快取),MemStore 和 Store File(HFile)中查詢目標資料,並將查到的所有資料進行合併。此處所有資料是指同一條資料的不同版本(time stamp)或者不同的型別(Put/Delete)。
(5) 將從檔案中查詢到的資料塊(Block,HFile 資料儲存單元,預設大小為 64KB)快取到 Block Cache。
(6)將合併後的最終結果返回給客戶端。

寫流程

image.png

(1)Client 先訪問 zookeeper,獲取 hbase:meta 表位於哪個 Region Server。
(2)訪問對應的 Region Server,獲取 hbase:meta 表,根據讀請求的 namespace:table/rowkey,查詢出目標資料位於哪個 Region Server 中的哪個 Region 中。並將該 table 的 region 資訊以及 meta 表的位置資訊快取在客戶端的 meta cache,方便下次訪問。
(3)與目標 Region Server 進行通訊;
(4)將資料順序寫入(追加)到 WAL;
(5)將資料寫入對應的 MemStore,資料會在 MemStore 進行排序;
(6)向客戶端傳送 ack;
(7)等達到 MemStore 的刷寫時機後,將資料刷寫到 HFile。

九、HRegionServer 當機處理

0、概述

正因為機器的配置並不是太好加上網路硬碟等各方面的原因,機器當機的概率就會相對比較大。RegionServer作為HBase叢集中實際的執行節點,不可避免地也會出現當機。

當機並不十分可怕,因為不會丟資料。HBase叢集中一臺RegionServer當機(實指RegionServer程式掛掉)並不會導致已經寫入的資料丟失,和MySQL等資料庫一樣,HBase採用WAL機制保證這點:它會先寫HLog,再寫快取,快取寫滿後一起落盤。即使意外當機導致很多快取資料沒有及時落盤,也可以通過HLog日誌恢復出來。

可是沒有資料丟失並不意味著當機對業務方沒有任何影響。眾所周知,RegionServer當機是由Zookeeper首先感知到的,而Zookeeper感知到RegionServer當機事件是需要一定時間的。在這段時間內,所有的讀寫路由還會正常落到它上面,這些讀寫必然都會失敗。

1、處理流程

(1)RegionServer發生當機,RegionServer註冊到Zookeeper 的 /hbase/rs節點下的臨時節點就會離線,Zookeeper第一時間通知Master進行失效備援。

(2)Master首先會將這臺RegionServer上所有Region移到其他RegionServer上,再將HLog分發給其他RegionServer進行回放。

(3)再修改路由,業務方的讀寫恢復正常。

2、實踐

(1)排查RegionServer日誌

(2)排查系統監控

十、預分割槽

0、定義

每一個 region 維護著 StartRow 與 EndRow,如果加入的資料符合某個 Region 維護的 RowKey 範圍,則該資料交給這個 Region 維護。將新資料所要投放的分割槽提前規劃,以提高 HBase 效能,避免產生熱點問題。其中,規劃的分割槽數與未來半年或一年的資料量和機器規模有關。

1、預分割槽的優點

  • 增加資料讀寫效率
  • 負載均衡,防止資料傾斜/熱點問題
  • 方便叢集容災排程 region
  • 優化 Map 數量

2、預分割槽的幾種方式

(1)手動設定預分割槽

create 'staff1','info','partition1',SPLITS => ['1000','2000','3000','4000']

(2)生成 16 進位制序列預分割槽

create 'staff2','info','partition2',{NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}

(3)按照檔案中設定的規則預分割槽

建立 splits.txt 檔案內容如下:
aaaa
bbbb
cccc
dddd

然後執行:
create 'staff3','partition3',SPLITS_FILE => 'splits.txt'

(4)使用 JavaAPI 建立預分割槽

//自定義演算法,產生一系列 hash 雜湊值儲存在二維陣列中
byte[][] splitKeys = 某個雜湊值函式
//建立 HbaseAdmin 例項
HBaseAdmin hAdmin = new HBaseAdmin(HbaseConfiguration.create());
//建立 HTableDescriptor 例項
HTableDescriptor tableDesc = new HTableDescriptor(tableName);
//通過 HTableDescriptor 例項和雜湊值二維陣列建立帶有預分割槽的 Hbase 表
hAdmin.createTable(tableDesc, splitKeys);

十一、HRegion的負載均衡

HBase使用RowKey將表水平切割成多個 Hregion,每個HRegion都紀錄了它的StartKey和 EndKey,Client可以通過HMaster快速的定位每個 RowKey在哪個HRegion中,HRegion由HMaster分配到相應在HRegion Split後,兩個新的HRegion 最初會和之前的父HRegion在相同的 HRegionServer上,出於負載均衡的考慮,HMaster可能會將其中的一個甚至兩個重新分配的其他的 HRegionServer中,此時會引起有些HRegionServer處理的數 據在其他節點上 ,直到下一次Major Compaction將資料從遠端的節點移動到本地節點。這就是Hregion的負載均衡。

十二、rowKey設計

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

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

  • 通過 get 方式,指定 rowkey 獲取唯一一條記錄;
  • 通過 scan 方式,設定 startRow 和 stopRow 引數進行範圍匹配;
  • 全表掃描,即直接掃描整張表中所有行記錄。

HBase rowKey 設計原則

1、長度原則

rowkey 是一個二進位制碼流,可以是任意字串,最大長度 64kb,實際應用中一般為 10-100bytes,以 byte[]形式儲存,一般設計成定長。建議越短越好,不要超過 16 個位元組,原因如下:

  • 資料的持久化檔案 HFile 中是按照 KeyValue 儲存的,如果 rowkey 過長,比如超過 100 位元組,1000w 行資料,光 rowkey 就要佔用:100 * 1000w=10 億個位元組,將近 1G 資料,這樣會極大影響 HFile 的儲存效率。
  • MemStore 將快取部分資料到記憶體,如果 rowkey 欄位過長,記憶體的有效利用率就會降低,系統不能快取更多的資料,這樣會降低檢索效率。

2、雜湊原則

如果 rowkey 按照時間戳的方式遞增,不要將時間放在二進位制碼的前面,建議將 rowKey 的高位作為雜湊欄位,由程式隨機生成,低位放時間欄位,這樣將提高資料均衡分佈在每個 RegionServer,以實現負載均衡的機率。
如果沒有雜湊欄位,首欄位直接是時間資訊,所有的資料都會集中在一個 RegionServer 上,這樣在資料檢索的時候負載會集中在個別的 RegionServer 上,造成熱點問題,會降低查詢效率。

3、唯一原則

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

其他一些設計建議:

  • 儘量減少行鍵和列族的大小。在 HBase 中,value 永遠和它的 key 一起傳輸的。當具體的值在系統間傳輸時,它的 rowkey,列名,時間戳也會一起傳輸。如果你的 rowkey 和列名很大,這個時候它們將會佔用大量的儲存空間。
  • 列族儘可能越短越好,最好是一個字元。
  • 冗長的屬性名雖然可讀性好,但是更短的屬性名儲存在 HBase 中會更好。

十三、HBase 中熱點/資料傾斜的產生原因及解決方法

1、什麼是熱點

HBase 中的行是按照 rowkey 的字典順序排序的,這種設計優化了 scan 操作,可以將相關的行以及會被一起讀取的行存取在臨近位置,便於 scan。然而糟糕的 rowkey 設計是熱點的源頭。熱點發生在大量的 client 直接訪問叢集的一個或極少數個節點(訪問可能是讀,寫或者其他操作)。大量訪問會使熱點 region 所在的單個機器超出自身承受能力,引起效能下降甚至 region 不可用,這也會影響同一個 RegionServer 上的其他 region,由於主機無法服務其他 region 的請求。設計良好的資料訪問模式以使叢集被充分,均衡的利用。為了避免寫熱點,設計 rowkey 使得不同行在同一個 region,但是在更多資料情況下,資料應該被寫入叢集的多個 region,而不是一個。

2、常見的避免熱點的方法以及它們的優缺點

(1) 加鹽

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

(2) 雜湊

雜湊會使同一行永遠用一個字首加鹽。雜湊也可以使負載分散到整個叢集,但是讀卻是可以預測的。使用確定的雜湊可以讓客戶端重構完整的 rowkey,可以使用 get 操作準確獲取某一個行資料。

(3) 反轉

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

(4) 時間戳反轉

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

十四、HBase的協處理器

0、背景

HBase 作為列族資料庫最經常被人詬病的特性包括:無法輕易建立“二級索引”,難以執 行求和、計數、排序等操作。如果做一些簡單的相加或者聚合計算的時候直接將計算過程放置在 server 端,能夠減少通訊開銷,從而獲 得很好的效能提升。於是,HBase 在 0.92 之後引入了協處理器(coprocessors)實現一些新特性:能夠輕易建立二次索引、複雜過濾器(謂詞下推)以及訪問控制等。

1、兩種協處理器:observer 和 endpoint

1.1 Observer

Observer 類似於傳統資料庫中的觸發器,當發生某些事件的時候這類協處理器會被 Server 端呼叫。Observer Coprocessor 就是一些散佈在 HBase Server 端程式碼中的 hook 鉤子, 在固定的事件發生時被呼叫。比如:put 操作之前有鉤子函式 prePut,該函式在 put 操作執 行前會被 Region Server 呼叫;在 put 操作之後則有 postPut 鉤子函式。

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

  • RegionObserver:提供客戶端的資料操縱事件鉤子:Get、Put、Delete、Scan 等。
  • WALObserver:提供 WAL 相關操作鉤子。
  • MasterObserver:提供 DDL-型別的操作鉤子。如建立、刪除、修改資料表等。

下圖是以 RegionObserver 為例子講解 Observer 這種協處理器的原理:
image.png

(1)客戶端發出 put 請求

(2)該請求被分派給合適的 RegionServer 和 region

(3)coprocessorHost 攔截該請求,然後在該表上登記的每個 RegionObserver 上呼叫 prePut()

(4)如果沒有被 prePut()攔截,該請求繼續送到 region,然後進行處理

(5)region 產生的結果再次被 CoprocessorHost 攔截,呼叫 postPut()

(6)假如沒有 postPut()攔截該響應,最終結果被返回給客戶端

1.2 Endpoint

Endpoint 協處理器類似傳統資料庫中的儲存過程,客戶端可以呼叫這些 Endpoint 協處 理器執行一段 Server 端程式碼,並將 Server 端程式碼的結果返回給客戶端進一步處理,最常見 的用法就是進行聚集操作。如果沒有協處理器,當使用者需要找出一張表中的最大資料,即 max 聚合操作,就必須進行全表掃描,在客戶端程式碼內遍歷掃描結果,並執行求最大值的 操作。這樣的方法無法利用底層叢集的併發能力,而將所有計算都集中到 Client 端統一執行, 勢必效率低下。利用 Coprocessor,使用者可以將求最大值的程式碼部署到 HBase Server 端,HBase 將利用底層 cluster 的多個節點併發執行求最大值的操作。即在每個 Region 範圍內執行求最 大值的程式碼,將每個 Region 的最大值在 Region Server 端計算出,僅僅將該 max 值返回給客 戶端。在客戶端進一步將多個 Region 的最大值進一步處理而找到其中的最大值。這樣整體 的執行效率就會提高很多。

EndPoint 的工作原理如圖:
image.png

1.3 對比

Observer 類似於 RDBMS 中的觸發器,主要在服務端工作
Endpoint 類似於 RDBMS 中的儲存過程,主要在服務端工作

Observer 允許叢集在正常的客戶端操作過程中可以有不同的行為表現
Endpoint 允許擴充套件叢集的能力,對客戶端應用開放新的運算命令

Observer 可以實現許可權管理、優先順序設定、監控、ddl 控制、二級索引等功能
Endpoint 可以實現 min、max、avg、sum、distinct、group by 等功能

2、協處理器載入方式

協處理器的載入方式有兩種:靜態載入方式(Static Load)和動態載入方式(Dynamic Load)

靜態載入的協處理器稱之為 System Coprocessor
動態載入的協處理器稱之為 Table Coprocessor

十五、二級索引

為什麼需要HBse二級索引

由於 HBase 的查詢比較弱,如果需要實現類似於

select name,salary,count(1),max(salary) from user group by name,salary order by salary

等這樣的複雜性的統計需求,基本上不可能,或者說比較困難,所以我們在使用 HBase 的時候,一般都會藉助二級索引的方案來進行實現。HBase 的一級索引就是 rowKey,我們只能通過 rowkey 進行檢索。如果要對庫裡的非rowkey欄位進行資料檢索和查詢,往往要通過 MapReduce/Spark 等分散式計算框架進行,硬體資源消耗和時間延遲都會比較高。

為了HBase的資料查詢更高效、適應更多的場景, 諸如使用非rowkey欄位檢索也能做到秒級響應,或者支援各個欄位進行模糊查詢和多欄位組合查詢等, 因此需要在HBase上面構建二級索引, 以滿足現實中更復雜多樣的業務需求。

HBase 的二級索引方案:

1、基於Coprocessor方案

基於Coprocessor實現二級索引的大致思路:構建一份“索引”的對映關係,儲存在另一張hbase表或者其他DB裡面。業界比較知名的基於Coprocessor的開源方案:

  • 華為的hindex:基於0.94版本,當年剛出來的時候比較火,但是版本較舊,GitHub專案地址最近這幾年就沒更新過。
  • Apache Phoenix: 功能圍繞著SQL on HBase,支援和相容多個HBase版本, 二級索引只是其中一塊功能。 二級索引的建立和管理直接有SQL語法支援,使用起來很簡便, 該專案目前社群活躍度和版本更新迭代情況都比較好。

Apache Phoenix 在目前開源的方案中,是一個比較優的選擇。主打SQL on HBase,基於 SQL 能完成 HBase 的 CRUD 操作,支援 JDBC 協議。 Apache Phoenix 在 Hadoop 生態裡面位置:

image.png

Phoenix二級索引特點:

  • Covered Indexes(覆蓋索引) :把關注的資料欄位也附在索引表上,只需要通過索引表就能返回所要查詢的資料(列), 所以索引的列必須包含所需查詢的列(SELECT的列和WHRER的列)。
  • Functional indexes(函式索引): 索引不侷限於列,支援任意的表示式來建立索引。
  • Global indexes(全域性索引):適用於讀多寫少場景。通過維護全域性索引表,所有的更新和寫操作都會引起索引的更新,寫入效能受到影響。 在讀資料時,Phoenix SQL會基於索引欄位,執行快速查詢。
  • Local indexes(本地索引):適用於寫多讀少場景。 在資料寫入時,索引資料和表資料都會儲存在本地。在資料讀取時, 由於無法預先確定region的位置,所以在讀取資料時需要檢查每個region(以找到索引資料),會帶來一定效能(網路)開銷。

基於Coprocessor的方案優缺點:

優點: 基於Coprocessor的方案,從開發設計的角度看, 把很多對二級索引管理的細節都封裝在的Coprocessor具體實現類裡面, 這些細節對外面讀寫的人是無感知的,簡化了資料訪問者的使用。

缺點: 但是Coprocessor的方案入侵性比較強, 增加了在Regionserver內部需要執行和維護二級索引關係表的程式碼邏輯等,對Regionserver的效能會有一定影響。

2、非Coprocessor方案

選擇不基於Coprocessor開發,自行在外部構建和維護索引關係也是另外一種方式。

常見的是採用底層基於Apache Lucene的Elasticsearch(下面簡稱ES)或Apache Solr ,來構建強大的索引能力、搜尋能力, 例如支援模糊查詢、全文檢索、組合查詢、排序等。

十六、調優

1、通用優化

(1)NameNode 的後設資料備份使用 SSD。

(2)定時備份 NameNode 上的後設資料,每小時或者每天備份,如果資料極其重要,可以 5~10 分鐘備份一次。備份可以通過定時任務複製後設資料目錄即可。

(3)為 NameNode 指定多個後設資料目錄,使用 dfs.name.dir 或者dfs.namenode.name.dir 指定。一個指定本地磁碟,一個指定網路磁碟。這樣可以提供後設資料的冗餘和健壯性,以免發生故障。

(4)設定 dfs.namenode.name.dir.restore 為 true,允許嘗試恢復之前失敗的 dfs.namenode.name.dir 目錄,在建立 checkpoint 時做此嘗試,如果設定了多個磁碟,建議允許。

(5)NameNode 節點必須配置為 RAID1(映象盤)結構。

(6)保持 NameNode 日誌目錄有足夠的空間,這些日誌有助於幫助你發現問題。

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

2、Linux 優化

(1)開啟檔案系統的預讀快取(set readahead)可以提高讀取速度

$ sudo blockdev --setra 32768 /dev/sda

(2)關閉程式睡眠池

$ sudo sysctl -w vm.swappiness=0

3、HDFS 優化(hdfs-site.xml)

(1)保證 RPC 呼叫會有較多的執行緒數

屬性:dfs.namenode.handler.count
解釋:該屬性是 NameNode 服務預設執行緒數,的預設值是 10,根據機器的可用記憶體可以調整為 50~100。

屬性:dfs.datanode.handler.count
解釋:該屬性預設值為 10,是 DataNode 的處理執行緒數,如果 HDFS 客戶端程式讀寫請求比較多,可以調高到 15~20,設定的值越大,記憶體消耗越多,不要調整過高,一般業務中,5~10 即可。

(2)副本數的調整

屬性:dfs.replication
解釋:如果資料量巨大,且不是非常之重要,可以調整為 2~3,如果資料非常之重要,可以調整為 3~5。

(3)檔案塊大小的調整

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

4、MapReduce 優化(mapred-site.xml)

(1)Job 任務服務執行緒數調整

mapreduce.jobtracker.handler.count
該屬性是 Job 任務執行緒數,預設值是 10,根據機器的可用記憶體可以調整為 50~100。

(2)HTTP

屬性:mapreduce.tasktracker.http.threads
解釋:定義 HTTP 伺服器工作執行緒數,預設值為 40,對於大叢集可以調整到 80~100。

(3)檔案排序合併優化

屬性:mapreduce.task.io.sort.factor
解釋:檔案排序時同時合併的資料流的數量,這也定義了同時開啟檔案的個數,預設值為 10,如果調高該引數,可以明顯減少磁碟 IO,即減少檔案讀取的次數。

(4)設定任務併發

屬性:mapreduce.map.speculative
解釋:該屬性可以設定任務是否可以併發執行,如果任務多而小,該屬性設定為 true 可以明顯加快任務執行效率,但是對於延遲非常高的任務,建議改為 false,這就類似於迅雷下載。

(5)MR 輸出資料的壓縮

屬性:mapreduce.map.output.compress、mapreduce.output.fileoutputformat.compress
解釋:對於大叢集而言,建議設定 Map-Reduce 的輸出為壓縮的資料,而對於小叢集,則不需要。

(6)優化 Mapper 和 Reducer 的個數
屬性:mapreduce.tasktracker.map.tasks.maximum、mapreduce.tasktracker.reduce.tasks.maximum
解釋:以上兩個屬性分別為一個單獨的 Job 任務可以同時執行的 Map 和 Reduce 的數量。設定上面兩個引數時,需要考慮 CPU 核數、磁碟和記憶體容量。假設一個 8 核的 CPU,業務內容非常消耗 CPU,那麼可以設定 map 數量為 4,如果該業務不是特別消耗 CPU 型別的,那麼可以設定 map 數量為 40,reduce 數量為 20。這些引數的值修改完成之後,一定要觀察是否有較長等待的任務,如果有的話,可以減少數量以加快任務執行,如果設定一個很大的值,會引起大量的上下文切換,以及記憶體與磁碟之間的資料交換,這裡沒有標準的配置數值,需要根據業務和硬體配置以及經驗來做出選擇。在同一時刻,不要同時執行太多的 MapReduce,這樣會消耗過多的記憶體,任務會執行的非常緩慢,我們需要根據 CPU 核數,記憶體容量設定一個 MR 任務併發的最大值,使固定資料量的任務完全載入到記憶體中,避免頻繁的記憶體和磁碟資料交換,從而降低磁碟 IO,提高效能。

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

5、HBase 優化

(1)優化 DataNode 允許的最大檔案開啟數

屬性:dfs.datanode.max.transfer.threads
檔案:hdfs-site.xml
解釋:HBase 一般都會同一時間操作大量的檔案,根據叢集的數量和規模以及資料動作,設定為 4096 或者更高。預設值:4096

(2)優化延遲高的資料操作的等待時間

屬性:dfs.image.transfer.timeout
檔案:hdfs-site.xml
解釋:如果對於某一次資料操作來講,延遲非常高,socket 需要等待更長的時間,建議把該值設定為更大的值(預設 60000 毫秒),以確保 socket 不會被 timeout 掉。

(3)優化資料的寫入效率

屬性:mapreduce.map.output.compress、mapreduce.map.output.compress.codec
檔案:mapred-site.xml
解釋:開啟這兩個資料可以大大提高檔案的寫入效率,減少寫入時間。第一個屬性值修改為 true,第二個屬性值修改為:
org.apache.hadoop.io.compress.GzipCodec

(4)優化 DataNode 儲存

屬性:dfs.datanode.failed.volumes.tolerated
檔案:hdfs-site.xml
解釋:預設為0,意思是當DataNode中有一個磁碟出現故障,則會認為該 DataNode shutdown 了。如果修改為 1,則一個磁碟出現故障時,資料會被複制到其他正常的 DataNode 上,當前的 DataNode 繼續工作。

(5)設定 RPC 監聽數量

屬性:hbase.regionserver.handler.count
檔案:hbase-site.xml
解釋:預設值為 30,用於指定 RPC 監聽的數量,可以根據客戶端的請求數進行調整,讀寫請求較多時,增加此值。

(6)優化 HStore 檔案大小

屬性:hbase.hregion.max.filesize
檔案:hbase-site.xml
解釋:預設值 10737418240(10GB),如果需要執行 HBase 的 MR 任務,可以減小此值,因為一個 region 對應一個 map 任務,如果單個 region 過大,會導致 map 任務執行時間過長。該值的意思就是,如果 HFile 的大小達到這個數值,則這個 region 會被切分為兩個 Hfile。

(7)優化 hbase 客戶端快取

屬性:hbase.client.write.buffer
檔案:hbase-site.xml
解釋:用於指定 HBase 客戶端快取,增大該值可以減少 RPC 呼叫次數,但是會消耗更多記憶體,反之則反之。一般我們需要設定一定的快取大小,以達到減少 RPC 次數的目的。

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

屬性:hbase.client.scanner.caching
檔案:hbase-site.xml
解釋:用於指定 scan.next 方法獲取的預設行數,值越大,消耗記憶體越大。

6、記憶體優化

HBase 操作過程中需要大量的記憶體開銷,畢竟 Table 是可以快取在記憶體中的,一般會分配整個可用記憶體的 70% 給 HBase 的 Java 堆。但是不建議分配非常大的堆記憶體,因為 GC 過程持續太久會導致 RegionServer 處於長期不可用狀態,一般
16~48G 記憶體就可以了,如果因為框架佔用記憶體過高導致系統記憶體不足,框架一樣會被系統服務拖死。

7、JVM 優化(hbase-env.sh)

(1)並行 GC

引數:·-XX:+UseParallelGC·
解釋:開啟並行 GC。

(2)同時處理垃圾回收的執行緒數

引數:-XX:ParallelGCThreads=cpu_core – 1
解釋:該屬性設定了同時處理垃圾回收的執行緒數。

(3)禁用手動 GC

引數:-XX:DisableExplicitGC
解釋:防止開發人員手動呼叫 GC。

8、Zookeeper 優化

優化 Zookeeper 會話超時時間

引數:zookeeper.session.timeout
檔案:hbase-site.xml
解釋:該值會直接關係到 master 發現伺服器當機的最大週期,預設值為 30 秒,如果該值過小,會在 HBase 在寫入大量資料發生而 GC 時,導致 RegionServer 短暫的不可用,從而沒有向 ZK 傳送心跳包,最終導致認為從節點 shutdown。一般 20 臺左右的叢集需要配置 5 臺 Zookeeper。

相關文章