HBase 我終於看懂了HBase,太不容易了...

1、介紹HBase

Apache HBase™ is the  Hadoop database, a distributed, scalable, big data store.
HBase is a type of "NoSQL" database.

Apache HBase 是 Hadoop 數據庫,一個分佈式、可伸縮的大數據存儲。java

HBase是依賴Hadoop的。爲何HBase能存儲海量的數據?由於HBase是在HDFS的基礎之上構建的,HDFS是分佈式文件系統。數據庫

2、爲何要用HBase

截至到如今,已經學了很多的組件了,好比說分佈式搜索引擎「Elasticsearch」、分佈式文件系統「HDFS」、分佈式消息隊列「Kafka」、緩存數據庫「Redis」等等...apache

可以處理數據的中間件(系統),這些中間件基本都會有持久化的功能。爲何?若是某一個時刻掛了,那還在內存但還沒處理完的數據不就涼了?緩存

Redis有AOF和RDB、Elasticsearch會把數據寫到translog而後結合FileSystemCache將數據刷到磁盤中、Kafka自己就是將數據順序寫到磁盤....服務器

這些中間件會實現持久化(像HDFS和MySQL咱們自己就用來存儲數據的),爲何咱們還要用HBase呢?架構

雖然沒有什麼可比性,可是在學習的時候總會有一個疑問:「既然已學過的系統都有相似的功能了,那爲啥我還要去學這個玩意?」併發

是這樣理解的:異步

  • MySQL?MySQL數據庫咱們是算用得最多了的吧?但衆所周知,MySQL是單機的。MySQL能存儲多少數據,取決於那臺服務器的硬盤大小。以如今互聯網的數據量,不少時候MySQL是無法存儲那麼多數據的。
  • 好比我這邊有個系統,一天就能產生1TB的數據,這數據是不可能存MySQL的。(如此大的量數據,咱們如今的作法是先寫到Kafka,而後落到Hive中)
  • Kafka?Kafka咱們主要用來處理消息的(解耦異步削峯)。數據到Kafka,Kafka會將數據持久化到硬盤中,而且Kafka是分佈式的(很方便的擴展),理論上Kafka能夠存儲很大的數據。可是Kafka的數據咱們不會「單獨」取出來。持久化了的數據,最多見的用法就是從新設置offset,作「回溯」操做
  • Redis?Redis是緩存數據庫,全部的讀寫都在內存中,速度賊快。AOF/RDB存儲的數據都會加載到內存中,Redis不適合存大量的數據(由於內存太貴了!)。
  • Elasticsearch?Elasticsearch是一個分佈式的搜索引擎,主要用於檢索。理論上Elasticsearch也是能夠存儲海量的數據(畢竟分佈式),咱們也能夠將數據用『索引』來取出來,彷佛已是很是完美的中間件了。
  • 可是若是咱們的數據沒有常常「檢索」的需求,其實沒必要放到Elasticsearch,數據寫入Elasticsearch須要分詞,無疑會浪費資源。
  • HDFS?顯然HDFS是能夠存儲海量的數據的,它就是爲海量數據而生的。它也有明顯的缺點:不支持隨機修改,查詢效率低,對小文件支持不友好。

文中的開頭已經說了,HBase是基於HDFS分佈式文件系統去構建的。換句話說,HBase的數據其實也是存儲在HDFS上的。那確定有好奇寶寶就會問:HDFS和HBase有啥區別阿?分佈式

HDFS是文件系統,而HBase是數據庫,其實也沒啥可比性。「你能夠把HBase當作是MySQL,把HDFS當作是硬盤。HBase只是一個NoSQL數據庫,把數據存在HDFS上」。高併發

數據庫是一個以某種有組織的方式存儲的數據集合。

扯了這麼多,那咱們爲啥要用HBase呢?HBase在HDFS之上提供了高併發的隨機寫和支持實時查詢,這是HDFS不具有的。

我一直都說在學習某一項技術以前首先要了解它能幹什麼。若是僅僅看上面的」對比「,咱們能夠發現HBase能夠以低成原本存儲海量的數據而且支持高併發隨機寫和實時查詢。

但HBase還有一個特色就是:存儲數據的」結構「能夠地很是靈活(這個下面會講到,這裏若是沒接觸過HBase的同窗可能不知道什麼意思)。

3、入門HBase

聽過HBase的同窗可能都聽過「列式存儲」這個詞。我最開始的時候以爲HBase很難理解,就由於它這個「列式存儲」我一直理解不了它爲何是「列式」的。

在網上也有不少的博客去講解什麼是「列式」存儲,它們會舉咱們現有的數據庫,好比MySQL。存儲的結構咱們很容易看懂,就是一行一行數據嘛。

 

 

 

 轉換成所謂的列式存儲是什麼樣的呢?

 

 

 

能夠很簡單的發現,無非就是把每列抽出來,而後關聯上Id。這個叫列式存儲嗎?我在這打個問號。

轉換後的數據從個人角度來看,數據仍是一行一行的。

這樣作有什麼好處嗎?很明顯之前咱們一行記錄多個屬性(列),有部分的列是空缺的,可是咱們仍是須要空間去存儲。如今把這些列所有拆開,有什麼咱們就存什麼,這樣空間就能被咱們充分利用。

這種形式的數據更像什麼?明顯是Key-Value嘛。那咱們該怎麼理解HBase所謂的列式存儲和Key-Value結構呢?走進三歪的小腦殼,一探究竟。

3.1 HBase的數據模型

在看HBase數據模型的時候,其實最好仍是不要用「關係型數據庫」的知識去理解它。

In HBase, data is stored in tables, which have rows and columns. This is a terminology overlap withrelational databases (RDBMSs), but this is not a helpful analogy.

HBase裏邊也有表、行和列的概念。

  • 表沒什麼好說的,就是一張表
  • 一行數據由一個行鍵和一個或多個相關的列以及它的值所組成

好了,如今比較抽象了。在HBase裏邊,定位一行數據會有一個惟一的值,這個叫作行鍵(RowKey)。而在HBase的列不是咱們在關係型數據庫所想象中的列。

HBase的列(Column)都得歸屬到列族(Column Family)中。在HBase中用列修飾符(Column Qualifier)來標識每一個列。

在HBase裏邊,先有列族,後有列。

什麼是列族?能夠簡單理解爲:列的屬性類別

什麼是列修飾符?先有列族後有列,在列族下用列修飾符來標識一列。

還很抽象是否是?三歪來畫個圖:

 

 

 咱們再放點具體的值去看看,就更加容易看懂了:

 

 

 

這張表咱們有兩個列族,分別是UserInfoOrderInfo。在UserInfo下有兩個列,分別是UserInfo:nameUserInfo:age,在OrderInfo下有兩個列,分別是OrderInfo:orderIdOrderInfo:money

UserInfo:name的值爲:三歪。UserInfo:age的值爲24。OrderInfo:orderId的值爲23333。OrderInfo:money的值爲30。這些數據的主鍵(RowKey)爲1

上面的那個圖看起來可能不太好懂,咱們再畫一個咱們比較熟悉的:

 

 

 HBase表的每一行中,列的組成都是靈活的,行與行之間的列不須要相同。如圖下:

 

 

 

 

 

 

換句話說:一個列族下能夠任意添加列,不受任何限制

數據寫到HBase的時候都會被記錄一個時間戳,這個時間戳被咱們當作一個版本。好比說,咱們修改或者刪除某一條的時候,本質上是往裏邊新增一條數據,記錄的版本加一了而已。

好比如今咱們有一條記錄:

 

 

 如今要把這條記錄的值改成40,實際上就是多添加一條記錄,在讀的時候按照時間戳讀最新的記錄。在外界「看起來」就是把這條記錄改了。

 

 

 

3.2 HBase 的Key-Value

HBase本質上其實就是Key-Value的數據庫,上一次咱們學Key-Value數據庫仍是Redis呢。那在HBase裏邊,Key是什麼?Value是什麼?

咱們看一下下面的HBaseKey-Value結構圖:

 

 

 

Key由RowKey(行鍵)+ColumnFamily(列族)+Column Qualifier(列修飾符)+TimeStamp(時間戳--版本)+KeyType(類型)組成,而Value就是實際上的值。

對比上面的例子,其實很好理解,由於咱們修改一條數據其實上是在原來的基礎上增長一個版本的,那咱們要準肯定位一條數據,那就得(RowKey+Column+時間戳)。

KeyType是什麼?咱們上面只說了「修改」的狀況,大家有沒有想過,若是要刪除一條數據怎麼作?實際上也是增長一條記錄,只不過咱們在KeyType裏邊設置爲「Delete」就能夠了。

3.3 HBase架構

扯了這麼一大堆,已經說了HBase的數據模型和Key-Value了,咱們還有一個問題:「爲何常常會有人說HBase是列式存儲呢?」

其實HBase更多的是「列族存儲」,要談列族存儲,就得先了解了解HBase的架構是怎麼樣的。

咱們先來看看HBase的架構圖:

 

 

 

一、Client客戶端,它提供了訪問HBase的接口,而且維護了對應的cache來加速HBase的訪問。

二、Zookeeper存儲HBase的元數據(meta表),不管是讀仍是寫數據,都是去Zookeeper裏邊拿到meta元數據告訴給客戶端去哪臺機器讀寫數據

三、HRegionServer它是處理客戶端的讀寫請求,負責與HDFS底層交互,是真正幹活的節點。

總結大體的流程就是:client請求到Zookeeper,而後Zookeeper返回HRegionServer地址給client,client獲得Zookeeper返回的地址去請求HRegionServer,HRegionServer讀寫數據後返回給client。

 

 

 

3.4 HRegionServer內部

咱們來看下面的圖:

 

 

前面也提到了,HBase能夠存儲海量的數據,HBase是分佈式的。因此咱們能夠判定:HBase一張表的數據會分到多臺機器上的。那HBase是怎麼切割一張表的數據的呢?用的就是RowKey來切分,其實就是表的橫向切割。

 

 

說白了就是一個HRegion上,存儲HBase表的一部分數據。

 

 

HRegion下面有Store,那Store是什麼呢?咱們前面也說過,一個HBase表首先要定義列族,而後列是在列族之下的,列能夠隨意添加。

一個列族的數據是存儲在一塊兒的,因此一個列族的數據是存儲在一個Store裏邊的。

看到這裏,其實咱們能夠認爲HBase是基於列族存儲的(畢竟物理存儲,一個列族是存儲到同一個Store裏的)

 

 

Store裏邊有啥?有Mem Store、Store File、HFile,咱們再來看看裏邊都表明啥含義。

 

 

HBase在寫數據的時候,會先寫到Mem Store,當MemStore超過必定閾值,就會將內存中的數據刷寫到硬盤上,造成StoreFile,而StoreFile底層是以HFile的格式保存,HFile是HBase中KeyValue數據的存儲格式。

因此說:Mem Store咱們能夠理解爲內存 buffer,HFile是HBase實際存儲的數據格式,而StoreFile只是HBase裏的一個名字。

回到HRegionServer上,咱們還漏了一塊,就是HLog

 

 

這裏其實特別好理解了,咱們寫數據的時候是先寫到內存的,爲了防止機器宕機,內存的數據沒刷到磁盤中就掛了。咱們在寫Mem store的時候還會寫一份HLog

這個HLog是順序寫到磁盤的,因此速度仍是挺快的(是否是有似曾類似的感受)...

稍微總結一把:

  • HRegionServer是真正幹活的機器(用於與hdfs交互),咱們HBase表用RowKey來橫向切分表
  • HRegion裏邊會有多個Store,每一個Store其實就是一個列族的數據(因此咱們能夠說HBase是基於列族存儲的)
  • Store裏邊有Men Store和StoreFile(HFile),其實就是先走一層內存,而後再刷到磁盤的結構

3.5 被遺忘的HMaster

咱們在上面的圖會看到有個Hmaster,它在HBase的架構中承擔一種什麼樣的角色呢?讀寫請求都沒通過Hmaster呀。

 

 

那HMaster在HBase裏承擔什麼樣的角色呢??

HMaster is the implementation of the Master Server. The Master server is responsible for monitoring all RegionServer instances in the cluster, and is the interface for all metadata changes.

HMaster會處理 HRegion 的分配或轉移。若是咱們HRegion的數據量太大的話,HMaster會對拆分後的Region從新分配RegionServer。(若是發現失效的HRegion,也會將失效的HRegion分配到正常的HRegionServer中)

HMaster會處理元數據的變動和監控RegionServer的狀態。

4、RowKey的設計

到這裏,咱們已經知道RowKey是什麼了。不難理解的是,咱們確定是要保證RowKey是惟一的,畢竟它是行鍵,有了它咱們才能夠惟一標識一條數據的。

在HBase裏邊提供了三種的查詢方式:

  1. 全局掃描
  2. 根據一個RowKey進行查詢
  3. 根據RowKey過濾的範圍查詢

4.1 根據一個RowKey查詢

首先咱們要知道的是RowKey是會按字典序排序的,咱們HBase表會用RowKey來橫向切分表。

不管是讀和寫咱們都是用RowKey去定位到HRegion,而後找到HRegionServer。這裏有一個很關鍵的問題:那我怎麼知道這個RowKey是在這個HRegion上的?

HRegion上有兩個很重要的屬性:start-keyend-key

咱們在定位HRegionServer的時候,實際上就是定位咱們這個RowKey在不在這個HRegion的start-keyend-key範圍以內,若是在,說明咱們就找到了。

這個時候會帶來一個問題:因爲咱們的RowKey是以字典序排序的,若是咱們對RowKey沒有作任何處理,那就有可能存在熱點數據的問題。

舉個例子,如今咱們的RowKey以下:

java3y111 java3y222 java3y333 java3y444 java3y555 aaa bbb java3y777 java3y666 java3y...

Java3yxxx開頭的RowKey不少,而其餘的RowKey不多。若是咱們有多個HRegion的話,那麼存儲Java3yxxx的HRegion的數據量是最大的,而分配給其餘的HRegion數量是不多的。

關鍵是咱們的查詢也幾乎都是以java3yxxx的數據去查,這會致使某部分數據會集中在某臺HRegionServer上存儲以及查詢,而其餘的HRegionServer卻很空閒。

若是是這種狀況,咱們要作的是什麼?對RowKey散列就行了,那分配到HRegion的時候就比較均勻,少了熱點的問題。

HBase優化手冊:
建表申請時的預分區設置,對於常用HBase的小夥伴來講,HBase管理平臺裏申請HBase表流程必然不陌生了。
'給定split的RowKey組例如:aaaaa,bbbbb,ccccc;或給定例如:startKey=00000000,endKey=xxxxxxxx,regionsNum=x' 
第一種方式: 
是本身指定RowKey的分割點來劃分region個數.好比有一組數據RowKey爲[1,2,3,4,5,6,7],此時給定split RowKey是3,6,那麼就會劃分爲[1,3),[3,6),[6,7)的三個初始region了.若是對於RowKey的組成及數據分佈很是清楚的話,可使用這種方式精確預分區.

第二種方式 :
若是隻是知道RowKey的組成大體的範圍,能夠選用這種方式讓集羣來均衡預分區,設定始末的RowKey,以及根據數據量給定大體的region數,通常建議region數最多不要超過集羣的rs節點數,過多region數不但不能增長表訪問性能,反而會增長master節點壓力.若是給定始末RowKey範圍與實際誤差較大的話,仍是比較容易產生數據熱點問題.

最後:生成RowKey時,儘可能進行加鹽或者哈希的處理,這樣很大程度上能夠緩解數據熱點問題.

4.2根據RowKey範圍查詢

上面的狀況是針對經過RowKey單個查詢的業務的,若是咱們是根據RowKey範圍查詢的,那不必上面那樣作。

HBase將RowKey設計爲字典序排序,若是不作限制,那極可能相似的RowKey存儲在同一個HRegion中。那我正好有這個場景上的業務,那我查詢的時候不是快多了嗎?在同一個HRegion就能夠拿到我想要的數據了。

舉個例子:咱們會間隔幾秒就採集直播間熱度,將這份數據寫到HBase中,而後業務方常常要把主播的一段時間內的熱度給查詢出來。

我設計好的RowKey,將該主播的一段時間內的熱度都寫到同一個HRegion上,拉取的時候只要訪問一個HRegionServer就能夠獲得所有我想要的數據了,那查詢的速度就快不少。

最後

最後三歪再來帶着你們回顧一下這篇文章寫了什麼:

  1. HBase是一個NoSQL數據庫,通常咱們用它來存儲海量的數據(由於它基於HDFS分佈式文件系統上構建的)
  2. HBase的一行記錄由一個RowKey和一個或多個的列以及它的值所組成。先有列族後有列,列能夠隨意添加。
  3. HBase的增刪改記錄都有「版本」,默認以時間戳的方式實現。
  4. RowKey的設計若是沒有特殊的業務性,最好設計爲散列的,這樣避免熱點數據分佈在同一個HRegionServer中。
  5. HBase的讀寫都通過Zookeeper去拉取meta數據,定位到對應的HRegion,而後找到HRegionServer

 

轉載於:https://zhuanlan.zhihu.com/p/145551967?

相關鏈接:https://mp.weixin.qq.com/s?__biz=MzI4Njk3NjU1OQ==&mid=2247483742&idx=1&sn=73dba4a18542362a9aea620f6371df11&chksm=ebd5fe1edca27708c741d842ab13ecde888bbd66ddce16389f62c71b336d7ee5b8834f323aa5&scene=21#wechat_redirect

相關文章
相關標籤/搜索