hbase表中的數據按照行鍵的字典順序排序,hbase表中的數據按照行的的方向切分爲多個region。mysql
最開始只有一個region隨着數據量的增長,產生分裂,這個過程不停的進行。一個表可能對應一個或多個region。sql
region是hbase表分佈式存儲和負載均衡的基本單元,一個表的多個region可能分佈在多臺HRegionServer上。數據庫
region是分佈式存儲的基本單元,但不是存儲的基本單元,其內部還具備結構。一個region由多個Store來組成。緩存
有幾個store取決於表的列族的數量,一個列族對應一個store。之因此這麼設計,是由於一個列族中的數據每每數據很相似,方便進行壓縮,節省存儲空間。安全
表的一個列族對應一個store,store的數量由表中列族的數量來決定。一個store由一個memstore和零個或多個storefile組成。服務器
memStore負責保存內存中的數據。網絡
storefile其實就是hdfs中的hfile只能寫入不能修改,因此hbase寫入數據到hdfs的過程實際上是不斷追加hfile的過程。架構
hfile的結構:負載均衡
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。
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,Sequence File 的Key是HLogKey對象,HLogKey中記錄了寫入數據的歸屬信息,除了table和region名字外,同時還包括 sequence number和timestamp,timestamp是」寫入時間」,sequence number的起始值爲0,或者是最近一次存入文件系統中sequence number。HLog Sequece File的Value是HBase的KeyValue對象,即對應HFile中的KeyValue。
數據寫入hbase時,先在hlog中記錄日誌,再修改memstore,而後直接返回成功。這樣不須要真正等待寫入hdfs的過程,因此很快。
memstore內存有限,當寫入數量達到必定的閾值的時候,就會建立一個新的memstore繼續工做,而舊的memstore會用一個單獨的線程將數據寫出到storefile中,最終清空舊的memstore並在zookeeper中記錄最後寫出數據時間的redo point信息。
因爲storefile不能修改,因此數據的更新實際上是不停建立新的storefile的過程。
這樣多個storefile中可能存在對同一個數據的多個版本,其中部分舊的版本實際上是垃圾數據,時間過長,垃圾數據就可能不少,浪費磁盤空間。
因此當達到必定的閾值的時候,master會自動合併storefile,在合併的過程當中將垃圾數據清理。而當合並出來的文件達到必定程度時,再重新進行切分,防止文件過大。
雖然看起來是小變大再變小,可是通過這個過程垃圾數據就被清理掉了。因此store中的數據,實際上是memstore和storefile來組成的。
而memstore因爲是內存中的數據,一旦斷電就會丟失。爲了解決可能的意外形成數據丟失的問題,hbase在整個hregionserver中,經過記錄hlog來保存了全部數據操做的記錄。當hbase啓動時,會檢查zookeeper中的redopoint信息,從hlog中恢復這個時間點以後的數據,解決內存中memStore數據容易丟失的問題。
hlog文件在每臺hregionServer中都有一個,全部這臺機器中的全部HRegion都公用這個文件,這樣整個機器的磁盤性能均可覺得這一個文件提供支持,提高文件的讀寫效率。
hlog文件也是存儲在hdfs中的,也是分佈式存儲的,保證了日誌文件的可靠性。
在查詢數據時,先查找內存,若是內存中有當前鍵對應的數據,獲取數據直接返回。
若是沒有在內存中找到數據,就去查找region對應的hfile,注意不是將全部hfile中的數據恢復到內存,而是查找每一個hfile的Trailer,經過trailer找到Data Block Index,若是在這裏發現了要找的數據,經過索引找到Data Blocks中對應的Data Block,將Data Block數據送回內存組裝,最終將多個hfile中獲取到的數據進行合併,而後返回最新版本的數據。
因爲hbase中的數據自然排序,再加上底層索引,整個查詢也能夠很是的快。
在hbase的hbase名稱空間下有一張meta表,其中存放了表和region和regionSever之間的對應關係信息,這個表很特別,規定meta表只能有一個region。而且這個meta表的這個region的位置信息被存放在了zookeeper的meta-region-server節點下。
在客戶端從hbase中查找數據時,須要先聯繫zookeeper找到meta表對應的region的位置,鏈接這個位置讀取到meta表中的信息,才能知道要查詢的表、表的region和region對應的regionServer的信息。再根據這些信息鏈接真正要查詢的表對應的region的regionServer進行讀取,這個過程就稱之爲region的尋址過程。
這樣的尋址過程是至關耗費時間的,爲了提升性能,客戶端一般會緩存以前已經知道的region尋址信息,當客戶端再次讀取同一個表中的數據時,能夠經過本地緩存的region地址信息,直接定位讀取,提升效率。
哈希存儲引擎是哈希表的持久化實現,支持增、刪、改以及隨機讀取操做,但不支持順序掃描,對應的存儲系統爲key-value存儲系統。對於key-value的插入以及查詢,哈希表的複雜度都是O(1),明顯比樹的操做O(n)快,若是不須要有序的遍歷數據,哈希表就是your Mr.Right。
B+樹 B-樹 B*樹
B樹存儲引擎是B樹的持久化實現,不只支持單條記錄的增、刪、讀、改操做,還支持順序掃描(B+樹的葉子節點之間的指針),對應的存儲系統就是關係數據庫(Mysql等)。
LSM樹(Log-Structured Merge Tree)存儲引擎和B樹存儲引擎同樣,一樣支持增、刪、讀、改、順序掃描操做。並且經過批量存儲技術規避磁盤隨機寫入問題。固然凡事有利有弊,LSM樹和B+樹相比,LSM樹犧牲了部分讀性能,用來大幅提升寫性能。
經過以上的分析,應該知道LSM樹的由來了,LSM樹的設計思想很是樸素:將對數據的修改增量保持在內存中,達到指定的大小限制後將這些修改操做批量寫入磁盤,不過讀取的時候稍微麻煩,須要合併磁盤中歷史數據和內存中最近修改操做,因此寫入性能大大提高,讀取時可能須要先看是否命中內存,不然須要訪問較多的磁盤文件。極端的說,基於LSM樹實現的HBase的寫性能比Mysql高了一個數量級,讀性能低了一個數量級。
LSM樹原理把一棵大樹拆分紅N棵小樹,它首先寫入內存中,隨着小樹愈來愈大,內存中的小樹會flush到磁盤中,磁盤中的樹按期能夠作merge操做,合併成一棵大樹,以優化讀性能。
以上這些大概就是HBase存儲的設計主要思想,這裏分別對應說明下:
由於小樹先寫到內存中,爲了防止內存數據丟失,寫內存的同時須要暫時持久化到磁盤,對應了HBase的MemStore和HLog。
MemStore上的樹達到必定大小以後,須要flush到HRegion磁盤中(通常是Hadoop DataNode),這樣MemStore就變成了DataNode上的磁盤文件StoreFile,按期HRegionServer對DataNode的數據作merge操做,完全刪除無效空間,多棵小樹在這個時機合併成大樹,來加強讀性能。
hbase中的老大叫hmaster,小弟叫hregionServer,客戶端叫Client,Zookeepr爲hbase提供集羣協調。
訪問hbase保留一些緩存信息提高效率。
保證任什麼時候候集羣只有一個HMaster。
監控regionServer的狀態,將其上線下線信息通知mater。
存儲meta表Region的地址。
存儲hbase的元數據信息。包括有哪些表、有哪些列族等等。
爲RegionServer分配Region。
爲RegionServer進行負載的均衡。
GFS上的垃圾回收。
處理對Schema數據的更新請求。
維護Master分配給它的region,處理對這些region的IO請求。
負責切分在運行過程當中變得過大的region。
表按照行鍵進行了排序,並且加了索引,因此查詢時能夠很快定位。
數據按照行鍵切分爲多個HRegion,分佈在多個RegionServer中,查詢大量數據時,多個RegionServer能夠一塊兒工做,從而提升速度。
HRegion是存活在RegionServer的內存中的,讀寫會很是的高效。
還有HFile的支持保證大量的數據能夠持久化的保存。
數據最終落地到HDFS中,分佈式的存儲,保證數據段可靠性和可擴展性。
基於hdfs,因此支持可擴展性,能夠經過增長大量的廉價的硬件提升存儲容量。
按列存儲,空的數據不佔用空間,當存儲稀疏數據時,不會浪費空間。
按例存儲,同一列的數據存放在一塊兒,而同一列的數據通常都是一樣的類型的內容類似的數據,能夠實現很是高效的壓縮,節省空間。
基於hdfs,由hdfs的可靠性保證了hbase的可靠性,即數據能夠有多個備份。
利用zookeeper實現了HA(高可用集羣),即便某一臺機器掛掉另外的機器也能夠很快的替換它。
比起傳統的關係型數據庫,能夠存儲半結構化非結構化的數據,能夠存儲和處理更大級別的數據,提供高效的查詢,對於稀疏數據的處理更好,具備更好的橫向擴展性,免費開源性價比很高。可是不能支持很是好的事務特性,只支持行級的事務。只能經過行鍵來查詢,表設計時難度更高。而mysql用來存儲結構化的數據提供更好的事務控制。
比起hive,hive只是在mapreduce上包了一層殼,本質上仍是離線數據的處理的工具,實時查詢性能有限,本質上是一個基於hadoop的數據倉庫工具,不能支持行級別的新增修改和刪除。hbase能夠提供實時的數據的處理能力,適用於在線數據查詢處理,本質上是一種數據庫工具。
HBase表的設計會直接影響hbase使用的效率和使用的便利性。
HBase表的設計主要是列族的設計和行鍵的設計。
在設計hbase表時候,注意如下事項:
1.列族不宜過多,越少越好,官方推薦hbase表的列族不宜超過3個。列族設計過多,會很是消耗內存。
2.常常要在一塊兒查詢的數據最好放在一個列族中,儘可能的減小跨列族的數據訪問。
3.若是有多個列族,多個列族中的數據應該設計的比較均勻。
hbase表中行鍵是惟一標識一個表中行的字段,因此行鍵設計的好很差將會直接影響將來對hbase的查詢的性能和查詢的便利性,因此hbase中的行鍵是須要進行設計的。
行鍵必須惟一才能惟一標識數據。
行鍵必須有意義,這樣才能方便數據的查詢。
全部語言平臺針對字符串的操做是統一,數值類型在不一樣的系統中處理的方式可能不一樣。
不一樣長度的數據可能會形成天然排序時排序的結果和預期不一致。
行鍵最多能夠達到64KB,可是最好是在10~100字節之間,最好不要超過16字節,越短越好,最好是8字節的整數倍。
底層存儲是利用key-value存儲的,行鍵會屢次出現,若是行鍵過長會致使大量存儲空間被行鍵消耗掉。
綜合來看如下兩個原則是存在衝突的,因此在選擇的時候只能使用其中之一,具體使用那個原則,要根據實際的業務以及集羣的能力來考慮。
行鍵的設計將會影響數據在hbase表中的排序方式,這會影響region切分後的結果,要注意,在設計行鍵時應該讓常常要查詢的數據分散在不一樣的region中,防止某一個或某幾個regionserver成爲熱點。
當出現熱點數據的時候,會致使整個集羣的服務器相繼掛機,最終致使集羣崩潰,即雪崩。
行鍵的設計將會影響數據在hbase表中的排序方式,因此一種策略是將常常連續查詢的條件做爲行鍵最前面的數據,這樣一來能夠方便批量查詢。
上一篇:HBase簡介及搭建
下一篇:HBase的Java API操做