1. 程式人生 > >HBase原理部分

HBase原理部分

目錄

1、HBase底層原理

1.1、系統架構

1.2、物理儲存

1.2.1、整體物理結構

1.2.2、StoreFile 和HFile結構

1.2.3、MemStore 和 StoreFile

1.2.4、HLog(WAL)

1.3、定址機制

1.3.1、老的Region定址方式

1.3.2、新的Region定址方式

1.4、讀寫過程

1.4.1、讀請求過程

1.4.2、寫請求過程

1.5、RegionServer工作機制

1.6、Master工作機制

2、HBase高階應用

2.1、建表高階屬性

2.2、表設計


1、HBase底層原理

1.1、系統架構

上面這張圖是有一個錯誤點:應該是每一個 RegionServer 就只有一個 HLog,而不是一個 Region 有一個 HLog。下面這張圖是正確的。

Client職責

1、HBase 有兩張特殊表:
.META.:記錄了使用者所有表拆分出來的的 Region 對映資訊,.META.可以有多個 Regoin

-ROOT-:記錄了.META.表的 Region 資訊,-ROOT-只有一個 Region,無論如何不會分裂

 

2、Client 訪問使用者資料前需要首先訪問 ZooKeeper,找到-ROOT-表的 Region 所在的位置,然後訪問-ROOT-表,接著訪問.META.表,最後才能找到使用者資料的位置去訪問,中間需要多次網路操作,不過 client 端會做 cache 快取。

ZooKeeper職責

1、ZooKeeper 為 HBase 提供 Failover 機制,選舉 Master,避免單點 Master 單點故障問題

2、儲存所有 Region 的定址入口:-ROOT-表在哪臺伺服器上。-ROOT-這張表的位置資訊

3、實時監控 RegionServer 的狀態,將 RegionServer 的上線和下線資訊實時通知給 Master

4、儲存 HBase 的 Schema,包括有哪些 Table,每個 Table 有哪些 Column Family

Master職責

1、為 RegionServer 分配 Region
2、負責 RegionServer 的負載均衡
3、發現失效的 RegionServer 並重新分配其上的 Region
4、HDFS 上的垃圾檔案(HBase)回收
5、處理 Schema 更新請求(表的建立,刪除,修改,列簇的增加等等)

RegionServer職責

1、 RegionServer 維護 Master 分配給它的 Region,處理對這些 Region 的 IO 請求

2、負責和底層的檔案系統 HDFS 的互動,儲存資料到 HDFS
3、負責 Store 中的 HFile 的合併工作
4、RegionServer 負責 Split 在執行過程中變得過大的 Region,負責 Compact 操作

 

可以看到,client 訪問 HBase 上資料的過程並不需要 Master 參與(定址訪問 ZooKeeper 和RegioneServer,資料讀寫訪問 RegioneServer),Master 僅僅維護者 Table 和 Region 的元資料資訊,負載很低。

 

.META. 存的是所有的 Region 的位置資訊,那麼 RegioneServer 當中 Region 在進行分裂之後 的新產生的 Region,是由 Master 來決定發到哪個 RegioneServer,這就意味著,只有 Master知道 new Region 的位置資訊,所以,由 Master 來管理.META.這個表當中的資料的 CRUD

 

所以結合以上兩點表明,在沒有 Region 分裂的情況,Master 宕機一段時間是可以忍受的。

1.2、物理儲存

1.2.1、整體物理結構

1、Table 中的所有行都按照 RowKsey 的字典序排列。

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

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

4、HRegion 是 Hbase 中分散式儲存和負載均衡的最小單元。最小單元就表示不同的 HRegion可以分佈在不同的 HRegionServer 上。但一個 HRegion 是不會拆分到多個 server 上的。

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

1.2.2、StoreFile 和HFile結構

StoreFile 以 HFile 格式儲存在 HDFS 上,請看下圖 HFile 的資料組織格式:

首先 HFile 檔案是不定長的,長度固定的只有其中的兩塊:Trailer 和 FileInfo。 正如圖中所示:Trailer 中有指標指向其他資料塊的起始點。FileInfo 中記錄了檔案的一些 Meta 資訊,例如:AVG_KEY_LEN, AVG_VALUE_LEN, LAST_KEY, COMPARATOR, MAX_SEQ_ID_KEY 等。

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。

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

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

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

開始是兩個固定長度的數值,分別表示 Key 的長度和 Value 的長度。緊接著是 Key,開始是 固定長度的數值,表示 RowKey 的長度,緊接著是 RowKey,然後是固定長度的數值,表示Family 的長度,然後是 Family,接著是 Qualifier,然後是兩個固定長度的數值,表示 TimeStamp和 KeyType(Put/Delete)。Value 部分沒有這麼複雜的結構,就是純粹的二進位制資料了。

1.2.3、MemStore 和 StoreFile

一個 HRegion 由多個 Store 組成,每個 Store 包含一個列族的所有資料

Store 包括位於記憶體的一個 Memstore 和位於硬碟的多個 Storefile 組成

寫操作先寫入 Memstore,當 Memstore 中的資料量達到某個閾值,HRegionServer 啟動flushcache 程序寫入 Storefile,每次寫入形成單獨一個 HFile

當總 Storefile 大小超過一定閾值後,會把當前的 Region 分割成兩個,並由 HMaster 分配給 相應的 Region 伺服器,實現負載均衡

客戶端檢索資料時,先在 Memstore 找,找不到再找 Storefile

1.2.4、HLog(WAL)

WAL 意為 Write ahead log(http://en.wikipedia.org/wiki/Write-ahead_logging),類似 mysql 中的binlog,用來做災難恢復之用,HLog 記錄資料的所有變更,一旦資料修改,就可以從 Log 中 進行恢復。

每個 Region Server 維護一個 HLog,而不是每個 Region 一個。這樣不同 region(來自不同 table)的日誌會混在一起,這樣做的目的是不斷追加單個檔案相對於同時寫多個檔案而言,可以減 少磁碟定址次數,因此可以提高對 table 的寫效能。帶來的麻煩是,如果一臺 region server下線,為了恢復其上的 Region,需要將 RegionServer 上的 log 進行拆分,然後分發到其它 region server 上進行恢復。

HLog 檔案就是一個普通的 Hadoop Sequence File:
1、HLog Sequence File 的 Key 是 HLogKey 物件,HLogKey 中記錄了寫入資料的歸屬資訊,除 了 table 和 region 名字外,同時還包括 sequence number 和 timestamp,timestamp 是”寫入 時間”,sequence number 的起始值為 0,或者是最近一次存入檔案系統中 sequence number。

2、HLog Sequece File 的 Value 是 HBase 的 KeyValue 物件,即對應 HFile 中的 KeyValue

1.3、定址機制

既然讀寫都在 RegionServer 上發生,我們前面有講到,每個 RegionSever 為一定數量的 Region服務,那麼 Client 要對某一行資料做讀寫的時候如何能知道具體要去訪問哪個 RegionServer呢?那就是接下來我們要討論的問題

1.3.1、老的Region定址方式

在 HBase-0.96 版本以前,HBase 有兩個特殊的表,分別是-ROOT-表和.META.表,其中-ROOT-的位置儲存在 ZooKeeper 中,-ROOT-本身儲存了.META. Table 的 RegionInfo 資訊,並且-ROOT-不會分裂,只有一個 Region。而.META.表可以被切分成多個 Region。讀取的流程如下圖所示:

詳細步驟:

第 1 步:Client 請求 ZooKeeper 獲得-ROOT-所在的 RegionServer 地址
第 2 步:Client 請求-ROOT-所在的 RS 地址,獲取.META.表的地址,Client 會將-ROOT-的相關 資訊 cache 下來,以便下一次快速訪問
第 3 步:Client 請求.META.表的 RegionServer 地址,獲取訪問資料所在 RegionServer 的地址,Client 會將.META.的相關資訊 cache 下來,以便下一次快速訪問
第 4 步:Client 請求訪問資料所在 RegionServer 的地址,獲取對應的資料

從上面的路徑我們可以看出,使用者需要 3 次請求才能直到使用者 Table 真正的位置,這在一定 程式帶來了效能的下降。在 0.96 之前使用 3 層設計的主要原因是考慮到元資料可能需要很 大。但是真正叢集執行,元資料的大小其實很容易計算出來。在 BigTable 的論文中,每行METADATA 資料儲存大小為 1KB 左右,如果按照一個 Region 為 128M 的計算,3 層設計可以 支援的 Region 個數為 2^34 個,採用 2 層設計可以支援 2^17(131072)。那麼 2 層設計的情 況下一個叢集可以儲存 4P 的資料。這僅僅是一個 Region 只有 128M 的情況下。如果是 10G呢? 因此,通過計算,其實 2 層設計就可以滿足叢集的需求。因此在 0.96 版本以後就去掉了-ROOT-表了。

1.3.2、新的Region定址方式

如上面的計算,2 層結構其實完全能滿足業務的需求,因此 0.96 版本以後將-ROOT-表去掉了。 如下圖所示:

訪問路徑變成了 3 步:

第 1 步:Client 請求 ZooKeeper 獲取.META.所在的 RegionServer 的地址。
第 2 步:Client 請求.META.所在的 RegionServer 獲取訪問資料所在的 RegionServer 地址,Client會將.META.的相關資訊 cache 下來,以便下一次快速訪問。
第 3 步:Client 請求資料所在的 RegionServer,獲取所需要的資料。

總結去掉-ROOT-的原因有如下 2 點:其一,提高效能;其二,2層結構已經足以滿足叢集的需求

這裡還有一個問題需要說明,那就是 Client 會快取.META.的資料,用來加快訪問,既然有緩 存,那它什麼時候更新?如果.META.更新了,比如 Region1 不在 RerverServer2 上了,被轉移 到了 RerverServer3 上。Client 的快取沒有更新會有什麼情況?

其實,Client 的元資料快取不更新,當.META.的資料發生更新。如上面的例子,由於 Region1的位置發生了變化,Client 再次根據快取去訪問的時候,會出現錯誤,當出現異常達到重試 次數後就會去.META.所在的 RegionServer 獲取最新的資料,如果.META.所在的 RegionServer也變了,Client 就會去 ZooKeeper 上獲取.META.所在的 RegionServer 的最新地址。

1.4、讀寫過程

1.4.1、讀請求過程

1、客戶端通過 ZooKeeper 以及-ROOT-表和.META.表找到目標資料所在的 RegionServer(就是資料所在的Region的主機地址)

2、聯絡 RegionServer 查詢目標資料

3、RegionServer 定位到目標資料所在的 Region,發出查詢請求

4、Region 先在 Memstore 中查詢,命中則返回

5、如果在 Memstore 中找不到,則在 Storefile 中掃描。為了能快速的判斷要查詢的資料在不在這個 StoreFile 中,應用了 BloomFilter

(BloomFilter,布隆過濾器:迅速判斷一個元素是不是在一個龐大的集合內,但是他有一個 弱點:它有一定的誤判率) (誤判率:原本不存在與該集合的元素,布隆過濾器有可能會判斷說它存在,但是,如果 布隆過濾器,判斷說某一個元素不存在該集合,那麼該元素就一定不在該集合內)

1.4.2、寫請求過程

1、Client 先根據 RowKey 找到對應的 Region 所在的 RegionServer

2、Client 向 RegionServer 提交寫請求

3、RegionServer 找到目標 Region

4、Region 檢查資料是否與 Schema 一致

5、如果客戶端沒有指定版本,則獲取當前系統時間作為資料版本6、將更新寫入 WAL Log

7、將更新寫入 Memstore

8、判斷 Memstore 的是否需要 flush 為 StoreFile 檔案。

 

Hbase 在做資料插入操作時,首先要找到 RowKey 所對應的的 Region,怎麼找到的?其實這 個簡單,因為.META.表儲存了每張表每個 Region 的起始 RowKey 了。

 

建議:在做海量資料的插入操作,避免出現遞增 rowkey 的 put 操作
如果 put 操作的所有 RowKey 都是遞增的,那麼試想,當插入一部分資料的時候剛好進行分 裂,那麼之後的所有資料都開始往分裂後的第二個 Region 插入,就造成了資料熱點現象。

 

細節描述:HBase 使用 MemStore 和 StoreFile 儲存對錶的更新。

資料在更新時首先寫入 HLog(WAL Log),再寫入記憶體(MemStore)中,MemStore 中的資料是排 序的,當 MemStore 累計到一定閾值(預設是 128M)時,就會建立一個新的 MemStore,並且 將老的 MemStore 新增到 flush 佇列,由單獨的執行緒 flush 到磁碟上,成為一個 StoreFile。於 此同時,系統會在 ZooKeeper 中記錄一個 redo point,表示這個時刻之前的變更已經持久化 了。當系統出現意外時,可能導致記憶體(MemStore)中的資料丟失,此時使用HLog(WAL Log)來恢復 checkpoint 之後的資料。

StoreFile 是隻讀的,一旦建立後就不可以再修改。因此 HBase 的更新/修改其實是不斷追加 的操作。當一個 Store 中的 StoreFile 達到一定的閾值後,就會進行一次合併(minor_compact, major_compact),將對同一個 key 的修改合併到一起,形成一個大的 StoreFile,當 StoreFile的大小達到一定閾值後,又會對 StoreFile 進行 split,等分為兩個 StoreFile。由於對錶的更新是不斷追加的,compact 時,需要訪問 Store 中全部的 StoreFile 和 MemStore,將他們按rowkey 進行合併,由於 StoreFile 和 MemStore 都是經過排序的,並且 StoreFile 帶有記憶體中 索引,合併的過程還是比較快。

Minor_Compact 和 Major_Compact 的區別:
1)Minor 操作只用來做部分檔案的合併操作以及包括 minVersion=0 並且設定 ttl 的過期版 本清理,不做任何刪除資料、多版本資料的清理工作。
2)Major 操作是對 Region 下的 HStore 下的所有 StoreFile 執行合併操作,最終的結果是整 理合並出一個檔案。

Client 寫入 -> 存入 MemStore,一直到 MemStore 滿 -> Flush 成一個 StoreFile,直至增長到 一定閾值 -> 觸發 Compact 合併操作 -> 多個 StoreFile 合併成一個 StoreFile,同時進行版本 合併和資料刪除 -> 當StoreFilesCompact後,逐步形成越來越大的StoreFile-> 單個StoreFile大小超過一定閾值後,觸發 Split 操作,把當前 Region Split 成 2 個 Region,Region 會下線, 新 Split 出的 2 個孩子 Region 會被 HMaster 分配到相應的 HRegionServer 上,使得原先 1 個Region 的壓力得以分流到 2 個 Region 上由此過程可知,HBase 只是增加資料,所有的更新 和刪除操作,都是在 Compact 階段做的,所以,使用者寫操作只需要進入到記憶體即可立即返 回,從而保證 I/O 高效能。

寫入資料的過程補充:
工作機制:每個 HRegionServer 中都會有一個 HLog 物件,HLog 是一個實現 Write Ahead Log的類,每次使用者操作寫入 Memstore 的同時,也會寫一份資料到 HLog 檔案,HLog 檔案定期 會滾動出新,並刪除舊的檔案(已持久化到 StoreFile 中的資料)。當 HRegionServer 意外終止 後,HMaster 會通過 ZooKeeper 感知,HMaster 首先處理遺留的 HLog 檔案,將不同 Region的 log 資料拆分,分別放到相應 Region 目錄下,然後再將失效的 Region(帶有剛剛拆分的 log) 重新分配,領取到這些 Region 的 HRegionServer 在 load Region 的過程中,會發現有歷史 HLog需要處理,因此會 Replay HLog 中的資料到 MemStore 中,然後 flush 到 StoreFiles,完成資料 恢復。

1.5、RegionServer工作機制

1、Region分配

任何時刻,一個 Region 只能分配給一個 RegionServer。master 記錄了當前有哪些可用的RegionServer。以及當前哪些 Region 分配給了哪些 RegionServer,哪些 Region 還沒有分配。 當需要分配的新的 Region,並且有一個 RegionServer 上有可用空間時,Master 就給這個RegionServer 傳送一個裝載請求,把 Region 分配給這個 RegionServer。RegionServer 得到請 求後,就開始對此 Region 提供服務。

2、RegionServer上線

Master 使用 zookeeper 來跟蹤 RegionServer 狀態。當某個 RegionServer 啟動時,會首先在ZooKeeper 上的 server 目錄下建立代表自己的 znode。由於 Master 訂閱了 server 目錄上的變 更訊息,當 server 目錄下的檔案出現新增或刪除操作時,Master 可以得到來自 ZooKeeper的實時通知。因此一旦 RegionServer 上線,Master 能馬上得到訊息。

3、RegionServer下線

當 RegionServer 下線時,它和 zookeeper 的會話斷開,ZooKeeper 而自動釋放代表這臺 server的檔案上的獨佔鎖。Master 就可以確定:

  • RegionServer 和 ZooKeeper 之間的網路斷開了。
  • RegionServer 掛了。

無論哪種情況,RegionServer 都無法繼續為它的 Region 提供服務了,此時 Master 會刪除 server目錄下代表這臺 RegionServer 的 znode 資料,並將這臺 RegionServer 的 Region 分配給其它還 活著的同志。

1.6、Master工作機制

Master 上線
Master 啟動進行以下步驟:
1、從 ZooKeeper 上獲取唯一一個代表 Active Master 的鎖,用來阻止其它 Master 成為 Master。

2、掃描 ZooKeeper 上的 server 父節點,獲得當前可用的 RegionServer 列表。

3、和每個 RegionServer 通訊,獲得當前已分配的 Region 和 RegionServer 的對應關係。

4、掃描.META. Region 的集合,計算得到當前還未分配的 Region,將他們放入待分配 Region列表。

Master 下線
由於 Master 只維護表和 Region 的元資料,而不參與表資料 IO 的過程,Master 下線僅導致所有元資料的修改被凍結(無法建立刪除表,無法修改表的 schema,無法進行 Region的負載均衡,無法處理 Region 上下線,無法進行 Region 的合併,唯一例外的是 Region 的 split可以正常進行,因為只有 RegionServer 參與),表的資料讀寫還可以正常進行。因此 Master下線短時間內對整個 hbase 叢集沒有影響。

從上線過程可以看到,Master 儲存的資訊全是可以冗餘資訊(都可以從系統其它地方 收集到或者計算出來)

因此,一般 HBase 叢集中總是有一個 Master 在提供服務,還有一個以上的 Master 在等 待時機搶佔它的位置。

2、HBase高階應用

2.1、建表高階屬性

下面幾個 shell 命令在 HBase 操作中可以起到很好的作用,且主要體現在建表的過程中,看 下面幾個 create 屬性

1、BLOOMFILTER(布隆過濾器)

預設是 NONE 是否使用布隆過慮及使用何種方式,布隆過濾可以每列簇單獨啟用

使用 HColumnDescriptor.setBloomFilterType(NONE | ROW | ROWCOL) 對列族單獨啟用布隆,Default = ROW 對行進行布隆過濾

對 ROW,行鍵的雜湊在每次插入行時將被新增到布隆

對 ROWCOL,行鍵 + 列族 + 列族修飾的雜湊將在每次插入行時新增到布隆

使用方法:create 'table',{NAME => 'baseinfo' BLOOMFILTER => 'ROW'}

作用:用布隆過濾可以節省讀磁碟過程,可以有助於降低讀取延遲

2、VERSIONS(版本號)

預設是 1 ,這個引數的意思是資料保留 1 個 版本,如果我們認為我們的資料沒有這麼大的必要保留這麼多,隨時都在更新,而老版本的資料對我們毫無價值,那將此引數設為 1 能 節約 2/3 的空間。

使用方法::create 'table',{ NAME => 'baseinfo' VERSIONS=>'2'}

附:MIN_VERSIONS => '0'是說在 compact 操作執行之後,至少要保留的版本,只有在設 置了 TTL 的時候生效

3、COMPRESSION(壓縮)

預設值是 NONE ,即不使用壓縮,這個引數意思是該列族是否採用壓縮,採用什麼壓縮演算法。

方法: create 'table',{NAME=>'info',COMPRESSION=>'SNAPPY'} ,建議採用 SNAPPY 壓縮算 法 ,HBase 中,在 Snappy 釋出之前(Google 2011 年對外發布 Snappy),採用的 LZO 演算法, 目標是達到儘可能快的壓縮和解壓速度,同時減少對 CPU 的消耗;

在 Snappy 釋出之後,建議採用 Snappy 演算法(參考《HBase: The Definitive Guide》),具體 可以根據實際情況對 LZO 和 Snappy 做過更詳細的對比測試後再做選擇。

Algorithm

% remaining

Encoding

Decoding

GZIP

13.4% 21 MB/s 118 MB/s

LZO

20.5% 135 MB/s 410 MB/s
Zippy/Snappy 22.2% 172 MB/s 409 MB/s

如果建表之初沒有壓縮,後來想要加入壓縮演算法,可以通過 alter 修改 schema。

4、TTL(Time To Live)

預設是 2147483647,即Integer.MAX_VALUE 值,大概是 68 年,這個引數是說明該列族資料的存活時間,單位是 s,這個引數可以根據具體的需求對資料設定存活時間,超過存活時間的資料將不在表中顯示,待下次 major compact 的時候再徹底刪除資料。需要注意的是, TTL 設定之後 MIN_VERSIONS=>'0' 這樣設定之後,TTL 時間戳過期後,將全部徹底刪除該 family 下所有的資料,如果 MIN_VERSIONS 不等於 0 那將保留最新的MIN_VERSIONS 個版本的資料,其它的全部刪除,比如MIN_VERSIONS=>'1' 屆時將保留一個 最新版本的資料,其它版本的資料將不再儲存。

5、Alter(修改表)

使用方法:如修改壓縮演算法

disable 'table'

alter 'table',{NAME=>'info',COMPRESSION=>'snappy'}

enable 'table'

但是需要執行 major_compact 'table' 命令之後 才會做實際的操作。

6、describe/desc(查看錶詳細資訊)

這個命令查看了 create table 的各項引數或者是預設值。使用方式:describe 'user_info'

7、disable_all/enable_all

disable_all 'toplist.*' ,disable_all 支援正則表示式,並列出當前匹配的表的如下:

toplist_a_total_1001

toplist_a_total_1002

toplist_a_total_1008

toplist_a_total_1009

toplist_a_total_1019

toplist_a_total_1035

...
Disable the above 25 tables (y/n)? 並給出確認提示

8、drop_all

這個命令和 disable_all 的使用方式是一樣的。

9、HBase 預分割槽

預設情況下,在建立 HBase 表的時候會自動建立一個 region 分割槽,當匯入資料的時候,所有的 HBase 客戶端都向這一個 region 寫資料,直到這個 region 足夠大了才進行切分。一 種可以加快批量寫入速度的方法是通過預先建立一些空的 regions,這樣當資料寫入 HBase時,會按照 region 分割槽情況,在叢集內做資料的負載均衡。

命令方式:

# create table with specific split points
hbase>create 'table1','f1',SPLITS => ['\x10\x00', '\x20\x00', '\x30\x00', '\x40\x00']

 

# create table with four regions based on random bytes keys
hbase>create 'table2','f1', { NUMREGIONS => 8 , SPLITALGO => 'UniformSplit' }

 

# create table with five regions based on hex keys
hbase>create 'table3','f1', { NUMREGIONS => 10, SPLITALGO => 'HexStringSplit' }

也可以使用 api 的方式:

hbase org.apache.hadoop.hbase.util.RegionSplitter test_table HexStringSplit -c 10 -f info

hbase org.apache.hadoop.hbase.util.RegionSplitter splitTable HexStringSplit -c 10 -f info

 

引數:

test_table 是表名

HexStringSplit 是 split 方式

-c 是分 10 個 region

-f 是 family

可在 UI 上檢視結果,如圖:

這樣就可以將表預先分為 15 個區,減少資料達到 storefile 大小的時候自動分割槽的時間消耗,並且還有以一個優勢,就是合理設計 rowkey 能讓各個 region 的併發請求平均分配(趨於均勻) 使 IO 效率達到最高,但是預分割槽需要將 filesize 設定一個較大的值,設定哪個引數 呢 hbase.hregion.max.filesize 這個值預設是 10G 也就是說單個 region 預設大小是 10G。

這個引數的預設值在 0.90 到 0.92 到 0.94.3 各版本的變化:256M--1G--10G

但是如果 MapReduce Input 型別為 TableInputFormat 使用 hbase 作為輸入的時候,就要注意 了,每個 region 一個 map,如果資料小於 10G 那隻會啟用一個 map 造成很大的資源浪費, 這時候可以考慮適當調小該引數的值,或者採用預分配 region 的方式,並將檢測如果達到 這個值,再手動分配 region。

2.2、表設計

1、列簇設計

追求的原則是:在合理範圍內能儘量少的減少列簇就儘量減少列簇。

最優設計是:將所有相關性很強的 key-value 都放在同一個列簇下,這樣既能做到查詢效率最高,也能保持儘可能少的訪問不同的磁碟檔案。

以使用者資訊為例,可以將必須的基本資訊存放在一個列族,而一些附加的額外資訊可以放在另一列族。

2、RowKey設計

HBase 中,表會被劃分為 1...n 個 Region,被託管在 RegionServer 中。Region 兩個重要的屬性:StartKey 與 EndKey 表示這個 Region 維護的 rowKey 範圍,當我們要讀/寫資料時,如 果 rowKey 落在某個 start-end key 範圍內,那麼就會定位到目標 region 並且讀/寫到相關的資料。那怎麼快速精準的定位到我們想要操作的資料,就在於我們的 rowkey 的設計了。

Rowkey 設計三原則

一、rowkey長度原則

Rowkey 是一個二進位制碼流,Rowkey 的長度被很多開發者建議說設計在 10~100 個位元組,不過建議是越短越好,不要超過 16 個位元組。

原因如下:
1、資料的持久化檔案 HFile 中是按照 KeyValue 儲存的,如果 Rowkey 過長比如 100 個位元組,1000 萬列資料光 Rowkey 就要佔用 100*1000 萬=10 億個位元組,將近 1G 資料,這會極大影響 HFile 的儲存效率;

2、MemStore 將快取部分資料到記憶體,如果 Rowkey 欄位過長記憶體的有效利用率會降低, 系統將無法快取更多的資料,這會降低檢索效率。因此 Rowkey 的位元組長度越短越好。

3、目前作業系統是都是 64 位系統,記憶體 8 位元組對齊。控制在 16 個位元組,8 位元組的整數倍利用作業系統的最佳特性。

二、rowkey雜湊原則

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

三、rowkey唯一原則

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

資料熱點

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

防止資料熱點的有效措施

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][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 - 結束時間]