在網上看過不少HBaes架構相關的文章,內容深淺不一,直到發現了一篇MapR官網的文章https://mapr.com/blog/in-depth-look-hbase-architecture/#.VdMxvWSqqko,寫得實在太sheng dong了。node
所以,以這篇文章做爲骨架,翻譯了許多原文的內容,同時對一些細節進行本身的擴展,造成本文。git
從物理結構上,HBase包含了三種類型的server,zookeeper、HMaster、region server,採用一種主從模式的結構。github
而底層的存儲,仍是依賴於HDFS的。面試
HBase 的tables根據rowkey的範圍進行水平切分,切分後分配到各個regions。一個region包含一個表在start key和end key全部行。region會被分配到集羣中的各個region server,而用戶都是跟region server進行讀寫交互。一個region通常建議大小在5-10G。緩存
通常也叫做HMaster,HMaster主要職責包括兩個方面:架構
HBase使用Zookeeper做爲分佈式協調服務,來維護集羣內的server狀態。負載均衡
Zookeeper經過 heartbeat 維護了哪些server是存活並可用的,並提供server的故障通知。同時,使用一致性協議來保證各個分佈式節點的一致性。分佈式
這裏,須要特別關注,zookeeper負責來HMaster的選舉工做,若是一個HMater節點宕機了,就會選擇另外一個HMaster節點進入active狀態。oop
Zookeeper用來共享分佈式系統中成員的狀態,它會和region server、HMaster(active)保持會話,經過heartbeat維持與這些ephemeral node(zk中的臨時節點概念)的活躍會話。翻譯
下面,咱們能夠看到,zk在其中起到了最核心的做用。
多個HMaster會去競爭成爲zookeeper上的臨時節點,而zookeeper會將第一個建立成功的HMaster做爲惟一當前active的HMaster,其餘HMater進入stand by的狀態。這個active的HMaster會不斷髮送heartbeat給zk,其餘stand by狀態的HMaster節點會監聽這個active HMaster的故障信息。一旦發現active HMaster宕機了,就會從新競爭新的active HMaster。這就實現了HMaster的高可用。
每一個region server會建立一個ephemeral node。HMaster會監視這些節點來確認哪些region server是可用的,哪些節點發生了故障宕機了。
若是一個region server或者active的HMaster 沒有發送heatbeat給zk,那麼和zk之間的會話將會過時,而且zk上會刪掉這個臨時節點,認爲這個節點發生故障須要下線了。
其餘監聽者節點會收到這個故障節點被刪除的消息。好比actvie的HMaster會監聽region server的消息,若是發現某個region server下線了,那麼就會從新分配region server來恢復相應的region數據。再好比,stand by的HMaster節點會監聽active 的HMaster節點,一旦收到故障通知,就會競爭上線成爲新的active HMaster。
有一個特殊的HBase目錄表,叫作META table,保存了集羣中各個region的位置。zookeeper中保存了這個meta table 的位置信息。
當咱們第一次訪問HBase集羣時,會作如下操做:
1)客戶端從zk中獲取保存meta table的位置信息,知道meta table保存在了哪一個region server,並在客戶端緩存這個位置信息;
2)client會查詢這個保存meta table的特定的region server,查詢meta table信息,在table中獲取本身想要訪問的row key所在的region在哪一個region server上。
3)客戶端直接訪問目標region server,獲取對應的row
進一步,咱們瞭解一下meta table的存儲結構。
一個region server運行在一個HDFS的data node上,而且擁有如下組件:
整個寫的過程更加複雜,而與region server的交互式最重要的一部分,這裏只介紹跟region server的交互。
主要分爲兩個步驟,寫WAL 和 寫緩存。
「實際上,這裏除了保證數據不丟,還跟提升寫入效率有關,具體後續專門寫一個相關文檔進行展開說明」
1)寫WAL
當客戶端提交了一個put 請求,那麼在region server上須要首先寫WAL(write-ahead-log)。
須要注意三點
2)寫緩存
數據寫入WAL成功,纔會繼續寫入MemStore。
而後纔會返回ack給客戶端,表示寫入成功了。
MemStore主要保存數據更新在內存中,以字典序的KeyValue形式,跟HFile裏面保存的同樣。
每個column family會有一個對應的memstore
更新的數據會在memstore中以key-value形式排好序存儲,注意看圖,按字典序排,同時按version的倒序排列。
咱們能夠看到,key的組成包括rowkey-cf-col-version。
當MemStore存儲了足夠多的數據,整個有序集會被寫入一個新的HFile文件中,保存在HDFS。
HBase中每一個colum family會有多個HFile,用來存儲實際的keyValue。
注意,這裏解釋了爲何HBase中columfaily的數量是有限制的(具體是多少?)。
每個cf有一個對應的MemStore,當一個MemStore滿了,所屬region的全部memstore都會被flush到磁盤。因此MemStore的flush的最小單位是一個region,而不是一個MemStore。
flush的同時,它還會存儲一些額外的信息,好比最後一個寫的序列號,讓系統知道它當前持久化到什麼位置了。
最大的序列號做爲元數據,會被存儲在每一個HFile中,表示持久化到哪一個位置了,下一次持久化應該從哪裏繼續。一個region啓動時,會讀取每一個HFile的序列號,而後最大的序列號會被用來做爲新的起始序列號。
HBase中,數據以有序KV的形式,存儲在HFile中。當MemStore存儲了足夠的數據,所有kv對被寫入HFile存入HDFS。
這裏寫文件的過程是順序寫,避免了硬盤大量移動磁頭的過程,比隨機寫高效不少。
HFile的邏輯結構如圖
主要分爲四個部分:Scanned block section,Non-scanned block section,Opening-time data section和Trailer。
文件中採用相似b+樹都多層索引:
文件的末尾有個trailer節點,指向了meta block。trailer節點還擁有其餘信息,好比布隆過濾器和時間範圍信息。
布隆過濾器幫助咱們過濾那些不包含在這個HFilfe中的rowkey。
時間範圍信息用來跳過那些不在這個HFilie時間範圍內的row。
所以,當一個HFile被讀取後,HFile的索引信息就會被緩存在BlockCache中,這樣使得查詢只須要一次磁盤查詢操做,後續查找只須要讀取blockcache內的索引信息便可。
region server上的實體結構關係以下:
regionserver : region = 1 : n,每一個region server上有多個region。
region : store= 1 : n,每一個region裏面有多個store
store : memstore = 1 : 1。
Memstore:Hfile = 1:n。
看到這裏了,原創不易,點個關注、點個贊吧,你最好看了~
知識碎片從新梳理,構建Java知識圖譜:https://github.com/saigu/JavaKnowledgeGraph(歷史文章查閱很是方便)
掃碼關注個人公衆號「阿丸筆記」,第一時間獲取最新更新。同時能夠免費獲取海量Java技術棧電子書、各個大廠面試題。