一. 系統架構
1. 架構圖
- 錯誤架構圖 這張圖是有一個錯誤點:應該是每一個 RegionServer 就隻有一個 HLog,而不是一個 Region 有一個 HLog。
- 正确圖解 從HBase的架構圖上可以看出,HBase中的元件包括Client、Zookeeper、HMaster、HRegionServer、HRegion、Store、MemStore、StoreFile、HFile、HLog等,接下來介紹他們的作用。
2. 相關元件
1. Client
- HBase 有兩張特殊表:
- .META.:記錄了使用者所有表拆分出來的的 Region 映射資訊,.META.可以有多個 Regoin
- -ROOT-:記錄了.META.表的 Region 資訊,-ROOT-隻有一個 Region,無論如何不會分裂
- Client 通路使用者資料前需要首先通路 ZooKeeper,找到-ROOT-表的 Region 所在的位置,然 後通路-ROOT-表,接着通路.META.表,最後才能找到使用者資料的位置去通路,中間需要多次 網絡操作,不過 client 端會做 cache 緩存。
2. ZooKeeper
- ZooKeeper 為 HBase 提供 Failover 機制,選舉 Master,避免單點 Master 單點故障問題
- 存儲所有 Region 的尋址入口:-ROOT-表在哪台伺服器上。-ROOT-這張表的位置資訊
- 實時監控 RegionServer 的狀态,将 RegionServer 的上線和下線資訊實時通知給 Master
- 存儲 HBase 的 Schema,包括有哪些 Table,每個 Table 有哪些 Column Family
3. Master
- 為 RegionServer 配置設定 Region
- 負責 RegionServer 的負載均衡
- 發現失效的 RegionServer 并重新配置設定其上的 Region
- HDFS 上的垃圾檔案(HBase)回收
- 處理 Schema 更新請求(表的建立,删除,修改,列簇的增加等等)
4. RegionServer
- RegionServer 維護 Master 配置設定給它的 Region,處理對這些 Region 的 IO 請求
- 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 當機一段時間是可以忍受的。
5. HRegion
-
table在行的方向上分隔為多個Region。Region是HBase中分布式存儲和負載均衡的最小單元,即不同的region可以分别在不同的Region Server上,但同一個Region是不會拆分到多個server上。
Region按大小分隔,每個表一般是隻有一個region。随着資料不斷插入表,region不斷增大,當region的某個列族達到一個門檻值時就會分成兩個新的region。
- 每個region由以下資訊辨別:< 表名,startRowkey,建立時間>
- 由目錄表(-ROOT-和.META.)記錄該region的endRowkey
6. Store
- 每一個region由一個或多個store組成,至少是一個store,hbase會把一起通路的資料放在一個store裡面,即為每個 ColumnFamily建一個store,如果有幾個ColumnFamily,也就有幾個Store。一個Store由一個memStore和0或者 多個StoreFile組成。 HBase以store的大小來判斷是否需要切分region
7. MemStore
- memStore 是放在記憶體裡的。儲存修改的資料即keyValues。當memStore的大小達到一個閥值(預設128MB)時,memStore會被flush到文 件,即生成一個快照。目前hbase 會有一個線程來負責memStore的flush操作。
8. StoreFile
- memStore記憶體中的資料寫到檔案後就是StoreFile,StoreFile底層是以HFile的格式儲存。
9. HFile
- HBase中KeyValue資料的存儲格式,HFile是Hadoop的 二進制格式檔案,實際上StoreFile就是對Hfile做了輕量級包裝,即StoreFile底層就是HFile
10. HLog
- HLog(WAL log):WAL意為write ahead log,用來做災難恢複使用,HLog記錄資料的所有變更,一旦region server 當機,就可以從log中進行恢複。
- HLog檔案就是一個普通的Hadoop Sequence File, Sequence File的value是key時HLogKey對象,其中記錄了寫入資料的歸屬資訊,除了table和region名字外,還同時包括sequence number和timestamp,timestamp是寫入時間,sequence number的起始值為0,或者是最近一次存入檔案系統中的sequence number。 Sequence File的value是HBase的KeyValue對象,即對應HFile中的KeyValue。
二. 實體存儲
1. 整體的實體架構
- Table 中的所有行都按照 RowKsey 的字典序排列。
- Table 在行的方向上分割為多個 HRegion。
- HRegion 按大小分割的(預設 10G),每個表一開始隻有一個 HRegion,随着資料不斷插入 表,HRegion 不斷增大,當增大到一個閥值的時候,HRegion 就會等分會兩個新的 HRegion。 當表中的行不斷增多,就會有越來越多的 HRegion。
- HRegion 是 Hbase 中分布式存儲和負載均衡的最小單元。最小單元就表示不同的 HRegion 可以分布在不同的 HRegionserver 上。但一個 HRegion 是不會拆分到多個 server 上的。
- HRegion 雖然是負載均衡的最小單元,但并不是實體存儲的最小單元。事實上,HRegion 由一個或者多個 Store 組成,每個 Store 儲存一個 Column Family。每個 Strore 又由一個 memStore 和 0 至多個 StoreFile 組成
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,然後是兩個固定長度的數值,表示 Time Stamp 和 Key Type(Put/Delete)。Value 部分沒有這麼複雜的結構,就是純粹的二進制資料了。
3. MemStore 和 StoreFile
- 一個 Hregion 由多個 Store 組成,每個 Store 包含一個列族的所有資料。
- Store 包括位于記憶體的一個 memstore 和位于硬碟的多個 storefile 組成。
- 寫操作先寫入 memstore,當 memstore 中的資料量達到某個門檻值,HRegionServer 啟動 flushcache 程序寫入 storefile,每次寫入形成單獨一個 Hfile。
- 當總 storefile 大小超過一定門檻值後,會把目前的 region 分割成兩個,并由 HMaster 配置設定給相 應的 region 伺服器,實作負載均衡。
- 用戶端檢索資料時,先在 memstore 找,找不到再找 storefile。
4. Hbase WAL HLog預寫
- 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,需要将 region server 上的 log 進行拆分,然後分發到其它 region server 上進行恢複。
- HLog 檔案就是一個普通的 Hadoop Sequence File(序列化檔案):
- HLog Sequence File 的 Key 是 HLogKey 對象,HLogKey 中記錄了寫入資料的歸屬資訊,除 了 table 和 region 名字外,同時還包括 sequence number 和 timestamp,timestamp 是”寫入 時間”,sequence number 的起始值為 0,或者是最近一次存入檔案系統中 sequence number。
- HLog Sequece File 的 Value 是 HBase 的 KeyValue 對象,即對應 HFile 中的 KeyValue。
5. Region 尋址機制
既然讀寫都在 RegionServer 上發生,我們前面有講到,每個 RegionSever 為一定數量的 Region 服務,那麼 Client 要對某一行資料做讀寫的時候如何能知道具體要去通路哪個 RegionServer 呢?那就是接下來我們要讨論的問題
1. 老的 Region 尋址方式
- 在 HBase-0.96 版本以前,HBase 有兩個特殊的表,分别是-ROOT-表和.META.表,其中-ROOT的位置存儲在 ZooKeeper 中,-ROOT-本身存儲了.META. Table 的 RegionInfo 資訊,并且-ROOT不會分裂,隻有一個 Region。而.META.表可以被切分成多個 Region。讀取的流程如下圖所示:
- 詳細步驟:
- Client 請求 ZooKeeper 獲得-ROOT-所在的 RegionServer 位址
- Client 請求-ROOT-所在的 RS 位址,擷取.META.表的位址,Client 會将-ROOT-的相關 資訊 cache 下來,以便下一次快速通路
- Client 請求.META.表的 RegionServer 位址,擷取通路資料所在 RegionServer 的位址, Client 會将.META.的相關資訊 cache 下來,以便下一次快速通路
- 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-表了。
2. 新的 Region 尋址方式
- 如上面的計算,2 層結構其實完全能滿足業務的需求,是以 0.96 版本以後将-ROOT-表去掉了。 如下圖所示
- 通路路徑變成了 3 步:
- Client 請求 ZooKeeper 擷取.META.所在的 RegionServer 的位址。
- Client 請求.META.所在的 RegionServer 擷取通路資料所在的 RegionServer 位址,Client 會将.META.的相關資訊 cache 下來,以便下一次快速通路。
- 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. 讀資料流程
- Client先通路zookeeper,從meta表讀取region的位置,然後讀取meta表中的資料。meta中又存儲了使用者表的region資訊;
- 根據namespace、表名和rowkey在meta表中找到對應的region資訊;
- 找到這個region對應的regionserver;
- 查找對應的region;
- 先從MemStore找資料,如果沒有,再到BlockCache裡面讀;
- BlockCache還沒有,再到StoreFile上讀(為了讀取的效率);
- 如果是從StoreFile裡面讀取的資料,不是直接傳回給用戶端,而是先寫入BlockCache,再傳回給用戶端。
2. 寫資料流程
- Client 先根據 RowKey 找到對應的 Region 所在的 RegionServer
- Client 向 RegionServer 送出寫請求
- RegionServer 找到目标 Region
- Region 檢查資料是否與 Schema 一緻
- 如果用戶端沒有指定版本,則擷取目前系統時間作為資料版本
- 将更新寫入 WAL Log
- 将更新寫入 Memstore
- 判斷 Memstore 的是否需要 flush 為 StoreFile 檔案。
四. 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 配置設定給其它還 活着的同志。
五. Master 工作機制
1. Master 上線
Master 啟動進行以下步驟:
- 從 ZooKeeper 上擷取唯一一個代表 Active Master 的鎖,用來阻止其它 Master 成為 Master。
- 掃描 ZooKeeper 上的 server 父節點,獲得目前可用的 RegionServer 清單。
- 和每個 RegionServer 通信,獲得目前已配置設定的 Region 和 RegionServer 的對應關系。
- 掃描.META. Region 的集合,計算得到目前還未配置設定的 Region,将他們放入待配置設定 Region 清單。
2. Master 下線
由于 Master 隻維護表和 Region 的中繼資料,而不參與表資料 IO 的過程,Master 下線僅 導緻所有中繼資料的修改被當機(無法建立删除表,無法修改表的 schema,無法進行 Region 的負載均衡,無法處理 Region 上下線,無法進行 Region 的合并,唯一例外的是 Region 的 split 可以正常進行,因為隻有 RegionServer 參與),表的資料讀寫還可以正常進行。是以 Master 下線短時間内對整個 hbase 叢集沒有影響。
從上線過程可以看到,Master 儲存的資訊全是可以備援資訊(都可以從系統其它地方 收集到或者計算出來)
是以,一般 HBase 叢集中總是有一個 Master 在提供服務,還有一個以上的 Master 在等 待時機搶占它的位置。
六. 資料flush過程
- 當MemStore資料達到門檻值(預設是128M,老版本是64M),将資料刷到硬碟,将記憶體中的資料删除,同時删除HLog中的曆史資料;
- 并将資料存儲到HDFS中;
- 在HLog中做标記點。
七. 資料合并過程
- 當資料塊達到3塊,Hmaster觸發合并操作,Region将資料塊加載到本地,進行合并;
- 當合并的資料超過256M,進行拆分,将拆分後的Region配置設定給不同的HregionServer管理;
- 當HregionServer當機後,将HregionServer上的hlog拆分,然後配置設定給不同的HregionServer加載,修改.META.;
- 注意:HLog會同步到HDFS。