(圖片來源於網絡,侵刪)
一、HBASE簡介
【1.1】 什麼是HBase
1)HBase譯爲“Hadoop Database”,是一個構建在HDFS之上的高可靠
、高性能
、列存儲
、可伸縮
、實時讀寫
的NoSQL
數據庫系統,利用HBase技術可在廉價PC Server上搭建起大規模結構化存儲集羣
NoSQL = Not Only SQL:會有一些把 NoSQL 數據的原生查詢語句封裝成 SQL,比如 HBase 就有 Phoenix 工具
2)因爲HDFS可以存儲存儲結構化
和半結構化
的鬆散數據
,所以HBase也可以用來存儲結構化
和半結構化
的鬆散數據
3)HBase是Google Bigtable的開源實現,但是也有很多不同之處👇
- HBase 依賴於 HDFS 做底層的數據存儲,BigTable 依賴 Google GFS 做數據存儲
- HBase 依賴於 MapReduce 做數據計算,BigTable 依賴 Google MapReduce 做數據計算
- HBase 依賴於 ZooKeeper 做服務協調,BigTable 依賴 Google Chubby 做服務協調
4)HBase的目標是存儲並處理大型的數據
,更具體來說是僅需使用普通的硬件配置,就能夠處理由成千上萬的行和列所組成的大型數據
5) 擴展:結構化、半結構化和非結構化👇
術語 | 概念 |
---|---|
結構化 | 數據結構字段含義確定,清晰,典型的如數據庫中的表結構 |
半結構化 | 具有一定結構,但語義不夠確定,典型的如 HTML 網頁,有些字段是確定的(title), 有些不確定(table) |
非結構化 | 雜亂無章的數據,很難按照一個概念去進行抽取,無規律性 |
【1.2】 與傳統數據庫的對比
1)關係型數據庫 和 非關係型數據庫的典型代表
- ①
NoSQL
:HBase、Redis、Mongodb - ②
RDBMS
:Mysql、Oracle、Sql Server、DB2
2)傳統數據庫遇到的問題:
- ① 數據量很大的時候無法存儲
- ② 沒有很好的
備份機制
- ③ 數據達到一定數量開始緩慢,很大的話基本無法支撐
3)HBASE優勢:
- ① 線性擴展,隨着數據量增多可以通過節點擴展進行支撐
- ② 數據存儲在HDFS上,備份機制健全
- ③ 通過Zookeeper協調查找數據,訪問速度快
【1.3】 HBase 中的表特點
1)大
:一個表可以有上十億行,上百萬列
2)面向列
:面向列(族)的存儲和權限控制,列(簇)獨立檢索
3)稀疏
:對於爲空(null)的列,並不佔用存儲空間,因此,表可以設計的非常稀疏
4)無模式
:每行都有一個可排序的主鍵和任意多的列,列可以根據需要動態的增加,同一 張表中不同的行可以有截然不同的列
【1.4】 HBase集羣中的角色
1)一個或者多個主節點 : HMaster
2)多個從節點 : HRegionServer
3)HBase依賴項 :
- Zookeeper:管理HBase元數據、監聽HMaster、HRegionServer上下線、Master選舉
- HDFS:依賴HDFS作爲存儲、HDFS提供良好的備份機制
二、HBASE數據模型
【2.1】 Row Key
什麼是Row Key?
Row Key是HBase中數據的主鍵,訪問數據的方式都需要通過Row Key進行查詢
1)訪問HBase Table中的數據,只有三種
方式:
- ① 通過單個row key訪問 (get)
- ② 通過row key的range(範圍) (scan)
- ③ 全表掃描 (scan)
2)HBase會對錶中的數據按照Row Key
排序(字典順序
)
3)Row key只能存儲64k
的字節數據
(實際應用中長度一般爲 10-100bytes
),在HBase內部,Row Key
保存形式爲字節數組
【2.2】 Column Family列族 & Column列
1)HBase表中的每個列都歸屬於某個列族,列族必須作爲表模式(schema)
定義的一部分預先給出
。如 create ‘表名’, ‘列族名’
2)列名以列族作爲前綴,每個“列族”都可以有多個列成員(column)
;如course:math
, course:english
, 新的列族成員(列)可以隨後按需
、動態的加入
3)權限控制、存儲以及調優都是在列族層面
進行的
4)HBase把同一列族
裏面的數據存儲在同一目錄
下,由幾個文件保存
【2.3】 Timestamp時間戳
1)在HBase每個cell
存儲單元對同一份數據有多個版本
,根據唯一的時間戳
來區分每個版本之間的差異,不同版本的數據按照時間倒序排序
,最新的數據版本排在最前面
2)時間戳的類型是 64位整型
3)時間戳可以由HBase(在數據寫入時自動)賦值,此時時間戳是精確到毫秒的當前系統時間
4)時間戳也可以由客戶顯式賦值,如果應用程序要避免數據版本衝突,就必須自己生成具有唯一性的時間戳
5)爲了避免數據存在過多版本造成的的管理 (包括存貯和索引)負擔,HBase提供了兩種
數據版本回收方式
:
- ①.保存數據的最後n個版本
- ②.保存最近一段時間內的版本(設置數據的生命週期TTL)
6)用戶可以針對每個列族
進行設置
【2.4】 Cell單元格
1)由 RowKey 和 "ColumnFamily:Column"的座標交叉決定
2)單元格是有版本的
3)單元格的內容是未解析的字節數組
, 由 {row key, column( =<family> +<qualifier>), version}
唯一確定的單元;cell
中的數據是沒有類型
的,全部是字節碼形式存貯
【2.5】 VersionNum
1)數據的版本號,每條數據可以有多個版本號,默認值爲系統時間戳
,類型爲Long
【2.6】 Region
什麼是Region?
Region可以類比成關係型數據庫中的分區,每個Region存儲一個表中的一部分連續數據
1)HBase自動
把表水平劃分成多個區域(region)
,每個region會保存一個表裏面某段連續的數據
;每個表默認
一開始只有一個region
,隨着數據不斷插入表,region不斷增大,當增大到一個閥值
的時候,region就會等分成兩個新的region(裂變)
2)當table中的行不斷增多,就會有越來越多的region。這樣一張完整的表被切分成多個Region,保存在多個RegionServer
上
3)因爲RegionServer管理Region,所以Region是HBase負責均衡的最小單元
,最小單元就表示不同的Region可以分佈在不同的HRegion Server上,對於一張表中不同的Region,可以分佈在不同的HRegionServer上,但對於一張表中的一個Region是不會拆分到多個RegionServer上的
4)Region雖然是負載均衡的最小單元,但並不是物理存儲的最小單元;
事實上,Region由一個或者多個Store組成
,每個Store保存一個column family;
每個Strore又由一個MemStore和0至多個StoreFile組成
三、HBase各角色作用解析
【3.1】 Client
1)Client包含了訪問HBase的接口
,另外Client還維護了對應的cache
來加速HBase的訪問,比如cache
的.META.
元數據的信息
【3.2】 Zookeeper
1)保證任何時候,集羣中只有一個Active Master
,如果Master異常,會通過競爭機制產生新的Master提供服務
2)存貯所有Region的尋址入口
3)實時監控RegionServer的狀態,將RegionServer的上線和下線信息實時通知給Master
4)存儲HBase的schema
和table元數據信息
【3.3】 Master
1)爲RegionServer分配Region
2)負責RegionServer的負載均衡
3)發現失效的RegionServer並重新分配其上的Region
4)處理對schema更新請求
【3.4】 RegionServer
1)RegionServer維護
Master分配給它的Region,處理對Region的IO請求
2)RegionServer負責切分
在運行過程中變得過大的Region;可以看到,Client訪問HBase上數據的過程並不需要Master參與(尋址訪問Zookeeper和RegionServer,數據讀寫訪問RegioneServer),Master僅僅維護者table和Region的元數據信息,負載很低
3)負責和底層HDFS的交互,存儲數據到HDFS
4)負責Storefile的合併
工作
四、HBase基於HDFS、ZK架構圖
五、HBASE讀寫流程
【5.1】 寫數據
1)Client 訪問 Zookeeper,獲取 hbase:meta表位於哪個 RegionServer
2)訪問對應的RegionServer,獲取hbase:meta表,根據rowkey的範圍確定RegionServer和Region,並將該table的Region信息以及meta表的位置信息緩存在客戶端的 Meta cache,方便下次訪問
3)Client與目標RegionServer進行通訊,發起寫入數據請求
4)Client將數據寫入(追加)到HLog(WAL,Write ahead log,預寫日誌),以防止數據丟失
5)然後將數據寫入對應的MemStore,數據會在MemStore內進行排序
6)如果HLog和Memstore都寫入成功,則這條數據寫入成功,向客戶端發送消息,告知寫入成功,如果其中一個寫入失敗,就表示這次寫入失敗
7)等達到MemStore的閾值後,將數據flush到磁盤成爲StoreFile,當StoreFile達到閾值(默認3個)後進行compact操作,將多個StoreFile合併成一個大StoreFile
注意:
1)此過程沒有Master的參與
2)客戶端在寫數據時會先去查看本地的meta cache,如果有之前的緩存數據,直接通過緩存元數據訪問 RegionServer,這時不通過Zookeeper獲取meta表去查找元數據,。如果集羣發生某些變化導致hbase:meta元數據更改,客戶端再根據本地元數據表請求的時候就會發生異常
,此時客戶端需要重新加載一份最新
的元數據表到本地
3)MemStore觸發時機
【5.2】讀數據
1)Client 訪問 Zookeeper,獲取 hbase:meta表位於哪個 RegionServer
2)訪問對應的RegionServer,獲取hbase:meta表,根據rowkey確定當前將要讀取的數據位於哪個RegionServer
中的哪個Region中。並將該table的region信息以及meta表的位置緩存在客戶端 meta cache,方便下次訪問
3)Client向該RegionServer服務器發起讀取數據請求,然後RegionServer收到請求並響應
4)分別在BlockCache(讀緩存)、MemStore和StoreFile(BlockCache中有的數據
在StoreFile中就不再讀取)中查詢目標數據,並將查到的所有數據進行合併;
此處的所有數據指的是同一條數據的不同版本(Time Stamp)或者不同的類型(Put/Delete)
5)將從文件中查詢到的數據塊(Block,HFile數據存儲單元,默認大小爲64KB)緩存到Block Cache
6)將合併後的最終結果返回給客戶端
注意:
1)此過程沒有Master的參與
2)客戶端在讀數據時會先去查看本地的meta cache,如果有之前的緩存數據,直接通過緩存元數據訪問 RegionServer,這時不通過Zookeeper獲取meta表去查找元數據,。如果集羣發生某些變化導致hbase:meta元數據更改,客戶端再根據本地元數據表請求的時候就會發生異常,此時客戶端需要重新加載一份最新的元數據表到本地
【5.3】 Flush 機制
flush 大致可以分爲三個階段:prepare 階段
,flush 階段
,commit 階段
1)prepare 階段
遍歷當前 Region
中所有的 Memstore
,將Memstore中當前數據集CellSkipListSet
做一個快照snapshot
,之後創建一個新的CellSkipListSet,後期寫入的數據都會寫入新的CellSkipListSet
中
2)flush 階段
遍歷所有Memstore
,將 prepare階段生成的 snapshot 持久化爲臨時文件
,臨時文件會統一放到目錄.tmp
下。這個過程因爲涉及到磁盤IO
操作,因此相對比較耗時
3)commit 階段
遍歷所有 Memstore,將 flush階段生成的臨時文件
移到指定的ColumnFamily
目錄下,針對HFile生成對應的storefile
和Reader
,把storefile
添加到HStore的storefiles
列表中,最後再清空prepare階段生成的snapshot
flush 的觸發條件一般分爲: memstore 級別
、region 級別
、regionServer 級別
、HLog數量上限
,具體配置可在官網文檔中查詢到
【5.4】 compact 機制
compact 合併機制,主要分爲 minor compaction 小合併 、major compaction 大合併兩個階段
1)minor compaction 小合併
將Store中多個HFile
合併爲一個HFile
,一次Minor Compaction的結果是HFile數量減少
並且合併出一個更大的StoreFile
,這種合併的觸發頻率很高
2)major compaction 大合併
合併 Store
中所有的 HFile
爲一個HFile
,此時被清理的數據有:被標記刪除的數據
、TTL過期數據
、版本號超過設定版本號的數據
。合併頻率比較低,默認7天
執行一次,並且性能消耗非常大
,建議生產關閉
(設置爲0
),在應用空閒時間手動觸發
。一般可以是手動控制進行合併,防止出現在業務高峯期
【5.5】 region的拆分
爲什麼要拆分 region 呢?
因爲region中存儲的是大量
的 rowkey
數據 ,當 region 中的數據條數過多
, region 變得很大的時候,直接影響查詢效率
,因此當 region 過大的時候.hbase會拆分region , 這也是HBase的一個優點
region 拆分策略
0.94
版本前默認切分策略,當region大小大於某個閾值(hbase.hregion.max.filesize=10G)
之後就會觸發切分,一個region等分爲2個region
0.94版本~2.0
版本默認切分策略 :根據拆分次數來判斷觸發拆分的條件
region split的計算公式是:
regioncount^3 * 128M * 2
,當region達到該 size 的時候進行split
例如:
第一次split:1^3 * 256 = 256MB
第二次split:2^3 * 256 = 2048MB
第三次split:3^3 * 256 = 6912MB
第四次split:4^3 * 256 = 16384MB > 10GB
,因此取較小的值10GB
後面每次split的size都是10GB了
預分區機制
當一個Hbase 表剛被創建的時候,Hbase默認的分配一個 region
給table。也就是說這個時候,所有的讀寫請求
都會訪問到同一個 regionServer 的同一個region中
,這個時候就達不到負載均衡
的效果了,集羣中的其他 regionServer 就可能會處於比較空閒的狀態
爲了解決這個問題,就有了 pre-splitting
,也就是預分區機制
,在創建table的時候就配置好,生成多個region
,這樣的好處就是可以優化數據讀寫效率
,並且使用負載均衡機制
,防止數據傾斜
操作很簡單,在創建表時,手動指定分區就好了:
例如👇
create 'person','info1','info2',SPLITS => ['1000','2000','3000','4000']
【5.6】 region的合併
Region的合併不是爲了性能
, 而是出於維護
的目的
比如刪除了大量的數據 ,這個時候每個Region都變得很小 ,存儲多個 Region就浪費了 ,這個時候可以把Region合併起來,進而可以減少一些 Region 服務器節點,由此可見 region 的合併其實是爲了更好的維護 Hbase 集羣