HBase 原理
1. HBase 底層原理
1.1 系統(tǒng)架構
1.1.1 Client 職責
1. HBase 有兩張?zhí)厥獾谋?#xff1a;
.META.: 記錄了用戶所有表拆分出來的 Region 映射信息,.META. 可以有多個 Region
-ROOT-(新版中已去掉這一層): 記錄了 .META. 表的 Region 信息,-ROOT- 只有一個 Region,無論如何都不會分裂
2. Client 訪問用戶數(shù)據(jù)前需要首先訪問 ZooKeeper,找到 -ROOT- 表的 Region 所在的服務器位置,然后訪問 -ROOT- 表,接著訪問 .META. 表,最后才能找到用戶數(shù)據(jù)的服務器位置,并訪問。在這期間會有多次網絡操作,不過 Client 端會做 cache 緩存。
?
1.1.2 ZooKeeper 職責
1.1.3 Master 職責
1.1.4 RegionServer 職責
可以看出,Client 訪問 HBase 上數(shù)據(jù)的過程并不需要 Mster 的參與(尋址訪問 ZooKeeper 和 RegionServer,數(shù)據(jù)讀寫訪問 RegionServer),Master 僅僅維護著 Table 和 Region 的元數(shù)據(jù)信息,負載較低。
.META. 存儲的是所有的 Region 的位置信息,那么 RegionServer 當中的 Region 在進行分裂之后新產生的 Region 是由 Master 來決定存儲到哪個 RegionServer,這就意味著,只有 Master 知道 new Region 的位置信息,所以,由 Master 來管理 .META. 這個表當中數(shù)據(jù) CRUD(Create, Read, Update, Delete)。
所以,結合以上兩點:在沒有 Region 分裂的情況下,Master 宕機一段時間是可以忍受的。
?
1.2 物理存儲
1.2.1 整體物理結構
?
1.2.2 StoreFile 和 HFile 結構
StoreFile 以 HFile 格式保存在 HDFS 上,如下圖所示:
HFile 是不定長的,長度固定的只有其中的兩個部分:Trailer 和 FileInfo
如圖所示:
- Trailer 中有指針指向其他數(shù)據(jù)塊的起點
- FileInfo 中記錄了文件的一些 Meta 信息,例如 AVE_KEY_LEN, AVG_VALUE_LEN, LAST_KEY, COMPARATOR, MAX_SEQ_ID_KEY 等
HFile 分為六個部分:
HFile 的 Data Block,MetaBlock 通常采用壓縮方式存儲,壓縮之后可以大大減少網絡 IO 和磁盤 IO,但是這樣會增加 CPU 的開銷,用來進行壓縮和解壓。目標 HFile 支持兩種壓縮方式:GZIP, LZO
Data Block 和 Meta Index 塊記錄了每個 Data 塊和 Meta 塊的起始點。
Data Block 是 HBase I/O 的基本單元,為了提高效率,HRegionServer 中有基于 LRU 的 Block Cache 機制。每個 Data 塊的大小可以在創(chuàng)建一個 Table 的時候通過參數(shù)指定,大號的 Block 有利于順序 Scan,小號 Block 利于隨機查詢。每個 Data 塊除了開頭的 Magic 以外就是一個個 Key-Value 對拼接而成,Magic 內容就是一些隨機數(shù)據(jù),目的是防止數(shù)據(jù)損壞。
HFile 里面的每個 KeyValue 對就是一個簡單的 byte[] 數(shù)組。但是這個 byte 數(shù)組里面包含了很多項,并且有固定的結構。具體結構如下:
開始是兩個固定長度的數(shù)值,分別表示 Key 的長度和 Value 的長度,后面是 Key,Row Length 是固定長度的數(shù)值,表示 RowKey 的長度,Row 表示 RowKey,再后面是 Column Family Length,表示列簇的長度,然后是 Column Family,再后面是 Column Qualifier,表示列,然后是兩個固定長度的數(shù)值,分別是 Time Stamp 和 KeyType(Put/Delete 添加或刪除)。Value 部分沒有這么復雜的結構,就是純粹的二進制數(shù)據(jù)。
?
1.2.3 MemStore 和 StoreFile
一個 HRegion 由多個 Store 組成,每個 Store 包含一個列簇的所有數(shù)據(jù), 一個 Store 對應一個 Region 中的一個 ColumnFamily,每個 Store 包含多個 StoreFile。
Store 由位于內存的一個 MemStore 和位于磁盤的多個 StoreFile 組成。
寫操作先寫入 MemStore,當 MemStore 中的數(shù)據(jù)量達到某個閾值時候,HRegionServer 啟動 FlushCache 進程將數(shù)據(jù)寫入 StoreFile,每次寫入形成一個單獨的 HFile。
當總 StoreFile 大小超過一定閾值后,會把當前的 Region 分割成兩個,并由 HMaster 分配給相應的 Region 服務器,實現(xiàn)負載均衡。
客戶端檢索數(shù)據(jù)時,先在 MemStore 中查找,找不到再從 StoreFile 中查找。
?
1.2.4 HLog(WAL)
WAL 意為 Write Ahead Log,類似于 MySQL 中的 binlog,用來做災難恢復,HLog 記錄數(shù)據(jù)的所有變更,一旦數(shù)據(jù)修改,就可以從中進行恢復。
每個 RegionServer 維護一個 HLog,而不是每個 Region 維護一個 HLog,這樣,不同的 Region(來自不同的 Table)的日志會混在一起,這樣做的目的是不斷追加單個文件,相對于同時寫多個文件而言,可以減少磁盤尋址次數(shù),因此可以提高對 Table 的寫性能。同樣,帶來的麻煩是,如果一臺 RegionServer 下線,為了恢復其上面的 Region,需要將 RegionServer 上的 HLog 文件進行拆分,然后分發(fā)到其它 RegionServer 上進行恢復。
HLog 文件就是一個普通的 Hadoop Sequence File:
?
1.3 尋址機制
數(shù)據(jù)的訪問路徑分為 3 步:
老版本的尋址方式中有個 -ROOT- 環(huán)節(jié),新版中已經去掉,去掉 -ROOT- 的原因如下:
Note: Client 會緩存 .META. 的數(shù)據(jù),用來加快訪問。問題隨之而來,那它什么時候更新?如果 .META. 更新了,比如 Region1 不在 RegionServer2 中了,被轉移到其他 RegionServer 上了,Client 的緩存沒有更新會有什么情況發(fā)生?
其實,Client 的元數(shù)據(jù)緩存不更新,當 .META. 的數(shù)據(jù)發(fā)生更新后,Client 再次根據(jù)緩存去訪問的時候,就會出現(xiàn)錯誤,當出現(xiàn)異常達到重試次數(shù)上限后就會去 .META. 所在的 RegionServer 獲取最新的數(shù)據(jù),如果 .META. 所在的 RegionServer 也變了,Client 就會去 ZooKeeper 上獲取 .META. 所在的 RegionServer 的最新地址。
?
1.4 讀寫請求
1.4.1 讀請求的過程
為了能快速的判斷要查詢的數(shù)據(jù)在不在這個 StoreFile 中,應用了 BloomFilter
BloomFilter, 布隆過濾器:迅速判斷一個元素是不是在一個龐大的集合內,但是它有一個缺點:有一定的誤判率 --> 原來不存在于該集合的元素,布隆過濾器有可能會判斷說它存在,但是,如果布隆過濾器判斷說一個元素不存在于該集合,姥這個元素一定不存在于這個集合。
?
1.4.2 寫請求過程
HBase 在做數(shù)據(jù)插入操作時,首先要找到 RowKey 所對應的 Region,如何查找 --> 去 ZooKeeper 中查找存儲 .META. 文件的 RegionServer,然后再從 .META. 中查找存儲了要找的 Region 的 RegionServer,因為 .META. 表中存儲了每張表每個 Region 的起始 RowKey。
建議:在做海量數(shù)據(jù)的插入操作時,避免出現(xiàn)遞增 RowKey 的 put 操作
如果 put 操作的所有 RowKey 都是遞增的,那么,當插入一部分數(shù)據(jù)的時候剛好進行分裂,之后所有的數(shù)據(jù)都開始往分裂后的第二個 Region 插入,就造成了數(shù)據(jù)熱點現(xiàn)象。
細節(jié)描述:
HBase 使用 MemStore 和 StoreFile 存儲對表的更新。
數(shù)據(jù)在更新時首先寫入 HLog(WAL Log),再寫入內存(MemStore)中,MemStore 中的數(shù)據(jù)是排序的,當 MemStore 累計達到閾值(默認是 128M)時,就會創(chuàng)建一個新的 MemStore,并且將老的 MemStore 添加到 Flush 隊列,由單獨的線程 Flush 到磁盤上,成為一個新的 StoreFile。與此同時,系統(tǒng)會在 ZooKeeper 中記錄一個 Redo point,表示這個時刻之前的變更已經持久化了。當系統(tǒng)出現(xiàn)意外時,可能導致內存(MemStore)中的數(shù)據(jù)丟失,此時使用 HLog(WAL Log) 來恢復 Checkpoint 之后的數(shù)據(jù)。
MemStore 執(zhí)行 Flush 操作的觸發(fā)條件:
HBase 的有三種默認的 Split 策略:
- ConstantSizeRegionSplitPolicy
- IncreasingToUpperBoundRegionSplitPolicy
- SteppingSplitPolicy
StoreFile 是只讀的,一旦創(chuàng)建后就不可以再修改。因此 HBase 的更新/修改其實是不斷追加的操作。當一個 Store 中的 StoreFile 達到一定的閾值后,就會進行一次合并(minor_compact, major_compact),將對同一個 RowKey 的修改合并到一起,形成一個大的 StoreFile。由于對表的更新是不斷追加的,compact 時,需要訪問 Store 中全部的 StoreFile 和 MemStore,將他們按 RowKey 進行合并,由于 StoreFile 和 MemStore 都是經過排序的,并且 StoreFile 帶有內存中的索引,合并的過程還是比較快的。
Minor_Compact 和 Major_Compact 的區(qū)別:
Client 寫入數(shù)據(jù) --> 存入 MemStore,一直到 MemStore 寫滿 --> Flush 成一個 StoreFile,直至增長到一定閾值 --> 觸發(fā) Compact 合并操作 --> 多個 StoreFile 合并成一個 StoreFile,同時進行版本合并和數(shù)據(jù)刪除 --> 當 StoreFile 經過 Compact 之后,逐步形成越來越大的 StoreFile --> 單個 StoreFile 大小超過一定閾值后,觸發(fā) Split 操作,把當前 Region Split 成 2 個 Region,原來的 Region 會下線,新 Split 出來的 2 個子 Region 會被 HMaster 分配到相應的 RegionServer 上,使得原先的一個 Region 的壓力被分流到 2 個 Region 上,由此過程可知:HBase 只是增加數(shù)據(jù),所有的更新和刪除操作,都是在 Compact 階段做。所以,用戶寫操作只需要進入到內存即可立即返回,從而保證 I/O 的高性能。
寫入數(shù)據(jù)的過程補充:
工作機制:每個 RegionServer 中都會有一個 HLog 對象,HLog 是一個實現(xiàn) WAL 的類,每次用戶將數(shù)據(jù)寫入到 MemStore 的同時,也會寫一份數(shù)據(jù)到 HLog 文件,HLog 文件定期會滾動更新,并刪除舊的文件(已持久化到 StoreFile 中的數(shù)據(jù))。當 RegionServer 意外終止的時候,HMaster 會通過 ZooKeeper 感知,HMaster 首先處理遺留的 HLog 文件,將不同 Region 的數(shù)據(jù)拆分,分別放到對應的 Region 目錄下,然后再將失效的 Region(帶有剛剛拆分的 HLog)重新分配,領取到這些 Region 的 RegionServer 在 Load Region 的過程中,會發(fā)現(xiàn)有歷史 HLog 需要處理,因此會 Replay HLog 中的數(shù)據(jù)到 MemStore 中,然后 Flush 到 StoreFile,完成數(shù)據(jù)的恢復。
?
1.5 RegionServer 工作機制
1. Region 分配
任何時刻,一個 Region 只能分配給一個 RegionServer。Master 記錄了當前有哪些可用的 RegionServer,以及當前哪些 Region 分配給了哪些 RegionServer,哪些 Region 還沒有分配。當需要分配新的 Region,并且有一個 RegionServer 上有可用空間時,Master 就給這個 RegionServer 發(fā)送一個裝載請求,把 Region 分配給這個 RegionServer。RegionServer 得到這個請求后,就開始對此 Region 提供服務。
2. RegionServer 上線
Master 使用 ZooKeeper 來跟蹤 RegionServer 狀態(tài)。當某個 RegionServer 啟動時,會首先在 ZooKeeper 上的 server 目錄下創(chuàng)建一個代表自己的臨時 ZNode,由于 Master 訂閱了 server 目錄下的變更消息(Watcher),當 server 目錄下的文件出現(xiàn)新增或刪除操作時,Master 可以得到來自 ZooKeeper 的實時通知。因此一旦 RegionServer 上線,Master 就能馬上得到消息。
3. RegionServer 下線
當 RegionServer 下線時,它和 ZooKeeper 的會話就會斷開,ZooKeeper 自動刪除代表這臺 RegionServer 的 ZNode,Master 就可以確定這臺 RegionServer 節(jié)點掛了。
無論出現(xiàn)哪種情況,RegionServer 都無法繼續(xù)為它的 Region 提供服務了,此時, Master 就會將這臺 RegionServer 上的 Region 分配給其它的 RegionServer。
?
1.6 Master 工作機制
Master 上線
Master 啟動步驟如下:
Master 下線
由于 Master 只維護表和 Region 的元數(shù)據(jù),而不參與表數(shù)據(jù) I/O 的過程,Master 下線僅導致所有元數(shù)據(jù)的修改被凍結(無法創(chuàng)建、刪除表,無法修改表的 Schema,無法進行 Region 的負載均衡,無法處理 Region 的上下線,無法進行 Region 的合并,唯一例外的是 Region 的 Split 可以正常進行,因為只有 RegionServer 參與),表的數(shù)據(jù)讀寫還是可以正常進行。因此,Master 下線短時間內對整個 HBase 集群并不一定會產生影響。
從 Master 的上線過程可以看到,Master 保存的信息全是可以冗余的信息(都可以從系統(tǒng)其它地方收集或者計算得到)。因此,一般 HBase 集群中總是有一個 Master 在提供服務,還有一個以上的 Master 在等待時機搶占它的位置。
總結
- 上一篇: 常用并发工具类(并发集合类)
- 下一篇: UART串口通信浅谈之(一)--基础概述