HBase技術簡介
一、HBase簡介
HBase – Hadoop Database,是一個高可靠性、高效能、面向列、可伸縮的分散式儲存系統,利用HBase技術可在廉價PC Server上搭建起大規模結構化儲存叢集。
HBase是Google BigTable的開源實現,類似Google BigTable利用GFS作為其檔案儲存系統,HBase利用Hadoop HDFS作為其檔案儲存系統;Google執行MapReduce來處理Bigtable中的海量資料,HBase同樣利用Hadoop MapReduce來處理HBase中的海量資料;Google Bigtable利用 Chubby作為協同服務,HBase利用Zookeeper作為對應。
上圖描述了Hadoop EcoSystem中的各層系統,其中HBase位於結構化儲存層,Hadoop HDFS為HBase提供了高可靠性的底層儲存支援,Hadoop MapReduce為HBase提供了高效能的計算能力,Zookeeper為HBase提供了穩定服務和failover機制。
此外,Pig和Hive還為HBase提供了高層語言支援,使得在HBase上進行資料統計處理變的非常簡單。 Sqoop則為HBase提供了方便的RDBMS資料匯入功能,使得傳統資料庫資料向HBase中遷移變的非常方便。
二、HBase訪問介面
-
Native Java API,最常規和高效的訪問方式,適合Hadoop MapReduce Job並行批處理HBase表資料
-
HBase Shell,HBase的命令列工具,最簡單的介面,適合HBase管理使用
-
Thrift Gateway,利用Thrift序列化技術,支援C++,PHP,Python等多種語言,適合其他異構系統線上訪問HBase表資料
-
REST Gateway,支援REST 風格的Http API訪問HBase, 解除了語言限制
-
Pig,可以使用Pig Latin流式程式語言來操作HBase中的資料,和Hive類似,本質最終也是編譯成MapReduce Job來處理HBase表資料,適合做資料統計
-
Hive,當前Hive的Release版本尚沒有加入對HBase的支援,但在下一個版本Hive 0.7.0中將會支援HBase,可以使用類似SQL語言來訪問HBase。
三、HBase資料模型
3.1 Table & Column Family
Row Key:
行鍵,Table的主鍵,用來檢索記錄。訪問HBase table中的行,只有三種方式:
- 通過單個row key訪問
- 通過row key的range
- 全表掃描
row key可以是任意字串(最大長度是 64KB,實際應用中長度一般為 10-100bytes左右),在HBase內部,row key儲存為位元組陣列。資料按照row key的字典序(byte order)排序儲存,因此設計key時要充分排序儲存這個特性,將經常一起讀取的行儲存放到一起。
HBase支援單行事務,行的一次讀寫是原子操作 (不論一次讀寫多少列),這個設計決策能夠使使用者很容易的理解程式在對同一個行進行併發更新操作時的行為。
Column Family:
列簇,Table在水平方向有一個或者多個Column Family組成,一個Column Family中可以由任意多個Column組成,即Column Family支援動態擴充套件,無需預先定義Column的數量以及型別,所有Column均以二進位制格式儲存,使用者需要自行進行型別轉換。
列名都以列族作為字首。例如’courses:history’,’courses:math’,都屬於courses 這個列族。 訪問控制、磁碟和記憶體的使用統計都是在列族層面進行的。實際應用中,列族上的控制權限能幫助我們管理不同型別的應用:我們允許一些應用可以新增新的基本資料、一些應用可以讀取基本資料並建立繼承的列族、一些應用則只允許瀏覽資料(甚至可能因為隱私的原因不能瀏覽所有資料)。
Timestamp:
時間戳,每次資料操作對應的時間戳,可以看作是資料的version number。時間戳的型別是 64位整型。時間戳可以由HBase在資料寫入時自動賦值,此時時間戳是精確到毫秒的當前系統時間;時間戳也可以由客戶顯式賦值,如果應用程式要避免資料版本衝突,就必須自己生成具有唯一性的時間戳。
為了避免資料存在過多版本造成的的管理 (包括儲存和索引)負擔,HBase提供了兩種資料版本回收方式:一是儲存資料的最後n個版本,二是儲存最近一段時間內的版本(比如最近七天)。使用者可以針對每個列族進行設定。
Cell:
由 {row key
, column family
, column qualifier
, version
} 唯一確定的單元。cell中的資料是沒有型別的,全部是位元組碼形式存貯。
3.2 Table & Region
當Table隨著記錄數不斷增加而變大後,會逐漸分裂成多份splits,成為regions,一個region由[startkey,endkey)表示,不同的region會被Master分配給相應的RegionServer進行管理:
3.3 -ROOT- && .META. Table
HBase中有兩張特殊的Table,-ROOT-和.META.
-
.META.:記錄了使用者表的Region資訊,.META.可以有多個regoin
-
-ROOT-:記錄了.META.表的Region資訊,-ROOT-只有一個region
-
Zookeeper中記錄了-ROOT-表的location
Client訪問使用者資料之前需要首先訪問zookeeper,然後訪問-ROOT-表,接著訪問.META.表,最後才能找到User Table的位置去訪問,中間需要多次網路操作,不過Client端會做cache快取。
四、HBase系統架構
Client
HBase Client使用HBase的RPC機制與HMaster和HRegionServer進行通訊,對於管理類操作,Client與HMaster進行RPC;對於資料讀寫類操作,Client與HRegionServer進行RPC
Zookeeper
Zookeeper Quorum中除了儲存了-ROOT-表的地址和HMaster的地址,HRegionServer也會把自己以Ephemeral方式註冊到Zookeeper中,使得HMaster可以隨時感知到各個HRegionServer的健康狀態。此外,Zookeeper也避免了HMaster的單點問題,見下文描述。
HMaster
HMaster沒有單點問題,HBase中可以啟動多個HMaster,通過Zookeeper的Master Election機制保證總有一個Master執行,HMaster在功能上主要負責Table和Region的管理工作:
-
管理使用者對Table的增、刪、改、查操作
-
管理HRegionServer的負載均衡,調整Region分佈
-
在Region Split後,負責新Region的分配
-
在HRegionServer停機後,負責失效HRegionServer 上的Regions遷移
-
HDFS的垃圾檔案回收
注意:Client訪問HBase上資料的過程並不需要HMaster參與(定址訪問Zookeeper和HRegionServer,資料讀寫訪問HRegioneServer),HMaster僅僅維護者table和region的元資料資訊,負載很低。
HRegionServer
HRegionServer主要負責響應使用者I/O請求,向HDFS檔案系統中讀寫資料,是HBase中最核心的模組。
注意,每個HRegsionServer維護一個HLog檔案
HRegionServer內部管理了一系列HRegion物件,每個HRegion對應了Table中的一個Region,HRegion中由多個HStore組成。每個HStore對應了Table中的一個Column Family的儲存,可以看出每個Column Family其實就是一個集中的儲存單元,因此最好將具備共同IO特性的column放在一個Column Family中,這樣最高效。
HStore
HStore 是HBase儲存的核心,其中由兩部分組成:
- MemStore
- StoreFiles。
MemStore是Sorted Memory Buffer,使用者寫入的資料首先會放入MemStore,當MemStore滿了以後會Flush成一個StoreFile(底層實現是HFile)。
Compaction:當StoreFile檔案數量增長到一定閾值,會觸發Compact合併操作,將多個StoreFiles合併成一個StoreFile,合併過程中會進行版本合併和資料刪除,因此可以看出HBase其實只有增加資料,所有的更新和刪除操作都是在後續的compact過程中進行的,這使得使用者的寫操作只要進入記憶體中就可以立即返回,保證了HBase I/O的高效能。
Split:當StoreFiles Compact後,會逐步形成越來越大的StoreFile,當單個StoreFile大小超過一定閾值後,會觸發Split操作,同時把當前Region Split成2個Region,父Region會下線,新Split出的2個孩子Region會被HMaster分配到相應的HRegionServer上,使得原先1個Region的壓力得以分流到2個Region上。下圖描述了Compaction和Split的過程:
HLog
在理解了上述HStore的基本原理後,還必須瞭解一下HLog的功能,因為上述的HStore在系統正常工作的前提下是沒有問題的,但是在分散式系統環境中,無法避免系統出錯或者宕機,因此一旦HRegionServer意外退出,MemStore中的記憶體資料將會丟失,這就需要引入HLog了。
每個HRegionServer中都有一個HLog物件,HLog是一個實現Write Ahead Log的類,在每次使用者操作寫入MemStore的同時,也會寫一份資料到HLog檔案中(HLog檔案格式見後續),HLog檔案定期會滾動出新的,並刪除舊的檔案(已持久化到StoreFile中的資料)。當HRegionServer意外終止後,HMaster會通過Zookeeper感知到,HMaster首先會處理遺留的 HLog檔案,將其中不同Region的Log資料進行拆分,分別放到相應region的目錄下,然後再將失效的region重新分配,領取 到這些region的HRegionServer在Load Region的過程中,會發現有歷史HLog需要處理,因此會Replay HLog中的資料到MemStore中,然後flush到StoreFiles,完成資料恢復。
五、HBase儲存格式
HBase中的所有資料檔案都儲存在Hadoop HDFS檔案系統上,主要包括上述提出的兩種檔案型別:
-
HFile, HBase中KeyValue資料的儲存格式,HFile是Hadoop的二進位制格式檔案,實際上StoreFile就是對HFile做了輕量級包裝,即StoreFile底層就是HFile
-
HLog File,HBase中WAL(Write Ahead Log) 的儲存格式,物理上是Hadoop的Sequence File
HFile
下圖是HFile V2的儲存格式:
HFile的組成分成四部分,分別是Scanned Block(資料block)、Non-Scanned block(元資料block)、Load-on-open(在hbase執行時,HFile需要載入到記憶體中的索引、bloom filter和檔案資訊)以及trailer(檔案尾)。
在HFile中根據一個key搜尋一個data的過程:
-
先記憶體中對HFile的root index進行二分查詢。如果支援多級索引的話,則定位到的是leaf/intermediate index,如果是單級索引,則定位到的是data block
-
如果支援多級索引,則會從快取/hdfs(分散式檔案系統)中讀取leaf/intermediate index chunk,在leaf/intermediate chunk根據key值進行二分查詢(leaf/intermediate index chunk支援二分查詢),找到對應的data block。
-
從快取/hdfs中讀取data block。
-
在data block中遍歷查詢key。
Data Block是HBase I/O的基本單元,為了提高效率,HRegionServer中有基於LRU的 Block Cache 機制。每個Data塊的大小可以在建立一個Table的時候通過引數指定(預設64K),大號的Block有利於順序Scan,小號Block利於隨機查詢。在DataBlock中儲存的是一系列KeyValue,在KeyValue後面跟一個timestamp,如下圖所示:
HFile裡面的每個KeyValue對就是一個簡單的byte陣列。但是這個byte數組裡麵包含了很多項,並且有固定的結構。KV結構圖如下:
可以看出KeyValue格式分為四個部分:KeyLength、ValueLength、Key、Value。
其中KeyLength和ValueLength都是整型,表示長度。Key有固定的格式,KeyType有四種類型,分別是Put、Delete、 DeleteColumn和DeleteFamily。Value部分沒有這麼複雜的結構,就是純粹的二進位制資料了。
HLogFile
上圖中示意了HLog檔案的結構,其實HLog檔案就是一個普通的Hadoop Sequence File,Sequence File 的Key是HLogKey物件,HLogKey中記錄了寫入資料的歸屬資訊,除了table和region名字外,同時還包括 sequence number和timestamp,timestamp是“寫入時間”,sequence number的起始值為0,或者是最近一次存入檔案系統中sequence number。
HLog Sequece File的Value是HBase的KeyValue物件,即對應HFile中的KeyValue,可參見上文描述。
六、關鍵流程
6.1 region定位
HBase如何找到某個row key (或者某個row key的range)所在的region?使用三層類似B+樹的結構來儲存region位置:
- 第一層:Zookeeper儲存了-ROOT-表的位置。
- 第二層:-ROOT- 表儲存了.META.表所有region的位置,通過-ROOT-表,可以訪問.META.表的資料。
- 第三層:.META.是一個特殊的表,儲存了HBase中所有資料表的region位置資訊。
需要注意的是:
- -ROOT-表永遠不會被split,保證了只需要三次跳轉,就能定位到任意region
- META.表每行儲存一個region的位置資訊,row key採用表名+表的最後一行編碼而成
- 為了加快訪問,.META.表的全部region都儲存在記憶體中
- Client會將查詢過的位置資訊儲存快取起來,快取不會主動失效
6.2 region分配
任何時刻,一個region只能分配給一個HRegionServer。HMaster記錄了當前有哪些可用的HRegionServer。以及當前哪些region分配給了哪些HRegionServer,哪些region還沒有分配。當存在未分配的region,並且有一個HRegionServer上有可用空間時,HMaster就給這個HRegionServer傳送一個裝載請求,把region分配給這個HRegionServer。HRegionServer得到請求後,就開始對此region提供服務。
6.3 寫請求處理
資料在更新時首先寫入Log(WAL log)和記憶體(MemStore)中,MemStore中的資料是排序的,當MemStore累計到一定閾值時,就會建立一個新的MemStore,並且將老的MemStore新增到flush佇列,由單獨的執行緒flush到磁碟上,成為一個StoreFile。與此同時,系統會在Zookeeper中記錄一個redo point,表示這個時刻之前的變更已經持久化了。
當系統出現意外時,可能導致記憶體(MemStore)中的資料丟失,此時使用Log(WAL log)來恢復checkpoint之後的資料。
前面提到過StoreFile是隻讀的,一旦建立後就不可以再修改。因此HBase的更新其實是不斷追加的操作,所有的更新和刪除操作都是在後續的compact過程中進行的,這使得使用者的寫操作只要 進入記憶體中就可以立即返回,保證了HBase I/O的高效能。
6.4 讀請求處理
如果想快速讀取資料,通用的原則是資料保持有序 並 儘可能儲存在記憶體裡。HBase實現了這兩個目標。
- HBase提供三維有序儲存,首先以rowkey字典序,然後以column family + column qualifier字典序,最後單元格是以timestamp時間戳降序排序。
- HBase讀操作使用了LRU快取技術,這種快取叫做BlockCache,用來儲存從HFile裡讀入記憶體的頻繁訪問的資料。
從HBase讀資料,會依次訪問三個地方:首先檢查MemStore,然後檢查BlockCache,最後才會訪問硬碟上的對應HFile。
6.5 Compact/Split
上文已經講到,當StoreFile檔案數量達到一定閾值,會觸發compaction;當單個StoreFile大小超過一定閾值後,會觸發split。
Compaction分為兩種:major compaction(大合併)和 minor compaction(小合併)
-
minor compaction把多個小HFile合併成一個大HFile,主要是為了提高讀效率(因為一個row可能散佈在多個HFile檔案中)。minor compaction不做任何刪除資料、過期資料的清理工作。
-
major compaction是把給定region的一個列族的所有HFile合併成一個檔案,major compaction會丟棄有刪除標記的或過期的內容,釋放佔用的空間。
-
minor合併是輕量級的,可以頻繁發生;major合併相當耗資源,不要經常使用,且通常需要手工觸發。
Split操作過程完成的非常快,因為原始的資料檔案並不會被改變,系統只是簡單的建立兩個Reference檔案指向原始的資料檔案,每個Reference檔案管理原始檔案一半的資料。Reference檔名字是一個ID,它使用被參考的region的名字的hash作為字首,例如:1278437856009925445.3323223323。Reference檔案只含有非常少量的資訊,這些資訊包括被分割的原始region的key以及這個檔案管理前半段還是後半段。只有當系統做compaction的時候原始資料檔案才會被分割成兩個獨立的檔案並放到相應的region目錄下面,同時原始資料檔案和那些Reference檔案也會被清除。
6.6 HRegionServer上線和下線
HMaster使用Zookeeper來跟蹤HRegionServer狀態。當某個HRegionServer啟動時,會首先在Zookeeper上的server目錄下建立代表自己的檔案,並獲得該檔案的獨佔鎖。由於HMaster訂閱了server目錄上的變更訊息,當server目錄下的檔案出現新增或刪除操作時,HMaster可以得到來自Zookeeper的實時通知。因此一旦HRegionServer上線,HMaster能馬上得到訊息。
當HRegionServer下線時,它和Zookeeper的會話斷開,Zookeeper自動釋放代表這臺server的檔案上的獨佔鎖。而HMaster不斷輪詢server目錄下檔案的鎖狀態,如果發現某個HRegionServer丟失了它自己的獨佔鎖(或者HMaster連續幾次和HRegionServer通訊都無法成功),HMaster就會去嘗試獲取代表這個HRegionServer的讀寫鎖,一旦獲取成功,就可以確定:
- 可能性一:HRegionServer和Zookeeper之間的網路斷開了;
- 可能性二:HRegionServer掛了;
的其中一種情況發生了,無論哪種情況,HRegionServer都無法繼續為它的region提供服務了,此時HMaster會刪除server目錄下代表這臺HRegionServer的檔案,並將這臺HRegionServer的region分配給其它還活著的HRegionServer。
如果網路短暫出現問題導致HRegionServer丟失了它的鎖,那麼HRegionServer重新連線到Zookeeper之後,只要代表它的檔案還在,它就會不斷嘗試獲取這個檔案上的鎖,一旦獲取到了,就可以繼續提供服務。
6.7 HMaster上線和下線
HMaster啟動會依次進行以下步驟:
- 從Zookeeper上獲取唯一一個master的鎖,用來阻止其它HMaster成為工作HMaster。
- 掃描Zookeeper上的server目錄,獲得當前可用的HRegionServer列表。
- 和2中的每個HRegionServer通訊,獲得當前已分配的region和HRegionServer的對應關係。
- 掃描.META.中region的集合,計算得到當前還未分配的region,將他們放入待分配region列表。
由於HMaster只維護表和region的元資料,而不參與表資料IO的過程,因此HMaster下線僅導致所有元資料的修改被凍結(無法建立刪除表,無法修改表的schema,無法進行region的負載均衡,無法處理region上下線,無法進行region的合併,唯一例外的是region的split可以正常進行,因為只有HRegionServer參與),表的資料讀寫還可以正常進行。因此HMaster下線短時間內對整個HBase叢集沒有影響。
從上線過程可以看到,HMaster儲存的資訊全是可以冗餘資訊(都可以從系統其它地方收集到或者計算出來),因此,一般HBase叢集中總是有一個HMaster在提供服務,還有一個以上的HMaster在等待時機搶佔它的位置。
七、結束
本文轉至加駿hbase