1. 程式人生 > 實用技巧 >3-HBase體系結構

3-HBase體系結構

結構體系

部署架構

一個HBase叢集由一個Master(也可以把兩個Master做成 High Available)和多個RegionServer組成。

HBase有兩種伺服器:Master伺服器和RegionServer伺服器。

  • Master伺服器負責維護表結構資訊

  • RegionServer伺服器負責儲存實際的資料,他們直接儲存在Hadoop的HDFS上

    • RegionServer非常依賴ZooKeeper服務
    • ZooKeeper管理了HBase所有RegionServer的資訊,包括具體的資料段存放在哪個RegionServer上。

體系架構

HBase中的元件包括Client、Zookeeper、HMaster、HRegionServer、HRegion、Store、MemStore、StoreFile、HFile、HLog等

Client

當客戶端從ZooKeeper獲取RegionServer的地址後,它會直接從RegionServer獲取或操作(插入、刪除)資料,而不經過Master。

Client 訪問使用者資料前需要首先訪問 ZooKeeper,找到-ROOT-表的 Region 所在的位置,然後訪問-ROOT-表,接著訪問.META.表,最後才能找到使用者資料的位置去訪問。

  • .META.:記錄了使用者所有表拆分出來的的 Region 對映資訊,.META.可以有多個 Regoin

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

定址方式
三層查詢(HBase-0.96 版本以前)

  1. 使用者通過查詢zk(ZooKeeper) 的/hbase/root-regionserver節點來知道-ROOT-表在什麼RegionServer上
  2. Client 請求-ROOT-所在的 RegionServer 地址,獲取.META.表的地址,Client 會將-ROOT-的相關資訊 cache 下來,以便下一次快速訪問
  3. Client 請求.META.表的 RegionServer 地址,獲取訪問資料所在 RegionServer 的地址, Client 會將.META.的相關資訊 cache 下來,以便下一次快速訪問
  4. Client 請求訪問資料所在 RegionServer 的地址,獲取對應的資料

總結:使用者需要 3 次請求才能直到使用者 Table 真正的位置,這在一定程式帶來了效能的下降。

二層查詢(HBase-0.96 版本以後)

使用 3 層設計的主要原因是考慮到元資料可能需要很大。

每行 METADATA 資料儲存大小為 1KB 左右,如果按照一個 Region 為 128M 的計算,3 層設計可以支援的 Region 個數為 2^34 個,採用 2 層設計可以支援 2^17(131072)。使用 2 層設計的情況下,一個叢集可以儲存 4P 的資料。這僅僅是一個 Region 只有 128M 的情況下。 2 層設計就可以滿足叢集的需求,因此在 0.96 版本以後就去掉 了-ROOT-表了。

  1. 客戶端先通過ZooKeeper的/hbase/meta-region-server節點查詢到哪臺RegionServer上有hbase:meta表。
  2. 客戶端連線含有hbase:meta表的RegionServer。 hbase:meta表儲存了所有Region的行鍵範圍資訊, 通過這個表就可以查詢出你要存取的rowkey屬於哪個Region的範圍裡面, 以及這個Region又是屬於哪個RegionServer。
  3. 獲取這些資訊後, 客戶端就可以直連其中一臺擁有你要存取的rowkey的RegionServer, 並直接對其操作。
  4. 客戶端會把meta資訊快取起來,下次操作就不需要進行以上載入hbase:meta的步驟了。

Zookeeper

元資料表hbase:meata的位置儲存在ZooKeeper

HDFS

真正承載資料的載體

Master

Master只負責各種協調工作,如建表、刪表、移動Region、合併等操作。

RegionServer

RegionServer就是存放Region的容器,直觀上說就是伺服器上的一個服務。RegionServer上有一個或者多個Region,資料就儲存在Region上。

RegionServer的內部架構圖

  • WAL(Write-Ahead Log):預寫日誌。當操作到達Region的時候,HBase先把操作寫到WAL裡面。 HBase會先把資料放到基於記憶體實現的Memstore裡,等資料達到一定的數量時才刷寫(flush)到最終儲存的HFile內。

  • 多個Region:Region相當於一個數據分片,每一個Region都有起始rowkey和結束rowkey,代表了它所儲存的row範圍。

Region

Region就是一段資料的集合。HBase中的表一般擁有一個到多個Region。
Region有以下特性:

  • Region不能跨伺服器,一個RegionServer上有一個或者多個Region。
  • 資料量小的時候,一個Region足以儲存所有資料;但是,當資料量大的時候,HBase會拆分Region。
  • 當HBase在進行負載均衡的時候,也有可能會從一臺RegionServer上把Region移動到另一臺RegionServer上。
  • Region是基於HDFS的,它的所有資料存取操作都是呼叫了HDFS的客戶端介面來實現的。

一個Region就是多個行的集合。在Region中行的排序按照行鍵(rowkey)字典排序。

Region 內部結構圖

一個Region包含有:

  • 多個Store:每一個Region內都包含有多個Store例項。一個Store對應一個列族的資料,如果一個表有兩個列族,那麼在一個Region裡面就有兩個Store。在最右邊的單個Store的解剖圖上,我們可以看到Store內部有MemStore和HFile這兩個組成部分。

Store

Store中有兩個重要組成部分:

  • MemStore:每個Store中有一個MemStore例項。 資料寫入WAL之後就會被放入MemStore。 MemStore是記憶體的儲存物件, 只有當MemStore滿了的時候才會將資料刷寫(flush) 到HFile中

  • HFile:在Store中有多個HFile。 當MemStore滿了之後HBase就會在HDFS上生成一個新的HFile, 然後把MemStore中的內容寫到這個HFile中。HFile直接跟HDFS打交道,它是資料的儲存實體。

Store內部結構圖

MemStore

Memstore是儲存在記憶體中,Memstore存在的意義是維持資料按照rowkey順序排列,而不是做一個快取

使用記憶體先把資料整理成順序存放,然後再一起寫入硬碟。

資料被寫入WAL之後就會被載入到MemStore中去。 MemStore的大小增加到超過一定閥值的時候就會被刷寫到HDFS上, 以HFile的形式被持久化起來。

HFile(StoreFile)

HFile是資料儲存的實際載體,我們建立的所有表、列等資料都儲存在HFile裡面。HFile是由一個一個的塊組成的。 在HBase中一個塊的大小預設為64KB, 由列族上的BLOCKSIZE屬性定義。

MemStore刷寫而成的檔案叫HFile, StoreFile就是HFile的抽象類

HFile的組成

  • Data (資料塊) :每個HFile有多個Data塊。儲存HBase表中的資料。可選的
  • Meta(元資料塊):Meta塊是可選的,Meta塊只有在檔案關閉的時候才會寫入。Meta塊儲存了該HFile檔案的元資料資訊
  • FileInfo(檔案資訊):只有在檔案關閉的時候寫入。儲存的是這個檔案的資訊,比如最後一個Key(Last
    Key) ,平均的Key長度(Avg Key Len)等。必選的
  • DataIndex(儲存Data塊索引資訊的塊檔案):索引的資訊也就是Data塊的偏移值(offset)。可選的
  • MetaIndex(儲存Meta塊索引資訊的塊檔案):可選的
  • Trailer:儲存了FileInfo、 DataIndex、 MetaIndex塊的偏移值。必選的
Data資料塊

Data資料塊的第一位儲存的是塊的型別, 後面儲存的是多個KeyValue鍵值對, 也就是單元格(Cell)的實現類。 Cell是一個介面,KeyValue是它的實現類。

  • BlockType(塊型別)
    • DATA
    • ENCODED_DATA
    • LEAF_INDEX
    • BLOOM_CHUNK
    • META
    • INTERMEDIATE_INDEX
    • ROOT_INDEX
    • FILE_INFO
    • GENERAL_BLOOM_META
    • DELETE_FAMILY_BLOOM_META
    • TRAILER
    • INDEX_V1
KeyValue類

一個KeyValue類裡面最後一個部分是儲存資料的Value,而前面的部分都是儲存跟該單元格相關的元資料資訊。如果你儲存的value很小,那麼這個單元格的絕大部分空間就都是rowkey、columnfamily、column等的元資料,所以大家的列族和列的名字如果很長,大部分的空間就都被拿來儲存這些資料了。

採用適當的壓縮演算法就可以極大地節省儲存列族、 列等資訊的空間。壓縮和解壓必然帶來效能損耗

KeyValue類結構圖

資料儲存順序

WAL是儲存在HDFS上的, Memstore是儲存在記憶體中的, HFile也是儲存在HDFS上的。

資料是先寫入WAL, 再被放入Memstore, 最後被持久化到HFile中。

預寫日誌(Log)

預寫日誌(Write-ahead log,WAL) 就是設計來解決宕機之後的操作恢復問題的。資料到達Region的時候是先寫入WAL,然後再被載入到Memstore的。WAL的資料是儲存在HDFS。

關閉或開啟WAL特性

WAL是預設開啟的

Mutation.setDurability(Durability.SKIP_WAL)

-- 方法來設定和獲取欄位的值
Mutation.getDurability()
  • 在HBase的Java API中,指定寫入時不使用WAL log
Put put = new Put(rowKey);
put.setWriteToWAL(false);
  • 在HBase shell中,關閉一張表的WAL log
disable 'TABLE_NAME'
alter 'TABLE_NAME', DURABILITY => 'SKIP_WAL'
enable 'TABLE_NAME'
延遲(非同步)同步寫入WAL
Mutation.setDurability(Durability.ASYNC_WAL)

DURABILITY可選的值有ASYNC_WAL, FSYNC_WAL, SKIP_WAL, SYNC_WAL(預設值), USE_DEFAULT等

  • ASYNC_WAL
    Write the Mutation to the WAL asynchronously
  • FSYNC_WAL
    Write the Mutation to the WAL synchronously and force the entries to disk.
  • SKIP_WAL
    Do not write the Mutation to the WAL
  • SYNC_WAL
    Write the Mutation to the WAL synchronously.
  • USE_DEFAULT
    If this is for tables durability, use HBase's global default value (SYNC_WAL).
WAL 滾動

WAL的檢查間隔由hbase.regionserver.logroll.period定義, 預設值為1小時。檢查的內容是把當前WAL中的操作跟實際持久化到HDFS上的操作比較,看哪些操作已經被持久化了,被持久化的操作就會被移動到.oldlogs資料夾內

一個WAL例項包含有多個WAL檔案。 WAL檔案的最大數量通過hbase.regionserver.maxlogs(預設是32) 引數來定義

觸發滾動條件
  • 當WAL檔案所在的塊(Block) 快要滿了
  • 當WAL所佔的空間大於或者等於某個閥值,該閥值的計算公式:hbase.regionserver.hlog.blocksize * hbase.regionserver.logroll.multiplier
    • hbase.regionserver.hlog.blocksize: 儲存系統的塊大小,若基於HDFS,則設定為HDFS的塊大小
    • hbase.regionserver.logroll.multiplier:預設值0.95。即當WAL檔案所佔的空間大於或者等於95%的塊大小, 則這個WAL檔案就會被歸檔到.oldlogs資料夾內
WAL歸檔

WAL檔案被創建出來後會放在/hbase/.log,一旦WAL檔案被判定為要歸檔,則會被移動到/hbase/.oldlogs資料夾。

當這個WAL不需要作為用來恢復資料的備份時,Master會負責定期地去清理.oldlogs資料夾。

引用WAL檔案的場景:

  • TTL程序: 該程序會保證WAL檔案一直存活直到達到hbase.master.logcleaner.ttl定義的超時時間(預設10分鐘) 為止
  • 備份(replication) 機制: 如果你開啟了HBase的備份機制,那麼HBase要保證備份叢集已經完全不需要這個WAL檔案了,才會刪除這個WAL檔案。

只有當該WAL檔案沒有被以上兩種情況引用時, 才會被系統徹底地刪除掉。

資料儲存架構

結構圖
表結構圖

行結構

Namespace(表名稱空間)

表名稱空間的作用是把多個屬於相同業務領域的表分成一個組。

在建表時可以新增上名稱空間( : )

保留表空間

HBase中預定義2個保留表空間

  • HBase: 系統表空間,用於HBase內部表
  • default: 那些沒有定義表空間的表都被自動分配到這個表空間下
Table(表)

一個表由一個或者多個列族組成

Row(行)

一個行包含了多個列,這些列通過列族來分類。一行中的資料可以分佈在不同的伺服器上。

Row key

rowkey行鍵可以是任意字串(最大長度是 64KB,實際應用中長度一般為 10-100bytes),最好是16。在 HBase 內部,rowkey 儲存為位元組陣列。每個行(row)都擁有唯一的行鍵(row key)來確定其唯一性。rowkey就是決定row儲存順序和位置的唯一憑證。

HBase中無法根據某個column來排序,只能根據rowkey來排序(字典順序)

column

最基本的儲存單位是列(column),一個列或者多個列形成一行(row)。

在HBase中,行跟行的列可以完全不一樣,這個行的資料跟另外一個行的資料也可以儲存在不同的機器上,甚至同一行內的列也可以儲存在完全不同的機器上。

Hbase只支援3中查詢方式

1、基於Rowkey的單行查詢

2、基於Rowkey的範圍掃描

3、全表掃描

Column Family

若干列可以組成列族(Column Family)。Hbase通過列族劃分資料的儲存,列族下面可以包含任意多的列,實現靈活的資料存取。

Hbase表的建立的時候就必須指定列族,不需要指定列。

Hbase的列族不是越多越好,官方推薦的是列族最好小於或者等於3。我們使用的場景一般是1個列族。

表屬性(如:過期時間,資料塊快取,是否壓縮等屬性)都是定義在列簇上。

在HBase中一個列的名稱前面總是帶著他所屬的列族,它的格式是( 列族:列名 )。

TimeStamp(時間戳/版本號)

在Hbase中使用不同的timestame來標識相同rowkey行對應的不同版本的資料。用來標定同一個列中多個單元格的版本號。

版本通過時間戳來索引。時間戳的型別是 64 位整型。時間戳可以由hbase(在資料寫入時自動)賦值,它是精確到毫秒的當前系統時間。時間戳也可以由使用者顯式賦值。每個 cell 中,不同版本的資料按照時間倒序排序,即最新的資料排在最前面。

多版本資料管理

hbase 提供了兩種資料版本回收方式

  • 儲存資料的最後 N個版本
  • 儲存最近一段時間內的版本(設定資料的生命週期 TTL)
Cell(單元格)

一個列上可以儲存多個版本的值,每個版本就稱為單元格(Cell)。多個版本的值被儲存到多個單元格中,多個版本之間用timestame(Version)來區分。因此,由行鍵:列族:列:版本號(rowkey:column family:column:version)來唯一確定一條結果。