1. 程式人生 > >4、HBase 分散式資料庫

4、HBase 分散式資料庫

一、HBase 定義

 

HBase 是一個高可靠性、高效能、面向列、可伸縮的分散式儲存系統。適合於儲存大表資料(表的規模可以達到數十億行以及數百萬列),並且對大表資料的讀、寫訪問可以達到實時級別;利用 Hadoop HDFS(Hadoop Distributed File System)作為其檔案儲存系統,提供實時讀寫的分散式資料庫系統;利用 ZooKeeper 作為協同服務。

Hbase 作為一個分散式的大資料資料庫系統,首先提供的就是高可靠性,由於在大資料系統中,我們需要保證整體資料的安全性和可靠性,所以 Hbase 也提供了自己所需要的相關的安全性保障,首先,Hbase 借力於外部元件,比如 HDFS, Hbase 將自己的檔案寫入到 HDFS 中,這就藉助 HDFS 的資料安全性保障,保證了其資料的可靠性儲存,並且主備叢集之間的容災能力可以增強 HBase 資料的高可用性, 主叢集提供資料服務,備用叢集提供資料備份,當主叢集出現故障時,備叢集可以提供資料服務。這裡 Hbase 通過主備的形式來進行資料的安全性保障,實際上是借鑑了儲存中主備容災的相關思想,我們可以通過儲存裝置來實現應用級別的容災保護,也可以通過 HBase 自己的程序來實現相關的容災效能。HBase 叢集容災作為提高 HBase 集群系統高可用性的一個關鍵特性,為 HBase 提供了實時的異地資料容災功能。它對外提供了基礎的運維工具,包含災備關係維護,重建,資料校驗,資料同步進展檢視等功能。為了實現資料的實時容災,可以把本 HBase 叢集中的資料備份到另一個叢集。如上所說的是我們針對於應用和資料的保護, 那麼程序的保護和 HDFS 很類似,組價內的程序底層次元件依賴於高層次元件來進行容災保護,比如 Region 失效之後,需要 HMaster 來進行相關的遷移等操作, 那麼高層次的元件依賴於 Zookeeper 來進行保護。這樣就在程序上做了保護。高效能主要是面向於使用者的實際讀取操作,和其他相關的元件一樣,Hbase 作為大資料的儲存系統,一樣是讀多寫少的這種應用場景,所以如何實現高效率的讀取操作就是 Hbase 所需要做的很重要的一個工作。那麼 Hbase 首先通過了分散式的叢集保證了整體效能能夠滿足需求,其次還根據了 key-value 的形式保障了整體讀取的高效性,另外 Hbase 還支援二級索引。

HBase    是一個 Key-Value    型別的分散式儲存資料庫。每張表的資料,是按照RowKey 的字典順序排序的,因此,如果按照某個指定的 RowKey 去查詢資料,或者指定某一個 RowKey 範圍去掃描資料時,HBase 可以快速定位到需要讀取的資料位置,從而可以高效地獲取到所需要的資料。在實際應用中,很多場景是查詢某一個列值為 XXX 的資料。HBase 提供了 Filter 特性去支援這樣的查詢,它的原理是:按照 RowKey 的順序,去遍歷所有可能的資料,再依次去匹配那一列的值,直到獲取到所需要的資料。可以看出,可能僅僅為了獲取一行資料,它卻掃描了很多不必要的資料。因此,如果對於這樣的查詢請求非常頻繁並且對查詢效能要求較高,使用 Filter 無法滿足這個需求。我們傳統的時候,進行資料索引都是通過 key 值來進行的,那麼我們可以根據自己所關注的相關列,對其建立一個二級索引表,這次我們在進行索引的時候,就可以直接根據二級索引表來查詢匹配的資料,而不是根據 Rowkey 的值遍歷資料進行查詢。

和傳統的資料庫不同的是,傳統資料庫是面向於行的儲存,我們也可以稱之為是面向於業務的,這個時候我們建立表格,都是預先定義好列的,然後向裡面一行一行的新增資料資訊。這樣的話,拓展性會很差。不能完全適應大資料的相關處理。那麼在 Hbase 中,我們採用了面向於列的儲存,那麼這樣儲存的話,底層是按照列的形式來維護資料,進行實際的儲存操作,我們也可以進行屬性的拓展。那麼在實際的業務中,面向於行的儲存多用於實際的業務操作,因為業務中,我們新增資訊都是按照行儲存的思維來進行的,一次性新增一行資訊。面向於列的儲存主要用於資料分析和資料探勘,我們在進行分析的時候主要是關注某一個屬性對於分析結果的影響,比如,年齡對於購買電子產品的一個相關關聯性,這個時候我們的關注點就是年齡屬性和是否會購買的結果,而對於其他的屬性就不會更多的關注。面向於行的儲存,一次可以完整的讀取出所有的資訊,但是在進行資料分析或者使用者在進行條目讀取時有特殊需求的情況下,資料就會多讀取一部分。如果是面向於列的儲存,對於關注點很明確的資料請求會很適合,但是如果需要完整的讀取出某一個數據,就必須需要下發多次資料讀取請求。

HBase 適合具有如下需求的應用:(1)海量資料(TB、PB)

海量資料的適應性主要取決於兩個角度,首先第一個就是 Hbase 借力於 HDFS 元件,可以藉助到 HDFS 的儲存無限拓展能力。雖然 HDFS 可以無限拓展,但是 Hbase 本身能否承載這麼多資料的表格載入也是一個需要考量的問題,所以 Hbase 本身也提供了對於海量資料的支援能力,尤其體現在效能方面,為了能夠正常的使用和查詢讀取資料,那麼在海量資料的情況下,Hbase 提供了非常優秀的基於 key-value 形式的索引,並且華為自身還做了對應特性的增強,添加了二級索引機制。

(2)高吞吐量

高吞吐量主要體現在資料的流式匯入和匯出等機制,HDFS 雖然給 Hbase 提供了海量資料的基礎,但是 Hbase 本身也需要能夠接收和處理這些資料,就好比於水管,總的水管容量再大,分枝水管過細,水流量也不會很高。所以 Hbase 在自身的基礎上,就加強了對於海量資料的高吞吐量支援。

(4) 需要在海量資料中實現高效的隨機讀取實現方式為 key-value 和二級索引機制

(4)需要很好的效能伸縮能力這裡主要體現的就是基於列儲存的良好的拓展性。

(5)能夠同時處理結構化和非結構化的資料(6)不需要完全擁有傳統關係型資料庫所具備的 ACID 特性

ACID 原則是資料庫事務正常執行的四個特性,分別指原子性、一致性、獨立性及永續性。

(1) 原子性(Atomicity):指一個事務要麼全部執行,要麼不執行.也就是說一個事務不可能只執行了一半就停止了.比如你從取款機取錢,這個事務可以分成兩個步驟:1 劃卡,2 出錢.不可能劃了卡,而錢卻沒出來.這兩步必須同時完成.要麼就不完成。

(2) 一致性(Consistency):指事務的執行並不改變資料庫中資料的一致性.例如,完整性約束了 a+b=10,一個事務改變了 a,那麼 b 也應該隨之改變。

(3) 獨立性(Isolation):事務的獨立性也有稱作隔離性,是指兩個以上的事務不會出現交錯執行的狀態.因為這樣可能會導致資料不一致。

(4) 永續性(Durability):事務的永續性是指事務執行成功以後,該事務所對資料庫所作的更改便是持久的儲存在資料庫之中,不會無緣無故的回滾。

二、資料結構

(1)結構化資料:具有固定的結構,屬性劃分,以及型別等資訊。我們通常所理解的關係型資料庫中所儲存的資料資訊,大多是結構化資料,如職工資訊表,擁有 ID、Name、Phone、Address 等屬性資訊。通常直接存放在資料庫表中。資料記錄的每一個屬性對應資料表的一個欄位。

(2)非結構化資料:無法用統一的結構來表示。如文字檔案、影象、視訊、聲音、網頁等資訊。資料記錄較小時(如 KB 級別),可考慮直接存放到資料庫表中(整條記錄對映到某一個列中),這樣也有利於整條記錄的快速檢索。資料較大時,通常考慮直接存放在檔案系統中。資料庫可用來存放相關資料的索引資訊。(3)半結構化資料:具有一定的結構,但又有一定的靈活可變性。典型如 XML、 HTML 等資料。其實也是非結構化資料的一種。可以考慮直接轉換成結構化資料進行儲存。根據資料記錄的大小和特點,選擇合適的儲存方式。這一點與非結構化資料的儲存類似。

行儲存和列儲存概念(1)按行儲存型別:資料按行儲存在底層檔案系統中。通常,每一行會被分配固定的空間。優點:有利於增加/修改整行記錄等操作;有利於整行資料的讀取操作。缺點:單列查詢時,會讀取一些不必要的資料。

(2)按列儲存型別:資料以列為單位,儲存在底層檔案系統中。

優點:有利於面向單列資料的讀取/統計等操作。缺點:整行讀取時,可能需要多次 I/O 操作。

 

 

HBase 包含模組:(1)HMaster

在 HA 模式下,包含主用 Master 和備用 Master。

①主用 Master:負責 HBase 中 RegionServer 的管理,包括表的增刪改查; RegionServer 的負載均衡,Region 分佈調整;Region 分裂以及分裂後的 Region 分配;RegionServer 失效後的 Region 遷移等。

②備用 Master:當主用 Master 故障時,備用 Master 將取代主用 Master 對外提供服務。故障恢復後,原主用 Master 降為備用。

和 HDFS 不同的是,在 HDFS 中,NameNode 的備用節點是在工作狀態的,並且會執行元資料持久化的操作,但是在 Hbase 中,備 Hmaster 是沒有承擔任何工作的,只處於是一個簡單的熱備狀態。和以往的逐層進行管理的模型不同的是, HMaster 作為最高層的管理程序,除了負責 regionServer 的管理以外,還對底層的 Region 進行了管理,由於 Hbase 認為 RegionServer 並不安全,所以就將 Region 的管理放在了自身進行維護,這個主要原因是 RegionServer 作為 Region

的管理,是沒有備份程序存在的,一旦 RegionServer 出現了故障,那麼底層的 Region 就無法進行訪問了。而 HMaster 將 Region 放在自身進行維護之後,一旦 RegionServer 出現了故障,那麼就可以直接將 Region 程序進行遷移操作,並且將對應的讀寫許可權交給其他的 RegionServer,這種情況只限程序出現故障的情況,如果是節點整體的故障,根據情況如果資料是儲存在 HDFS 上的,那麼根據 HDFS 的副本機制,資料還是可以正常找回的,如果是 Hbase 自身維護儲存資料,那麼同樣 Region 也是會故障的。

(2)RegionServer

RegionServer 負責提供表資料讀寫等服務,是 HBase 的資料處理和計算單元。

RegionServer 一般與 HDFS 叢集的 DataNode 部署在一起,實現資料的儲存功能。就像如上所說,RegionServer 這裡需要負責的是對 Region 的讀寫,這個很像是

DataNode,只有使用的許可權,沒有管理的許可權。由於 RegionServer 本身在設計時就沒有設計管理的許可權,所以對於 RegionServer 來說,雖然稱之為RegionServer,但是其實際上並沒有服務管理的含義只有核心處理的功能,相當於每次使用者提交了關於資料庫的讀寫請求之後,RegionServer 只做了相關的處理操作。受理使用者的請求,對使用者的命令進行解析,並且轉化為對應的讀寫操作和 Zookeeper 以及 Region 進行相關的任務操作執行,並且將最終執行返回的結果進行整合,並返回使用者進行檢視。

HBase 協作元件: ZooKeeper

ZooKeeper 為 HBase 叢集中各程序提供分散式協作服務。各 RegionServer 將自己的資訊註冊到 Zookeeper 中,主用 Master 據此感知各個 RegionServer 的健康狀態。

這裡我們說 Zookeeper 提供的是分散式的協作服務,所謂說協作服務,主要體現在程序安全性和資料查詢兩個角度。所謂說程序安全性就是由 Zookeeper 保證整體程序的執行安全,這方面上 Zookeeper 主要做兩件事,第一件事就是在 Hbase 程序啟動之初,需要裁決主備 HMaster 程序,決定由哪一個程序來提供服務,另外一個程序進入到熱備狀態。第二件事就是做 HBASE 的 MetaRegion 程序的同步工作。由於整體 Hbase 維護的時候都是維護的一個整體名稱空間。所以在實際上進行資料的讀寫操作時,如果按照動態子樹的思想進行資料的查詢工作,也就是指將元資料資訊分佈到各個節點進行維護,這樣做就可能會導致讀寫的延遲增加,造成資料庫修改的低效,畢竟在資料庫中,對於使用者業務或者是對延遲有要求的業務來說,延遲增加是一個致命的問題。所以為了保證整體查詢的高效性,需要元資料被整體維護,而不是切分維護。所以我們選擇將元資料存放在 Zookeeper 上,這是由於 Zookeeper 本身可以不僅提供高可靠性的資料安全保證,而且在進行元資料查詢等操作的時候還可以提供一個高效的多程序併發的查詢環境。

為什麼不將元資料 Region 存放在 HMaster 上?

這個問題就涉及到了一個整個 Hadoop 設計時的核心問題,就是如何保證程序的安全性?在前面的文件中,我們也已經解釋過,對於 Hadoop 來說,它本身是認為硬體永遠不可靠,所以 Hadoop 保證自身安全性和穩定性是不會使用到任何的硬體技術的,所以它就需要通過自身機制來達到可靠性保護的目的。目前 Hadoop 主要使用的方法就是分層保護,一個元件內,底層的程序由高層程序來保護,高層程序由 Zookeep 來保護,Zookeeper 由自身機制提供高容錯性和高可靠性保護。例如在 Hbase 中,RegionServer 安全性由 HMaster 保護,HMaster 由 Zookeeper

保護。那麼元資料作為 Hbase 中重要的資料資訊,為了能夠提供一個高效的讀寫訪問,Hbase 是將元資料檔案載入進記憶體中進行讀寫的,但是這樣做一旦出現問題就會導致資料丟失(資料庫的持久化問題),如果我們將元資料載入進 HMaster 程序進行訪問,主備程序本身其實可以有保護資料的條件,但是實際上由於備程序是處於不使用狀態的,所以僅僅只有一個程序維護和管理元資料是存在安全隱患的,所以我們需要一個安全的並且存在資料多副本的機制來進行相關的保護,這個時候就會使用到 Zookeeper 了,Zookeeper 不僅可以提供資料的安全性保證而且程序是存在副本機制的。所以我們會把資料寫入到 Zookeeper 中而不是HMaster 中進行保護。

HDFS

HDFS 為 HBase 提供高可靠的檔案儲存服務,HBase 的資料全部儲存在 HDFS 中。實際上,我們可以發現在 Hbase 中,很多關於保護的相關操作都是由外部元件來實現的,Hbase 實現了一個非常良好的元件直接的協同互動,這樣也可以保證相同的功能不會在元件之間產生冗餘的情況。所以關於資料的保護,Hbase 對資料的保護其實都是由 HDFS 來實現的,具體就可以理解為是 HDFS 的多資料副本機制來實現的。

1.Region

將一個數據表按 Key 值範圍橫向劃分為一個個的子表,實現分散式儲存。這個子表,在 HBase 中被稱作“Region”。每一個 Region 都關聯一個 Key 值範圍,即一個使用 StartKey 和 EndKey 描述的區間。事實上,每一個  Region  僅僅記錄  StartKey  就可以了,因為它的EndKey 就是下一個 Region 的 StartKey。

資料庫中實際記錄的就是一個個的表格,在實際進行儲存的時候,因為表的規模比較大,那麼在進行儲存的時候,如果整表進行維護那麼對於資料的快速查詢就會產生對應的問題。但是如果要是一條一條對資料進行維護,相應的維護開銷又會很大,所以我們選擇將一個完整的表劃分為多個分割槽進行維護,按照幾行幾行的形式,那麼每一個分割槽我們就稱之為是一個 Region,按照 Region 進行分割槽我們可以保證對資料一個較好的維護。

 

Region 分為元資料 Region 以及使用者 Region 兩類。Meta Region 記錄了每一個 User Region 的路由資訊。讀寫 Region 資料的路由,包括如下幾步:

(1) 找尋 Meta Region 地址。(2) 再由 Meta Region (3) 找尋 User Region 地址。

這裡需要說明的是對於 Region 的操作我們實際上分為了兩部分,一般來說,我們會將對資料的操作引擎和元資料放在一起,但是在 Hbase 中,我們沒有這麼做, 具體原因前面已經說明,Region 分為了資料操作和元資料操作兩個部分,一個使用者如果想要對 Region 進行讀寫,那麼首先需要做的就是向 Zookeeper 查詢元資料,之後就需要由 RegionServer 來執行具體的讀寫操作。使用者 Region 就相當於是資料,那麼路由其實指的是對資料儲存的路徑資訊,和其他相關的屬性資訊, 由於 Zookeeper 維護 MetaRegion,所以元資料在整合起來之後,如何根據元資料的資訊查詢到資料的位置就需要詳細的區分,這時候 MetaRegion中記錄的地址資訊就被稱之為是路由資訊,通過 MetaRegion 中的路由資訊進行定址就可以找到對應資料的儲存位置。那麼儲存位置主要有以下幾部分,機架號,節點號, 具體的儲存邏輯位置三個大的部分。

RegionServer 是 HBase 的資料服務程序。負責處理使用者資料的讀寫請求。 Region 被交由 RegionServer 管理。實際上,所有使用者資料的讀寫請求,都是和 RegionServer 上的 Region 進行互動。

Region 可以在 RegionServer 之間發生轉移。

RegionServer 這裡只負責做關於 Region 的讀寫操作,但是具體的維護和管理操作是不交由 RegionServer 來進行維護的,這個思想就很類似於 MapReduce 中的 NM 節點,自身擁有對資源的所有權,但是管理權卻不再自身,需要交由 Yarn 中的 RM 來進行統一集中的管理。RegionServer 作為對資料進行操作的核心驅動器,只負責了執行和監控任務的操作,其他的都不負責。RegionServer 一般都是和具體的 Region 部署在一個節點上的,所以從邏輯上來講,本身 RegionServer 是對 Region 有管理權的,但是實際上在進行相關的操作的時候管理權卻被 HMaster 回收了,這麼做的主要原因是由於 RegionServer 是沒有具體的安全保護機制的,屬於單程序。所以一旦 RegionServer 出現問題就會導致整體資料元資料丟失。RegionServer 在將對 Region 的元資料管理權交給 zookeeper 之後,首先保證了元資料的整體安全維護,而且在實際上 RegionServer 出現故障之後,我們就可以直接將元資料中的路由資訊改變為其他的節點,相當於是將資料的讀寫執行權交給了其他的節點,這樣做就可以實現快速的故障遷移和高可靠性的安全保證。

2.HMaster

HMaster 程序負責管理所有的 RegionServer。(1)新 RegionServer 的註冊。

(2)     RegionServer Failover 處理。

(3)負責建表/修改表/刪除表以及一些叢集操作。

就像之前所說的, 底層程序的安全性是交由上層程序實現的, 所以在這裡 HMaster 的第一個作用就是需要保證底層程序的安全,說到安全性的保證,其實也算不上保證             RegionServer     的安全, HMaster        主要是建立和註冊RegionServer    的資訊,保證  RegionServer         的合法性,並且需要監控

RegionServer 的健康狀況, 一旦 HMaster 檢測到 RegionServer 出現了故障和問題,這個時候就需要進行故障的遷移,由於如上所說的,RegionServer 只涉及對 Region 的操作,對於實際的資料維護等操作都不執行,所以在RegionServer 程序出現故障之後 HMaster 在做 Failover 故障切換時無需對資料進行遷移的操作,只需要將 Zookeeper 中的元資料路由資訊做一個更改即可,將對應的路由指標改向遷移後的目標 RegionServer 即可。這樣就可以實現快速可靠的故障遷移操作。

HMaster 程序負責所有 Region 的轉移操作。(1)新表建立時的 Region 分配。

(2)執行期間的負載均衡保障。

(3)     RegionServer Failover 後的 Region 接管。

HMaster 程序有主備角色。叢集可以配置兩個 HMaster 角色,叢集啟動時,這些 HMaster 角色通過競爭獲得主 HMaster 角色。主 HMaster 只能有一個,備 HMaster 程序在叢集執行期間處於休眠狀態,不干涉任何叢集事務。主備HMaster 的裁決交由 Zookeeper 決定。

HMaster 除了我們上面所說的對 RegionServer 的管理之外,對於 Region 的資料操作和維護也是由 HMaster 來做的,所以整體來講,Region 的元資料是由Zookeeper 維護和管理,Region 的資料和操作是由 HMaster 來管理,作為RegionServer,只負責了讀寫等動作的執行。就像之前所說的,HMaster 負責了RegionServer 在故障情況下的 Region 遷移操作,那麼 HMaster 首先就需要擁有對於 Region 的管理權,這裡 HMaster 做的工作主要就是對於 Region 的建立、分配。包括節點在維護 Region 的時候,為了保證不會出現某些節點的壓力過大的問題,HMaster 還需要做負載均衡的操作,保證整體叢集的壓力基本均衡,這個時候就需要對 Region 做對應的工作分配,將 RegionServer 維護的 Region 的壓力和開銷均衡到每一個節點。另外在 RegionServer 出現故障之後,如上我們需要做對應的故障遷移。

 

 

ColumnFamily 是 Region 的一個物理儲存單元。同一個 Region 下面的多個ColumnFamily,位於不同的路徑下面。ColumnFamily 資訊是表級別的配置。也就是說,同一個表的多個 Region,都擁有相同的 ColumnFamily 資訊(例如,都有兩個 ColumnFamily,且不同 Region 的同一個 ColumnFamily 配置資訊相同)。

ColumnFamily 列族,一個表在水平方向上由一個或多個 ColumnFamily 組成。一個 CF(ColumnFamily)可以由任意多個 Column 組成。Column 是 CF 下的一個標籤,可以在寫入資料時任意新增,因此 CF 支援動態擴充套件,無需預先定義 Column 的數量和型別。HBase 中表的列非常稀疏,不同行的列的個數和型別都可以不同。和傳統的行儲存相比,列儲存更適合用於資料分析,而且在大資料的環境下,我們可能需要隨時對列進行相關的操作,比如拓展和縮減。那麼這個時候如果按照傳統的行儲存形式來進行相關的結構設計就會出現無法拓展的情況,因為行儲存的一大典型特點就是需要在建立表的時候預先定義好列的結構,所以這個時候我們必須要做的就是對列進行模組化操作,所以列族在這個時候就出現了,通過列族的模組化設計,我們就可以實現對列的相關操作,保證整體的資料的拓展和屬性維度的靈活調動,在列族下,我們還設計了列這一層的概念,相當於是多個列構成了一個列族,具體原因就和 Region 是一樣的,對於大型的資料庫,列維度也是很多的,這個時候如果針對每一個列都去進行維護,那麼就和行維護一樣產生很大的開銷,所以我們可以把行儲存和列儲存做一個層次的對應比,行對應列,

Region 對應 ColumnFamily 的層次。那麼在實際中,一個 Region 中會包含多個ColumnFamily,同樣,多個 Region 也會擁有相同的 ColumeFamily。

4.key-value

KeyValue 具有特定的結構。Key 部分被用來快速的檢索一條資料記錄,Value 部分用來儲存實際的使用者資料資訊。

KeyValue 作為承載使用者資料的基本單元,需要儲存一些對自身的描述資訊,例如,時間戳,型別等等。那麼,勢必會有一定的結構化空間開銷。

和傳統的資料庫或者是檔案系統不同的是,Hbase 中的 key-value 是一起儲存的,通過欄位的形式一起以資料的型別儲存到實際的儲存空間中,key-value 分為了三部分,第一部分記錄的是 key 值的長度和 value 值的長度,第二部分是 key 值的具體欄位(行鍵值長度,行鍵值,列族長度,列族值,時間戳,key 型別),最後是實際的 value 資料。那麼 key 值裡面的行鍵值,列族值,以及時間戳就是我們事先資料查詢的三個重要欄位,我們又稱之為三維有序儲存。hbase 所謂的三維有序儲存的三維是指:rowkey(行主鍵),column key(columnFamily+qualifier),timestamp(時間戳)三部分組成的三維有序儲存。(1) rowkey,我們知道 rowkey 是行的主鍵,而且 hbase 只能用個 rowkey,

或者一個 rowkey 範圍即 scan 來查詢資料。所以 rowkey 的設計是至關重要的,關係到你應用層的查詢效率。我們知道,rowkey 是以字典順序排序的。而儲存的位元組碼,字典排序,我們知道,如果是字母,那就是字母的順序,比如,有兩個rowkey,rowkey1:aaa222,rowkey2:bbb111,那麼 rowkey1 是排在 rowkey2 前面的,因為按字典,a 排在 b 前面,如果 rowkey2 的第一位也是 a,那麼就根據第二位來比較,如果還相同,則比較第三為,後面同樣。這個理解了,我們在根據 rowkey 範圍查詢的時候,我們一般是知道 startRowkey,如果我們通過 scan 只傳 startRowKey:d 開頭的,那麼查詢的是所有比 d 大的都查了,而我們只需要 d 開頭的資料,那就要通過 endRowKey 來限制。我們可以通過設定 endRowKey 為: d 開頭,後面的根據你的 rowkey 組合來設定,一般是加比 startKey 大一位。比如說 rowkey 設計為:使用者 ID-日期,那麼查某個使用者某天的資料,startKEY 為3231-20121212,endKey 為:3231+20121213,那麼你查到的就是使用者為 3231 在

20121212 這一天的資料。(2) columnkey

columnkey 是第二維,資料按 rowkey 字典排序後,如果 rowkey 相同,則是根據 columnkey 來排序的,也是按字典排序。

我們在設計 table 的時候要學會利用這一點。比如我們的收件箱。我們有時候需要按主題排序,那我們就可以把主題這設定為我們的 columnkey,即設計為columnFamily+主題.,這樣的設計。

(3)     timestamp

timestamp 時間戳,是第三維,這是個按降序排序的,即最新的資料排在最前面。這個就沒有什麼說的了。

 

5.關於各個元件之間的邏輯關係說明

從模組程序來說,HBase 分為 HMaster 和 RegionServer。

RegionMaster 是為了維護 Region 的,其實也就是為了保證基本的表增刪改查工作的。並且服務是維護在 DataNode 上的。我們在 HBase 上建立了一個表,那麼這個表會按照鍵值的範圍橫向劃分成一個個的子表,就成為 Region。根據鍵值的大小不同,我們所維護的 Region 的大小也不同,Region 分為 METAregion 和使用者 region 兩種需要注意的是,region 的建立和遷移等操作是由 HMaster 來維護的,region 的資料維護和讀寫操作是交由 regionserver 來執行的。這樣做的話,一旦某一個 regionserver 失效,我們可以將該 region 進行轉移。在其他的節點上進行維護。HMaster 主要做的工作就是建立和維護 RegionServer,並且給這些 Region Server 來分配 Region,並且在 RegionServer 出現問題的時候進行 Region 的遷移操作。對於 HBASE 來說,一個表按照橫向進行劃分,都由物理上的 column 進行儲存,任意個 column 之間構成了 columnfamily,由於 columnfamily 的基本單位是表,所以基於表橫向建立的多個 region 他們就會擁有相同的 columnfamily 資訊。key 值劃定了 region,之後由出現了 keyvalue,我們在底層儲存時,資料都是按照 keyvalue 進行的組織和維護,使用者可以通過 key 值進行快捷的訪問和查詢。

Region,CloumnFamily 和 key-value 的關係如下所示:

上圖主要描述的是 Hbase 的資料構成方式,而實際上的 Region 程序構成圖如下所示:

 

(1) Store:一個 Region 由一個或多個 Store 組成,每個 Store 對應圖中的一個 Column Family。

(2) MemStore:一個 Store 包含一個 MemStore,MemStore 快取客戶端向 Region插入的資料。當 RegionServer 中的 MemStore 大小達到配置的容量上限時,RegionServer 會將 MemStore 中的資料“flush”到 HDFS 中。

(3) StoreFile:MemStore 的資料 flush 到 HDFS 後成為 StoreFile。隨著資料的插入,一個 Store 會產生多個 StoreFile,當 StoreFile 的個數達到配置的最大值時,RegionServer 會將多個 StoreFile 合併為一個大的StoreFile。

(4) Hfile:HFile 定義了 StoreFile 在檔案系統中的儲存格式,它是當前 HBase系統中 StoreFile 的具體實現。

(5) Hlog:HLog 日誌保證了當 RegionServer 故障的情況下使用者寫入的資料不丟失,RegionServer 的多個 Region 共享一個相同的 Hlog。

四、HBase 寫流程

客戶端發起請求通過 ZooKeeper 尋找到 meta 表所在 RegionServer meta 表中記載著各個 User Region 資訊(rowkey 範圍,所在 RegionServer),通過 meta 表尋找所要寫入的 Region 所在 RegionServer 請求按 RegionServer 和 Region 打包傳送到 Region 所在 RegionServer,由該 RegionServer 具體處理資料寫入。

 

Region 寫流程:

(1)首先,RegionServer 會請求需要寫入資料的 Region 的讀寫鎖(2)獲取到了讀寫鎖之後,RegionServer 會繼續請求所需要修改的行的行鎖。

(3)行鎖獲取成功之後,RegionServer 就會將資料寫入到記憶體中,並且再寫完成之後釋放掉對應的行鎖。

(4)行鎖釋放後,資料操作將會寫入日誌中(write ahead log 預寫日誌)

(5)全部修改完成之後,RegionServer 就會釋放掉對應的 Region 的讀寫鎖。在具體的讀寫請求中,首先第一步需要做到的就是查詢元資料,通過元資料我們就可以尋找到相關的資料具體的儲存節點和儲存位置。所以首先第一步作為提供介面的程序,client 受理客戶的請求,將讀寫請求轉發給 zookeeper,然後進行相關的操作,在寫操作中,又分為了新寫和讀改寫兩種操作,如果是新寫,那麼我們需要向 zookeeper 申請寫空間,建立一個元資料,如果是讀改寫,那麼就進行的是查詢和改寫操作,不需要新申請寫空間。

在向 Zookeeper 查詢到元資料之後,我們需要做的就是向 RegionServer 傳送請求,通過 RegionServer 進行具體相關的操作。

RegionServer 會再轉發請求之前首先獲取對應位置的許可權,許可權主要分為讀寫鎖,在進行寫操作的時候,由於 Hbase 屬於資料庫,所以要獲取到對應的讀鎖和寫鎖,讀鎖的獲取是為了保證其他程序資料的更新,寫鎖是為了保障資料的 ACID 特性不被破壞。在獲取到讀寫鎖之後,針對當前寫操作需要做的更改,程序還需要獲取寫操作對應操作的行鎖,然後獲取到之後,資料就會被先行寫入到記憶體中進行快取。寫完成之後先釋放的行鎖,之後寫操作日誌,然後最終釋放 Region 鎖也就是對應的讀寫鎖。先寫記憶體的原因:HBase 提供了一個 MVCC(多版本併發控制)機制,來保障寫資料階段的資料可見性。先寫 MemStore 再寫 WAL,是為了一些特殊場景下,記憶體中的資料能夠更及時的可見。如果寫 WAL 失敗的話,MemStore 中的資料會被回滾。寫記憶體可以避免多 Region 情形下帶來的過多的分散 IO 操作。資料在寫入到 MemStore 之後,也會順序寫入到 HLog 中,以保證資料的安全。

 

Flush 重新整理寫操作:重新整理操作會觸發資料從記憶體中寫入到對應的 HFile 中,如下三種場景,會觸發一個 Region 的 Flush 操作:

(1)該 Region 的 MemStore 的總大小,達到了預設的 Flush Size 閾值。這種場景下的 Flush 操作,通常僅瞬間堵塞使用者的寫操作。但如果超出預設 Flush Size 閾值過多的話,也可能會引起一小段時間的堵塞。

(2)RegionServer 的總記憶體大小超出了預設的閾值大小。這種場景下,在總記憶體沒有降低到預設的閾值以下之前,可能會較長時間堵塞。

(3)當 WALs 中檔案數量達到閾值時。記憶體資料快取高低水位技術:Cache 高低水位是指 Cache 中儲存髒資料的最高限制值和最低限制值。如果 Cache 的高、低水位設定不合理,會影響 Cache 的讀寫效能。髒資料(DirtyRead)是指源系統中的資料不在給定的範圍內或對於實際業務毫無意義,或是資料格式非法,以及在源系統中存在不規範的編碼和含糊的業務邏輯。通俗的講,當一個事務正在訪問資料,並且對資料進行了修改,而這種修改還沒有提交到資料庫中,這時,另外一個事務也訪問這個資料,然後使用了這個資料。因為這個資料是還沒有提交的資料,那麼另外一個事務讀到的這個資料是髒資料,依據髒資料所做的操作可能是不正確的。在儲存中,對於髒資料的理解其實說成是駐留在 Cache 中的資料比較合適,例如在 TCQ 和 NCQ 的情況下,Cache 中的髒資料就比較多。將髒資料快取在 Cache 中可使 IO 得到充分整合與排程,降低延遲,提升效能,但當寫 Cache 中快取的 IO 髒資料的總量達到一定上限時,就需要加快資料刷盤的速度,避免由於寫 Cache 快取了過多髒資料不能接收前端下發的新的寫 IO 請求。預設情況下,系統設定的低水位值為 20,在執行實際的業務,特別是隨機寫業務的時候,可適當的提升低水位值,如設定為 40 或者 50。高水位需根據實際業務的下發情況進行調整,重點關注調整後的效能變化狀況和 Cache 命中率狀況,針對隨機寫業務建議設定在 80 左右。刷盤執行緒每隔 1s 啟動一次高低水位設定的建議:高水位不宜設定太高。如果高水位設定的值太高頁面緩衝就小,如果前端 I/O 流量突然增加,會產生 I/O 波動和時延增大的現象,從而影響寫效能。低水位不宜設定太低。如果低水位設定的值太低,會導致後端將快取資料頻繁寫入硬碟,降低寫效能。高低水位的間距不宜太小。如果取值間距太小,不能很好的利用後端頻寬。系統推薦的 Cache 高水位和低水位的取值分別為 80%和 20%。 Compaction 壓縮操作:

Compaction 的主要目的,是為了減少同一個 Region 同一個 ColumnFamily 下面的小檔案數目,從而提升讀取的效能。

Compaction 分為 Minor、Major 兩類:

Minor:小範圍的 Compaction。有最少和最大檔案數目限制。通常會選擇一些連續時間範圍的小檔案進行合併。

Major:涉及該 Region 該 ColumnFamily 下面的所有的 HFile 檔案。Major Compaction 過程中,會清理被刪除的資料。

MinorCompaction 選取檔案時,遵循一定的演算法。

Split 分裂操作:

普通的 RegionSplit 操作,是指叢集執行期間,某一個 Region 的資料大小超出了預設的閾值,則需要將該 Region 自動分裂成為兩個子 Region。

分裂過程中,被分裂的 Region 會暫停讀寫服務。由於分裂過程中,父 Region 的資料檔案並不會真正的分裂並重寫到兩個子 Region 中,而是僅僅通過在新 Region 中建立引用檔案的方式,來實現快速的分裂。因此,Region 暫停服務的時間會比較短暫。

客戶端側所快取的父 Region 的路由資訊需要被更新。

這裡所指的分裂,就相當於重新建立了兩個新的邏輯 Region,這兩個新的 Region 沒有儲存資料,儲存的只是原有資料的對映,將舊的 Region 資料添加了一個對映到自身,資料本身還是儲存在原先的 Region 中。當新的寫請求下達的時候,資料就會寫到新的 Region 中。

 

五、HBase 讀流程

(1)客戶端發起請求

(2)通過 ZooKeeper 尋找到 meta 表所在 RegionServer meta 表中記載著各個 UserRegion 資訊(rowkey 範圍,所在 RegionServer),通

過 rowkey 查詢 meta 表,獲取所要讀取的 Region 所在 RegionServer

(3)請求傳送到該 RegionServer,由其具體處理資料讀取(4)資料讀取返回到客戶端。

Scanner 查詢器:

Scanner 可以理解為一個棧,一個 store 裡面有 menstore 和 hfile,當我們執行查詢的時候,就會開啟 menstore 的棧和各個 hfile 的棧,先從各個棧中 poll 出一條資料,然後做排序,next 返回排序後的第一個資料,然後該棧繼續 poll 出一條資料,繼續排序。在尋找到 rowkey 所對應的 RegionServer 和 Region 之後,需要開啟一個查詢器

Scanner,由其具體執行查詢資料,Region 中會包含記憶體資料 MemStore,檔案資料 Hfiles,那麼在 openscanner 的時候就需要分別讀取這兩塊資料,開啟對應不同的 scanner 做查詢操作。

OpenScanner 的過程,會為 MemStore,以及各個 HFile 建立所對應的 Scanner:

MemStore 對應的 Scanner 為 MemStoreScanner。HFile 對應的 Scanner 為StoreFileScanner。

BloomFilter 被用來優化一些隨機讀取的場景,即 Get 場景。它可以被用來快速的判斷一條使用者資料在一個大的資料集合(該資料集合的大部分資料都沒法被載入到記憶體中)中是否存在。

BloomFilter 在判斷一個數據是否存在時,擁有一定的誤判率。但對於“使用者資料 XXXX 不存在”的判斷結果是可信的。

HBase 的 BloomFilter 的相關資料,被儲存在 HFile 中。

資料在進行寫入的時候,我們需要針對寫入的資料進行反覆的雜湊計算,並且將對應的對映位改為 1,該位就是一個置位,沒有什麼實際意義,那麼一旦有資料需要讀取,我們可以針對需要讀取的請求,進行資料雜湊,之後和置位標誌進行對比,如果為 1 表示存在,如果不為 1 表示不存在。

六、HBase 增強特性

1.二級索引

二級索引為 HBase 提供了按照某些列的值進行索引的能力。二級索引就是把要查詢的列與 rowkey 關聯成一個索引表。此時列成新的 rowkey,原 rowkey 成為 value。其實就是查詢了 2 次。

在實際應用中,很多場景是查詢某一個列值為 XXX 的資料。HBase 提供了 Filter 特性去支援這樣的查詢,它的原理是:按照 RowKey 的順序,去遍歷所有可能的資料,再依次去匹配那一列的值,直到獲取到所需要的資料。可以看出,可能僅僅為了獲取一行資料,它卻掃描了很多不必要的資料。因此,如果對於這樣的查詢請求非常頻繁並且對查詢效能要求較高,使用 Filter 無法滿足這個需求。

沒有二級索引時,查詢手機號“68XXX 的記錄,必須按照 RowKey 做全表掃描,逐行匹配”“Mobile”欄位,時延很大。有二級索引時,先查索引表,再定位到資料表中的位置,不用全表掃描,時延小。

2.HFS

在 Hadoop 生態系統中,無論是 HDFS,還是 HBase,均在面對海量檔案的儲存的時候,在某些場景下,都會存在一些很難解決的問題:

如果把海量小檔案直接儲存在 HDFS 中,會給 NameNode 帶來極大的壓力。由於 HBase 介面以及內部機制的原因,一些較大的檔案也不適合直接儲存到HBase 中。

HBase 檔案儲存模組(HBase FileStream,簡稱 HFS)是 HBase 的獨立模組,它作為對 HBase 與 HDFS 介面的封裝,應用在 FusionInsight HD 的上層應用,為上層應用提供檔案的儲存、讀取、刪除等功能。

HFS 的出現解決了需要在 HDFS 中儲存海量小檔案,同時也要儲存一些大檔案的混合的場景。簡單來說,就是在 HBase 表中,需要存放大量的小檔案(10MB 以下),同時又需要存放一些比較大的檔案(10MB 以上)。

MOB 檔案

在實際應用中,使用者需要儲存大大小小的資料,比如影象資料、文件。小於 10MB 的資料一般都可以儲存在 HBase 上,對於小於 100KB 的資料,HBase 的讀寫效能是最優的。如果存放在 HBase 的資料大於 100KB 甚至到 10MB 時,插入同樣個數的資料檔案,其資料量很大,會導致頻繁的 compaction 和 split,佔用很多 CPU,磁碟 IO 頻率很高,效能嚴重下降。

MOB 資料(即 100KB 到 10MB 大小的資料)直接以 HFile 的格式儲存在檔案系統上(例如 HDFS 檔案系統),然後把這個檔案的地址資訊及大小資訊作為 value 儲存在普通 HBase 的 store 上,通過工具集中管理這些檔案。這樣就可以大大降低 HBase 的 compation 和 split 頻率,提升效能。

圖中 MOB 模組表示儲存在 HRegion 上的 mobstore,mobstore 儲存的是 key-value,key 即為 HBase 中對應的 key,value 對應的就是儲存在檔案系統上的引用地址以及資料偏移量。讀取資料時,mobstore 會用自己的 scanner,先讀取 mobstore 中的 key-value 資料物件,然後通過 value 中的地址及資料大小資訊,從檔案系統中讀取真正的資料。