自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

20張圖帶你到HBase的世界遨游

大數(shù)據(jù)
HBase 是一款面向列存儲(chǔ),用于存儲(chǔ)處理海量數(shù)據(jù)的 NoSQL 數(shù)據(jù)庫(kù)。它的理論原型是Google 的 BigTable 論文。你可以認(rèn)為 HBase 是一個(gè)高可靠性、高性能、面向列、可伸縮的分布式存儲(chǔ)系統(tǒng)。

[[377104]]

本文轉(zhuǎn)載自微信公眾號(hào)「sowhat1412」,作者SoWhat1412  。轉(zhuǎn)載本文請(qǐng)聯(lián)系sowhat1412公眾號(hào)。

1 HBase 淺析

1.1 HBase 是啥

HBase 是一款面向列存儲(chǔ),用于存儲(chǔ)處理海量數(shù)據(jù)的 NoSQL 數(shù)據(jù)庫(kù)。它的理論原型是Google 的 BigTable 論文。你可以認(rèn)為 HBase 是一個(gè)高可靠性、高性能、面向列、可伸縮的分布式存儲(chǔ)系統(tǒng)。

HBase 的存儲(chǔ)是基于HDFS的,HDFS 有著高容錯(cuò)性的特點(diǎn),被設(shè)計(jì)用來(lái)部署在低廉的硬件上,基于 Hadoop 意味著 HBase 與生俱來(lái)的超強(qiáng)的擴(kuò)展性和吞吐量。

HBase 采用的時(shí)key/value的存儲(chǔ)方式,這意味著,即使隨著數(shù)據(jù)量的增大,也幾乎不會(huì)導(dǎo)致查詢性能的下降。HBase 又是一個(gè)面向列存儲(chǔ)的數(shù)據(jù)庫(kù),當(dāng)表的字段很多時(shí),可以把其中幾個(gè)字段獨(dú)立出來(lái)放在一部分機(jī)器上,而另外幾個(gè)字段放到另一部分機(jī)器上,充分分散了負(fù)載的壓力。如此復(fù)雜的存儲(chǔ)結(jié)構(gòu)和分布式的存儲(chǔ)方式,帶來(lái)的代價(jià)就是即便是存儲(chǔ)很少的數(shù)據(jù),也不會(huì)很快。

HBase 并不是足夠快,只是數(shù)據(jù)量很大的時(shí)候慢的不明顯。HBase主要用在以下兩種情況:

單表數(shù)據(jù)量超過(guò)千萬(wàn),而且并發(fā)量很大。

數(shù)據(jù)分析需求較弱,或者不需要那么實(shí)時(shí)靈活。

1.2 HBase 的由來(lái)

我們知道 Mysql 是一個(gè)關(guān)系型數(shù)據(jù)庫(kù),學(xué)數(shù)據(jù)庫(kù)的時(shí)第一個(gè)接觸的就是 MySQL 了。但是 MySQL 的性能瓶頸是很大的,一般單個(gè)table行數(shù)不宜超過(guò)500萬(wàn)行,大小不宜超過(guò)2G。

我們以互聯(lián)網(wǎng)公司最核心用戶表為例,當(dāng)數(shù)據(jù)量達(dá)到千萬(wàn)甚至億級(jí)別時(shí)候,盡管你可以通過(guò)各種優(yōu)化來(lái)提速查詢,但是對(duì)單條數(shù)據(jù)的檢索耗時(shí)還是會(huì)超出你的預(yù)期!看下這個(gè)User表:

 

假如查詢 id=1 這條數(shù)據(jù)對(duì)應(yīng)的用戶name,系統(tǒng)會(huì)給我們返回aa。但由于MySQL是以行為位單位存儲(chǔ)的,當(dāng)查 name 時(shí)卻需要查詢一整行的數(shù)據(jù),連 age 和 email 也會(huì)被查出來(lái)!如果列非常多,那么查詢效率可想而知了。

我們稱列過(guò)多的表為寬表,優(yōu)化方法一般就是對(duì)列進(jìn)行豎直拆分:

 

此時(shí)查找 name 時(shí)只需要查找 user_basic 表,沒有多余的字段,查詢效率就會(huì)很快。如果一張表的行過(guò)多,會(huì)影響查詢效率,我們將這樣的表稱之為高表,可以采用水平拆表的方式提高效率:

 

這種水平拆分應(yīng)用比較多的 場(chǎng)景就是日志表,日志信息每天產(chǎn)生很多,可以按月/按日進(jìn)行水平拆分,這樣就實(shí)現(xiàn)了高表變矮。

上述的拆分方式貌似可以解決寬表跟高表問題,但是如果有一天公司業(yè)務(wù)變更,比如原來(lái)沒有微信,現(xiàn)在需加入用戶的微信字段。這時(shí)候需要改變表的結(jié)構(gòu)信息,該怎么辦?最簡(jiǎn)單的想法是多加一列,像這樣:

 

但是你要知道不是所有用戶都要微信號(hào)的,微信號(hào)這一列是設(shè)置默認(rèn)值還是采取其他的做法就得權(quán)衡一下了。如果需擴(kuò)展很多列出來(lái),但不是所有的用戶都有這些屬性,那么拓展起來(lái)就更加復(fù)雜了。這時(shí)可以用下JSON格式的字符串,將若干可選擇填寫信息匯總,而且屬性字段可以動(dòng)態(tài)拓展,于是有了下邊做法:

至此你可能認(rèn)為這樣存儲(chǔ)數(shù)據(jù)它不挺好的嘛,用 HBase 出來(lái)干嘛?Mysql 有個(gè)致命缺點(diǎn),就是當(dāng)數(shù)據(jù)達(dá)到一定的閾值,無(wú)論怎么優(yōu)化,它都無(wú)法達(dá)到高性能的發(fā)揮。而大數(shù)據(jù)領(lǐng)域的數(shù)據(jù),動(dòng)輒 PB 級(jí)數(shù)據(jù)量,這種存儲(chǔ)應(yīng)用明顯是不能很好的滿足需求的!并且針對(duì)上邊的問題,HBase 都有很好的解決方案~~。

 

1.3 HBase 設(shè)計(jì)思路

接著上邊說(shuō)到的幾個(gè)問題:高表、寬表、數(shù)據(jù)列動(dòng)態(tài)擴(kuò)展,把提到的幾個(gè)解決辦法:水平切分、垂直切分、列擴(kuò)展方法 雜糅在一起。

有張表,你怕它又寬又高跟動(dòng)態(tài)擴(kuò)展列,那么在設(shè)計(jì)之初,就把這個(gè)表給拆開,為了列的動(dòng)態(tài)拓展,直接存儲(chǔ)JSON格式:

這樣就解決了寬表跟列擴(kuò)展問題,高表怎么辦呢?一個(gè)表按行切分成partition,各存一部分行:

 

解決了高表、寬表、動(dòng)態(tài)擴(kuò)展列 的問題后你會(huì)發(fā)現(xiàn)數(shù)據(jù)量大了速度不夠快咋辦?用緩存唄,查詢出的數(shù)據(jù)放緩存中,下次直接從緩存拿數(shù)據(jù)。插入數(shù)據(jù)怎么辦呢?也可以這樣理解,我把要插入的數(shù)據(jù)放進(jìn)緩存中,再也不用管了,直接由數(shù)據(jù)庫(kù)從緩存拿數(shù)據(jù)插入到數(shù)據(jù)庫(kù)。此時(shí)程序不需要等待數(shù)據(jù)插入成功,提高了并行工作的效率。

你用緩存的考慮服務(wù)器宕機(jī)后緩存中數(shù)據(jù)沒來(lái)得及插入到數(shù)據(jù)庫(kù)中造成丟數(shù)據(jù)咋辦?參考 Redis 的持久化策略,可以插入數(shù)據(jù)這個(gè)操作添加一個(gè)操作日志,用于持久化插入操作,宕機(jī)重啟后從日志恢復(fù)。這樣設(shè)計(jì)架構(gòu)就變成了這個(gè)樣子:

這就是 HBase 實(shí)現(xiàn)的大致思路。接下來(lái)正式進(jìn)入 HBase 設(shè)計(jì)解析。

 

2 Hbase 簡(jiǎn)介

Hbase 官網(wǎng):http://hbase.apache.org

2.1 HBase 特點(diǎn)

海量存儲(chǔ)

HBase適合存儲(chǔ) PB 級(jí)別的海量數(shù)據(jù),能在幾十到百毫秒內(nèi)返回?cái)?shù)據(jù)。

列式存儲(chǔ)

HBase是根據(jù)列族來(lái)存儲(chǔ)數(shù)據(jù)的。列族下面可以有非常多的列,在創(chuàng)建表的時(shí)候列族就必須指定。

高并發(fā)

在并發(fā)的情況下,HBase的單個(gè)IO延遲下降并不多,能獲得高并發(fā)、低延遲的服務(wù)。

稀疏性

HBase的列具有靈活性,在列族中,你可以指定任意多的列,在列數(shù)據(jù)為空的情況下,是不會(huì)占用存儲(chǔ)空間的。

極易擴(kuò)展

基于 RegionServer 的擴(kuò)展,通過(guò)橫向添加 RegionSever 的機(jī)器,進(jìn)行水平擴(kuò)展,提升 HBase 上層的處理能力,提升HBase服務(wù)更多 Region 的能力。

基于存儲(chǔ)的擴(kuò)展(HDFS)。

2.2 HBase 邏輯結(jié)構(gòu)

邏輯思維層面 HBase的存儲(chǔ)模型如下:

 

Table(表):

表由一個(gè)或者多個(gè)列族構(gòu)成。數(shù)據(jù)的屬性如name、age、TTL(超時(shí)時(shí)間)等都在列族里邊定義。定義完列族的表是個(gè)空表,只有添加了數(shù)據(jù)行以后,表才有數(shù)據(jù)。

Column (列):

HBase 中的每個(gè)列都由 Column Family(列族) 和 Column Qualifier(列限定符)進(jìn)行限定,例如 info:name、info:age。建表時(shí)只需指明列族,而列限定符無(wú)需預(yù)先定義。

Column Family(列族):

多個(gè)列組合成一個(gè)列族。建表時(shí)不用創(chuàng)建列,在 HBase 中列是可增減變化的!唯一要確定的是列族,表有幾個(gè)列族在開始創(chuàng)建時(shí)就定好的。表的很多屬性,比如數(shù)據(jù)過(guò)期時(shí)間、數(shù)據(jù)塊緩存以及是否使用壓縮等都是定義在列族上的。

HBase 會(huì)把相同列族的幾個(gè)列數(shù)據(jù)盡量放在同一臺(tái)機(jī)器上。

Row(行):

一行包含多個(gè)列,這些列通過(guò)列族來(lái)分類。行中的數(shù)據(jù)所屬的列族從該表所定義的列族中選取。由于HBase是一個(gè)面向列存儲(chǔ)的數(shù)據(jù)庫(kù),所以一個(gè)行中的數(shù)據(jù)可以分布在不同的服務(wù)器上。

RowKey(行鍵):

RowKey 類似 MySQL 中的主鍵,在 HBase 中 RowKey 必須有且 RowKey 是按照字典排序的,如果用戶不指定 RowKey 系統(tǒng)會(huì)自動(dòng)生成不重復(fù)字符串。查詢數(shù)據(jù)時(shí)只能根據(jù) RowKey 進(jìn)行檢索,所以 Table 的 RowKey 設(shè)計(jì)十分重要。

Region(區(qū)域):

Region 就是若干行數(shù)據(jù)的集合。HBase 中的 Region 會(huì)根據(jù)數(shù)據(jù)量的大小動(dòng)態(tài)分裂,Region是基于HDFS實(shí)現(xiàn)的,關(guān)于Region的存取操作都是調(diào)用HDFS客戶端完成的。同一個(gè)行鍵的 Region 不會(huì)被拆分到多個(gè) Region 服務(wù)器上。

Region 有一點(diǎn)像關(guān)系型數(shù)據(jù)的分區(qū),數(shù)據(jù)存放在Region中,當(dāng)然Region下面還有很多結(jié)構(gòu),確切來(lái)說(shuō)數(shù)據(jù)存放在MemStore和HFile中。訪問HBase 時(shí)先去HBase 系統(tǒng)表查找定位這條記錄屬于哪個(gè)Region ,然后定位到這個(gè)Region 屬于哪個(gè)服務(wù)器,然后就到哪個(gè)服務(wù)器里面查找對(duì)應(yīng)Region 中的數(shù)據(jù)。

RegionServer:

RegionServer 就是存放Region的容器,直觀上說(shuō)就是服務(wù)器上的一個(gè)服務(wù)。負(fù)責(zé)管理維護(hù) Region。

2.3 HBase 物理存儲(chǔ)

以上只是一個(gè)基本的邏輯結(jié)構(gòu),底層的物理存儲(chǔ)結(jié)構(gòu)才是重中之重的內(nèi)容,看下圖

 

NameSpace:

命名空間,類似關(guān)系型數(shù)據(jù)庫(kù) DatabBase 概念,每個(gè)命名空間下有多個(gè)表。HBase有兩個(gè)自帶的命名空間,分別是hbase和default,hbase 中存放的是 HBase 內(nèi)置的表,default 表是用戶默認(rèn)使用的命名空間。

TimeStamp:

時(shí)間戳,用于標(biāo)識(shí)數(shù)據(jù)的不同版本(version),每條數(shù)據(jù)寫入時(shí)如果不指定時(shí)間戳,系統(tǒng)會(huì)自動(dòng)添加為其寫入 HBase 的時(shí)間。并且讀取數(shù)據(jù)的時(shí)候一般只拿出數(shù)據(jù)的Type符合,時(shí)間戳最新的數(shù)據(jù)。之所以按照Type取數(shù)據(jù)是因?yàn)镠Base的底層HDFS支持增刪查,但不支持改。

Cell:

單元格,由 {rowkey, column Family:column Qualifier, time Stamp} 唯一確定的單元。cell 中的數(shù)據(jù)是沒有類型的,全部是字節(jié)碼形式存儲(chǔ)。

3 HBase 底層架構(gòu)

 

3.1 Client

Client 包含了訪問 Hbase 的接口,另外 Client 還維護(hù)了對(duì)應(yīng)的 cache 來(lái)加速 Hbase 的訪問,比如緩存元數(shù)據(jù)的信息。

3.2 Zookeeper

HBase 通過(guò) Zookeeper 來(lái)做 Master 的高可用、RegionServer 的監(jiān)控、元數(shù)據(jù)的入口以及集群配置的維護(hù)等工作。Zookeeper 職責(zé)如下:

通過(guò)Zoopkeeper來(lái)保證集群中只有1個(gè)Master 在運(yùn)行,如果Master 發(fā)生異常會(huì)通過(guò)競(jìng)爭(zhēng)機(jī)制產(chǎn)生新的Master 來(lái)提供服務(wù)。

通過(guò) Zoopkeeper 來(lái)監(jiān)控 RegionServer 的狀態(tài),當(dāng)RegionSevrer有異常的時(shí)候,通過(guò)回調(diào)的形式通知MasterRegionServer上下線的信息。

通過(guò) Zoopkeeper 存儲(chǔ)元數(shù)據(jù) hbase:meata 的統(tǒng)一入口地址。

3.3 Master

Master 在 HBase 中的地位比其他類型的集群弱很多!數(shù)據(jù)的讀寫操作與他沒有關(guān)系,它掛了之后,集群照樣運(yùn)行。但是Master 也不能宕機(jī)太久,有很多必要的操作,比如創(chuàng)建表、修改列族配置等DDL跟Region的分割與合并都需要它的操作。

  1. 負(fù)責(zé)啟動(dòng)的時(shí)候分配Region到具體的 RegionServer。
  2. 發(fā)現(xiàn)失效的 Region,并將失效的 Region 分配到正常的 RegionServer 上。
  3. 管理HRegion服務(wù)器的負(fù)載均衡,調(diào)整HRegion分布。
  4. 在HRegion分裂后,負(fù)責(zé)新HRegion的分配。

HBase 中可以啟動(dòng)多個(gè)Master,通過(guò) Zookeeper 的 Master Election 機(jī)制保證總有一個(gè) Master 運(yùn)行。

3.4 RegionServer

HregionServer 直接對(duì)接用戶的讀寫請(qǐng)求,是真正的干活的節(jié)點(diǎn)。它的功能概括如下:

  1. 管理Master為其分配的Region。
  2. 處理來(lái)自客戶端的讀寫請(qǐng)求。
  3. 負(fù)責(zé)和底層HDFS的交互,存儲(chǔ)數(shù)據(jù)到HDFS。
  4. 負(fù)責(zé)Region變大以后的拆分。
  5. 負(fù)責(zé)StoreFile的合并工作。

ZooKeeper 會(huì)監(jiān)控 RegionServer 的上下線情況,當(dāng) ZK 發(fā)現(xiàn)某個(gè) HRegionServer 宕機(jī)之后會(huì)通知 Master 進(jìn)行失效備援。下線的 RegionServer 所負(fù)責(zé)的 Region 暫時(shí)停止對(duì)外提供服務(wù),Master 會(huì)將該 RegionServer 所負(fù)責(zé)的 Region 轉(zhuǎn)移到其他 RegionServer 上,并且會(huì)對(duì) 下線RegionServer 上存在 MemStore 中還未持久化到磁盤中的數(shù)據(jù)由 WAL重播進(jìn)行恢復(fù)。

3.5 WAL

WAL (Write-Ahead-Log) 預(yù)寫日志是 HBase 的 RegionServer 在處理數(shù)據(jù)插入和刪除的過(guò)程中用來(lái)記錄操作內(nèi)容的一種日志。每次Put、Delete等一條記錄時(shí),首先將其數(shù)據(jù)寫入到 RegionServer 對(duì)應(yīng)的HLog文件中去。只有當(dāng)WAL日志寫入成功的時(shí)候,客戶端才會(huì)被告訴提交數(shù)據(jù)成功。如果寫WAL失敗會(huì)告知客戶端提交失敗,這其實(shí)就是數(shù)據(jù)落地的過(guò)程。

WAL是保存在HDFS上的持久化文件。數(shù)據(jù)到達(dá) Region 時(shí)先寫入WAL,然后被加載到MemStore中。這樣就算Region宕機(jī)了,操作沒來(lái)得及執(zhí)行持久化,也可以再重啟的時(shí)候從WAL加載操作并執(zhí)行。跟Redis的AOF類似。

  1. 在一個(gè) RegionServer 上的所有 Region 都共享一個(gè) HLog,一次數(shù)據(jù)的提交先寫入WAL,寫入成功后,再寫入MenStore之中。當(dāng)MenStore的值達(dá)到一定的時(shí)候,就會(huì)形成一個(gè)個(gè)StoreFile。
  2. WAL 默認(rèn)是開啟 的,也可以手動(dòng)關(guān)閉它,這樣增刪改操作會(huì)快一點(diǎn)。但是這樣做犧牲的是數(shù)據(jù)的安全性。如果不想關(guān)閉WAL,又不想每次都耗費(fèi)那么大的資源,每次改動(dòng)都調(diào)用HDFS客戶端,可以選擇異步的方式寫入WAL(默認(rèn)間隔1秒寫入)
  3. 如果你學(xué)過(guò) Hadoop 中的 Shuffle(edits文件) 機(jī)制的就可以猜測(cè)到 HBase 中的 WAL 也是一個(gè)滾動(dòng)的日志數(shù)據(jù)結(jié)構(gòu),一個(gè)WAL實(shí)例包含多個(gè)WAL文件,WAL被觸發(fā)滾動(dòng)的條件如下。
  • WAL的大小超過(guò)了一定的閾值。
  • WAL文件所在的HDFS文件塊快要滿了。
  • WAL歸檔和刪除。

3.5 Region

每一個(gè) Region 都有起始 RowKey 和結(jié)束 RowKey,代表了存儲(chǔ)的Row的范圍。從大圖中可知一個(gè)Region有多個(gè)Store,一個(gè)Store就是對(duì)應(yīng)一個(gè)列族的數(shù)據(jù),Store 由 MemStore 和 HFile 組成的。

3.6 Store

Store 由 MemStore 跟 HFile 兩個(gè)重要的部分。

3.6.1 MemStore

每個(gè) Store 都有一個(gè) MemStore 實(shí)例,數(shù)據(jù)寫入到 WAL 之后就會(huì)被放入 MemStore 中。MemStore是內(nèi)存的存儲(chǔ)對(duì)象,當(dāng) MemStore 的大小達(dá)到一個(gè)閥值(默認(rèn)64MB)時(shí),MemStore 會(huì)被 flush到文件,即生成一個(gè)快照。目前HBase 會(huì)有一個(gè)線程來(lái)負(fù)責(zé)MemStore 的flush操作。

3.6.2 StoreFile

MemStore 內(nèi)存中的數(shù)據(jù)寫到文件后就是StoreFile,StoreFile底層是以 HFile 的格式保存。HBase以Store的大小來(lái)判斷是否需要切分Region。

3.6.3 HFile

在Store中有多個(gè)HFile,每次刷寫都會(huì)形成一個(gè)HFile文件落盤在HDFS上。HFile文件也會(huì)動(dòng)態(tài)合并,它是數(shù)據(jù)存儲(chǔ)的實(shí)體。

這里提出一點(diǎn)疑問:操作到達(dá)Region時(shí),數(shù)據(jù)進(jìn)入HFile之前就已經(jīng)被持久化到WAL了,而WAL就是在HDFS上的,為什么還要從WAL加載到MemStore中,再刷寫成HFile呢?

由于HDFS支持文件創(chuàng)建、追加、刪除,但不能修改!但對(duì)數(shù)據(jù)庫(kù)來(lái)說(shuō),數(shù)據(jù)的順序非常重要!

第一次WAL的持久化是為了保證數(shù)據(jù)的安全性,無(wú)序的。

再讀取到MemStore中,是為了排序后存儲(chǔ)。

所以MemStore的意義在于維持?jǐn)?shù)據(jù)按照RowKey的字典序排列,而不是做一個(gè)緩存提高寫入效率。

3.7 HDFS

HDFS 為 HBase 提供最終的底層數(shù)據(jù)存儲(chǔ)服務(wù),HBase 底層用HFile格式 (跟hadoop底層的數(shù)據(jù)存儲(chǔ)格式類似) 將數(shù)據(jù)存儲(chǔ)到HDFS中,同時(shí)為HBase提供高可用(Hlog存儲(chǔ)在HDFS)的支持,具體功能概括如下:

提供元數(shù)據(jù)和表數(shù)據(jù)的底層分布式存儲(chǔ)服務(wù)

數(shù)據(jù)多副本,保證的高可靠和高可用性

4 HBase 讀寫

在HBase集群中如果我們做 DML 操作是不需要關(guān)心 HMaster 的,只需要從 ZooKeeper 中獲得hbase:meta 數(shù)據(jù)地址,然后從RegionServer中增刪查數(shù)據(jù)即可。

4.1 HBase 寫流程

 

  1. Client 先訪問 zookeeper,訪問 /hbase/meta-region-server 獲取 hbase:meta 表位于哪個(gè) Region Server。
  2. 訪問對(duì)應(yīng)的 Region Server,獲取 hbase:meta 表,根據(jù)讀請(qǐng)求的 namespace:table/rowkey,查詢出目標(biāo)數(shù)據(jù)位于哪個(gè) Region Server 中的哪個(gè) Region 中。并將該 table 的 Region 信息以及 meta 表的位置信息緩存在客戶端的 meta cache,方便下次訪問。
  3. 與目標(biāo) Region Server 進(jìn)行通訊。
  4. 將數(shù)據(jù)順序?qū)懭?追加)到 WAL。
  5. 將數(shù)據(jù)寫入對(duì)應(yīng)的 MemStore,數(shù)據(jù)會(huì)在 MemStore 進(jìn)行排序。
  6. 向客戶端發(fā)送 ack,此處可看到數(shù)據(jù)不是必須落盤的。
  7. 等達(dá)到 MemStore 的刷寫時(shí)機(jī)后,將數(shù)據(jù)刷寫到 HFile
  8. 在web頁(yè)面查看的時(shí)候會(huì)隨機(jī)的給每一個(gè)Region生成一個(gè)隨機(jī)編號(hào)。

4.2 HBase 讀流程

 

  1. Client 先訪問 ZooKeeper,獲取 hbase:meta 表位于哪個(gè) Region Server。
  2. 訪問對(duì)應(yīng)的 Region Server,獲取 hbase:meta 表,根據(jù)讀請(qǐng)求的 namespace:table/rowkey, 查詢出目標(biāo)數(shù)據(jù)位于哪個(gè) Region Server 中的哪個(gè) Region 中。并將該 table 的 region 信息以 及 meta 表的位置信息緩存在客戶端的 meta cache,方便下次訪問。
  3. 與目標(biāo) Region Server 進(jìn)行通訊。
  4. 分別在 Block Cache(讀緩存),MemStore 和 Store File(HFile)中查詢目標(biāo)數(shù)據(jù),并將 查到的所有數(shù)據(jù)進(jìn)行合并。此處所有數(shù)據(jù)是指同一條數(shù)據(jù)的不同版本(time stamp)或者不同的類型(Put/Delete)。
  5. 將從文件HFile中查詢到的數(shù)據(jù)塊(Block,HFile 數(shù)據(jù)存儲(chǔ)單元,默認(rèn)大小為 64KB)緩存到 Block Cache。
  6. 將合并后的最終結(jié)果,然后返回時(shí)間最新的數(shù)據(jù)返回給客戶端。

4.2.1 Block Cache

HBase 在實(shí)現(xiàn)中提供了兩種緩存結(jié)構(gòu) MemStore(寫緩存) 和 BlockCache(讀緩存)。寫緩存前面說(shuō)過(guò)不再重復(fù)。

HBase 會(huì)將一次文件查找的 Block塊 緩存到 Cache中,以便后續(xù)同一請(qǐng)求或者鄰近數(shù)據(jù)查找請(qǐng)求,可以直接從內(nèi)存中獲取,避免昂貴的IO操作。

BlockCache是Region Server級(jí)別的,

一個(gè)Region Server只有一個(gè)Block Cache,在 Region Server 啟動(dòng)的時(shí)候完成 Block Cache 的初始化工作。

HBase對(duì)Block Cache的管理分為如下三種。

LRUBlockCache 是最初的實(shí)現(xiàn)方案,也是默認(rèn)的實(shí)現(xiàn)方案,將所有數(shù)據(jù)都放入JVM Heap中,交給JVM進(jìn)行管理。

SlabCache 實(shí)現(xiàn)的是堆外內(nèi)存存儲(chǔ),不再由JVM管理數(shù)據(jù)內(nèi)存。一般跟第一個(gè)組合使用,單它沒有改善 GC 弊端,引入了堆外內(nèi)存利用率低。

BucketCache 緩存淘汰不再由 JVM 管理 降低了Full GC 發(fā)生的頻率。

重點(diǎn):

讀數(shù)據(jù)時(shí)不要理解為先從 MemStore 中讀取,讀不到再讀 BlockCache 中,還讀不到再?gòu)腍File中讀取,然后將數(shù)據(jù)寫入到 BlockCache 中。因?yàn)槿绻藶樵O(shè)置導(dǎo)致磁盤數(shù)據(jù)new,內(nèi)存數(shù)據(jù)old。你讀取的時(shí)候會(huì)出錯(cuò)的!

結(jié)論:

HBase 把磁盤跟內(nèi)存數(shù)據(jù)一起讀,然后把磁盤數(shù)據(jù)放到 BlockCache中,BlockCache 是磁盤數(shù)據(jù)的緩存。HBase 是個(gè)讀比寫慢的工具。

4.3 HBase 為什么寫比讀快

HBase 能提供實(shí)時(shí)計(jì)算服務(wù)主要原因是由其架構(gòu)和底層的數(shù)據(jù)結(jié)構(gòu)決定的,即由LSM-Tree(Log-Structured Merge-Tree) + HTable(Region分區(qū)) + Cache決定的。

HBase 寫入速度快是因?yàn)閿?shù)據(jù)并不是真的立即落盤,而是先寫入內(nèi)存,隨后異步刷入HFile。所以在客戶端看來(lái),寫入速度很快。

HBase 存儲(chǔ)到內(nèi)存中的數(shù)據(jù)是有序的,內(nèi)存數(shù)據(jù)刷寫到HFile時(shí)也是有序的。并且多個(gè)有序的HFile還會(huì)進(jìn)行歸并排序生成更大的有序HFile。性能測(cè)試發(fā)現(xiàn)順序讀寫磁盤速度比隨機(jī)讀寫磁盤快至少三個(gè)數(shù)量級(jí)!

 

讀取速度快是因?yàn)樗褂昧薒SM樹型結(jié)構(gòu),因?yàn)榇疟P尋址耗時(shí)遠(yuǎn)遠(yuǎn)大于磁盤順序讀取的時(shí)間,HBase的架構(gòu)設(shè)計(jì)導(dǎo)致我們可以將磁盤尋址次數(shù)控制在性能允許范圍內(nèi)。

LSM 樹原理把一棵大樹拆分成N棵小樹,它首先寫入內(nèi)存中,隨著小樹越來(lái)越大,內(nèi)存中的小樹會(huì)flush到磁盤中,磁盤中的樹定期可以做merge操作來(lái)合并成一棵大樹,以優(yōu)化讀性能。

4.3.1查詢舉例

  1. 根據(jù)RowKey能快速找到行所在的Region,假設(shè)有10億條記錄,占空間1TB。分列成了500個(gè)Region,那讀取2G的記錄,就能找到對(duì)應(yīng)記錄。
  2. 數(shù)據(jù)是按照列族存儲(chǔ)的,假設(shè)分為3個(gè)列族,每個(gè)列族就是666M, 如果要查詢的東西在其中1個(gè)列族上,1個(gè)列族包含1個(gè)或者多個(gè) HStoreFile,假設(shè)一個(gè)HStoreFile是128M, 該列族包含5個(gè)HStoreFile在磁盤上. 剩下的在內(nèi)存中。
  3. 內(nèi)存跟磁盤中數(shù)據(jù)是排好序的,你要的記錄有可能在最前面,也有可能在最后面,假設(shè)在中間,我們只需遍歷2.5個(gè)HStoreFile共300M。
  4. 每個(gè)HStoreFile(HFile的封裝),是以鍵值對(duì)(KV)方式存儲(chǔ),只要遍歷一個(gè)個(gè)數(shù)據(jù)塊中的key的位置,并判斷符合條件可以了。一般key是有限的長(zhǎng)度,假設(shè)KV比是1:19,最終只需要15M就可獲取的對(duì)應(yīng)的記錄,按照磁盤的訪問100M/S,只需0.15秒。加上Block Cache 會(huì)取得更高的效率。
  5. 大致理解讀寫思路后你會(huì)發(fā)現(xiàn)如果你在讀寫時(shí)設(shè)計(jì)的足夠巧妙當(dāng)然讀寫速度快的很咯。

5 HBase Flush

5.1 Flush

對(duì)于用戶來(lái)說(shuō)數(shù)據(jù)寫到 MemStore 中就算OK,但對(duì)于底層代碼來(lái)說(shuō)只有數(shù)據(jù)刷到硬盤中才算徹底搞定了!因?yàn)閿?shù)據(jù)是要寫入到WAL(Hlog)中再寫入到MemStore中的,flush有如下幾個(gè)時(shí)機(jī)。

  1. 當(dāng) WAL 文件的數(shù)量超過(guò)設(shè)定值時(shí) Region 會(huì)按照時(shí)間順序依次進(jìn)行刷寫,直到 WAL 文件數(shù)量小于設(shè)定值。
  2. 當(dāng)Region Server 中 MemStore 的總大小達(dá)到堆內(nèi)存40%時(shí),Region 會(huì)按照其所有 MemStore 的大小順序(由大到小)依次進(jìn)行阻塞刷寫。直到Region Server中所有 MemStore 的總大小減小到上述值以下。當(dāng)阻塞刷寫到上個(gè)參數(shù)的0.95倍時(shí),客戶端可以繼續(xù)寫。
  3. 當(dāng)某個(gè) MemStore 的大小達(dá)到了128M時(shí),其所在 Region 的所有 MemStore 都會(huì)阻塞刷寫。
  4. 到達(dá)自動(dòng)刷寫的時(shí)間也會(huì)觸發(fā) MemStore 的 flush。自動(dòng)刷新的時(shí)間間隔默認(rèn)1小時(shí)。

5.2 StoreFile Compaction

由于 MemStore 每次刷寫都會(huì)生成一個(gè)新的 HFile,且同一個(gè)字段的不同版本(timestamp) 和不同類型(Put/Delete)有可能會(huì)分布在不同的 HFile 中,因此查詢時(shí)需要遍歷所有的 HFile。為了減少 HFile 的個(gè)數(shù)跟清理掉過(guò)期和刪除的數(shù)據(jù),會(huì)進(jìn)行 StoreFile Compaction。

Compaction 分為兩種,分別是 Minor Compaction 和 Major Compaction。

  1. Minor Compaction會(huì)將臨近的若干個(gè)較小的 HFile 合并成一個(gè)較大的 HFile,但不會(huì)清理過(guò)期和刪除的數(shù)據(jù)。
  2. Major Compaction 會(huì)將一個(gè) Store 下的所有的 HFile 合并成一個(gè)大 HFile,并且會(huì)清理掉過(guò)期和刪除的數(shù)據(jù)。

 

5.3 Region Split

每個(gè) Table 起初只有一個(gè) Region,隨著不斷寫數(shù)據(jù) Region 會(huì)自動(dòng)進(jìn)行拆分。剛拆分時(shí),兩個(gè)子 Region 都位于當(dāng)前的 Region Server,但出于負(fù)載均衡的考慮, HMaster 有可能會(huì)將某個(gè) Region 轉(zhuǎn)移給其他的 Region Server。

 

Region Split 時(shí)機(jī):

0.94 版本之前:

  • 當(dāng) 1 個(gè) Region 中的某個(gè) Store 下所有 StoreFile 的總大小超過(guò) hbase.hregion.max.filesize(默認(rèn)10G), 該 Region 就會(huì)進(jìn)行拆分。

0.94 版本之后:

  • 當(dāng) 1 個(gè) Region 中的某個(gè) Store 下所有 StoreFile 的總大小超過(guò) Min(R^2 * “hbase.hregion.memstore.flush.size=128M”,hbase.hregion.max.filesize"),該 Region 就會(huì)進(jìn)行拆分,其 中 R 為當(dāng)前 Region Server 中屬于該 Table 的個(gè)數(shù)。

舉例:

  • 第一次的閾值是128,切分后結(jié)果64 , 64。
  • 第二次閾值512M,64,512 ⇒ 54 + 256 + 256
  • 最后會(huì)形成一個(gè) 64M…10G 的這樣Region隊(duì)列,會(huì)產(chǎn)生數(shù)據(jù)傾斜問題。
  • 解決方法:提前做好Region組的規(guī)劃,0-1k,1k-2k,2k-3k這樣的。

官方不建議用多個(gè)列族,比如有CF1,CF2,CF3,但是 CF1數(shù)據(jù)很多而CF2跟CF3數(shù)據(jù)很少,那么當(dāng)觸發(fā)了region切分的時(shí)候,會(huì)把CF2跟CF3分成若干小份,不利于系統(tǒng)維護(hù)。

6 HBase 常見面試題

6.1 Hbase 中 RowKey 的設(shè)計(jì)原則

RowKey 長(zhǎng)度原則

二進(jìn)制碼流RowKey 最大長(zhǎng)度 64Kb,實(shí)際應(yīng)用中一般為 10-100bytes,以 byte[] 形式保存,一般設(shè)計(jì)定長(zhǎng)。建議越短越好,因?yàn)镠File是按照KV存儲(chǔ)的Key太大浪費(fèi)空間。

RowKey 散列原則

RowKey 在設(shè)計(jì)時(shí)候要盡可能的實(shí)現(xiàn)可以將數(shù)據(jù)均衡的分布在每個(gè) RegionServer 上。

RowKey 唯一原則

RowKey 必須在設(shè)計(jì)上保證其唯一性,RowKey 是按照字典順序排序存儲(chǔ)的,因此設(shè)計(jì) RowKey 時(shí)可以將將經(jīng)常讀取的數(shù)據(jù)存儲(chǔ)到一塊。

6.2 HBase 在大數(shù)據(jù)體系位置

其實(shí)就簡(jiǎn)單的把HBase當(dāng)成大數(shù)據(jù)體系下的DataBase來(lái)用就行,任何可以分析HBase的引擎比如MR、Hive、Spark等框架連接上HBase都可以實(shí)現(xiàn)控制。比如你可以把Hive跟HBase進(jìn)行關(guān)聯(lián),Hive中數(shù)據(jù)不再由HDFS存儲(chǔ)而是存儲(chǔ)到HBase中,并且關(guān)聯(lián)后Hive中添加數(shù)據(jù)在HBase中可看到,HBase中添加數(shù)據(jù)Hive也可看到。

6.3 HBase 優(yōu)化方法

6.3.1 減少調(diào)整

HBase中有幾個(gè)內(nèi)容會(huì)動(dòng)態(tài)調(diào)整,如Region(分區(qū))、HFile。通過(guò)一些方法可以減少這些會(huì)帶來(lái)I/O開銷的調(diào)整。

Region

沒有預(yù)建分區(qū)的話,隨著Region中條數(shù)的增加,Region會(huì)進(jìn)行分裂,這將增加I/O開銷,所以解決方法就是根據(jù)你的RowKey設(shè)計(jì)來(lái)進(jìn)行預(yù)建分區(qū),減少Region的動(dòng)態(tài)分裂。

HFile

MemStore執(zhí)行flush會(huì)生成HFile,同時(shí)HFilewe年過(guò)多時(shí)候也會(huì)進(jìn)行Merge, 為了減少這樣的無(wú)謂的I/O開銷,建議估計(jì)項(xiàng)目數(shù)據(jù)量大小,給HFile設(shè)定一個(gè)合適的值。

6.3.2 減少啟停

數(shù)據(jù)庫(kù)事務(wù)機(jī)制就是為了更好地實(shí)現(xiàn)批量寫入,較少數(shù)據(jù)庫(kù)的開啟關(guān)閉帶來(lái)的開銷,那么HBase中也存在頻繁開啟關(guān)閉帶來(lái)的問題。

關(guān)閉 Compaction。

HBase 中自動(dòng)化的Minor Compaction和Major Compaction會(huì)帶來(lái)極大的I/O開銷,為了避免這種不受控制的意外發(fā)生,建議關(guān)閉自動(dòng)Compaction,在閑時(shí)進(jìn)行compaction。

6.3.3 減少數(shù)據(jù)量

開啟過(guò)濾,提高查詢速度

開啟BloomFilter,BloomFilter是列族級(jí)別的過(guò)濾,在生成一個(gè)StoreFile同時(shí)會(huì)生成一個(gè)MetaBlock,用于查詢時(shí)過(guò)濾數(shù)據(jù)

使用壓縮

一般推薦使用Snappy和LZO壓縮

6.3.4 合理設(shè)計(jì)

HBase 表格中 RowKey 和 ColumnFamily 的設(shè)計(jì)是非常重要,好的設(shè)計(jì)能夠提高性能和保證數(shù)據(jù)的準(zhǔn)確性。

RowKey設(shè)計(jì)

  • 散列性:散列性能夠保證相同相似的RowKey聚合,相異的RowKey分散,有利于查詢
  • 簡(jiǎn)短性:RowKey作為key的一部分存儲(chǔ)在HFile中,如果為了可讀性將rowKey設(shè)計(jì)得過(guò)長(zhǎng),那么將會(huì)增加存儲(chǔ)壓力.
  • 唯一性:rowKey必須具備明顯的區(qū)別性。
  • 業(yè)務(wù)性:具體情況具體分析。

列族的設(shè)計(jì)

  • 優(yōu)勢(shì):HBase中數(shù)據(jù)是按列進(jìn)行存儲(chǔ)的,那么查詢某一列族的某一列時(shí)就不需要全盤掃描,只需要掃描某一列族,減少了讀I/O。
  • 劣勢(shì):多列族意味這一個(gè)Region有多個(gè)Store,一個(gè)Store就有一個(gè)MemStore,當(dāng)MemStore進(jìn)行flush時(shí),屬于同一個(gè)Region的Store中的MemStore都會(huì)進(jìn)行flush,增加I/O開銷。

6.4 HBase 跟關(guān)系型數(shù)據(jù)庫(kù)區(qū)別

指標(biāo) 傳統(tǒng)關(guān)系數(shù)據(jù)庫(kù) HBase
數(shù)據(jù)類型 有豐富的數(shù)據(jù)類型 字符串
數(shù)據(jù)操作 豐富操作,復(fù)雜聯(lián)表查詢 簡(jiǎn)單CRUD
存儲(chǔ)模式 基于行存儲(chǔ) 基于列存儲(chǔ)
數(shù)據(jù)索引 復(fù)雜的多個(gè)索引 只有RowKey索引
數(shù)據(jù)維護(hù) 新覆蓋舊 多版本
可伸縮性 難實(shí)現(xiàn)橫向擴(kuò)展 性能動(dòng)態(tài)伸縮

6.5 HBase 批量導(dǎo)入

  1. 通過(guò) HBase API進(jìn)行批量寫入數(shù)據(jù)。
  2. 使用 Sqoop工具批量導(dǎo)數(shù)到HBase集群。
  3. 使用 MapReduce 批量導(dǎo)入。
  4. HBase BulkLoad的方式。
  5. HBase 通過(guò) Hive 關(guān)聯(lián)導(dǎo)入數(shù)據(jù)。

大數(shù)據(jù)導(dǎo)入用 HBase API 跟 MapReduce 寫入效率會(huì)很低,因?yàn)檎?qǐng)求RegionServer 將數(shù)據(jù)寫入,這期間數(shù)據(jù)會(huì)先寫入 WAL 跟 MemStore,MemStore 達(dá)到閾值后會(huì)刷寫到磁盤生成 HFile文件,HFile文件過(guò)多時(shí)會(huì)發(fā)生Compaction,如果Region大小過(guò)大時(shí)也會(huì)發(fā)生Split。

 

BulkLoad 適合初次數(shù)據(jù)導(dǎo)入,以及HBase與Hadoop為同一集群。BulkLoad 是使用 MapReduce 直接生成 HFile 格式文件后,Region Servers 再將 HFile 文件移動(dòng)到相應(yīng)的Region目錄下。

 

7 參考

BlockCache講解:https://blog.51cto.com/12445535/2363376?source=dra

LSM 原理:https://www.zhihu.com/question/19887265

HBase教程:http://c.biancheng.net/view/6499.html

 

 

責(zé)任編輯:武曉燕 來(lái)源: sowhat1412
相關(guān)推薦

2022-10-20 08:31:33

加鎖解鎖代碼

2021-11-08 15:12:48

排序算法面試

2020-06-28 07:39:44

Kafka分布式消息

2020-12-04 06:37:19

HTTPS原理安全

2021-11-29 07:47:56

RocketMQ分布式消息

2022-02-28 11:10:42

ZGCG1收集器

2020-09-23 11:23:25

推薦系統(tǒng)廣告

2020-11-16 10:50:27

KubernetesIngressLinux

2010-03-04 10:34:04

Android操作系統(tǒng)

2021-09-07 05:04:53

HTTPHTTP3.0面試

2021-05-07 17:11:19

負(fù)載均衡運(yùn)維服務(wù)

2022-01-05 14:30:44

容器Linux網(wǎng)絡(luò)

2021-07-04 22:27:42

存儲(chǔ)BookKeeper系統(tǒng)

2022-02-11 20:45:42

HTTPHTTPS協(xié)議

2020-09-12 16:45:49

Git

2024-08-26 08:44:54

2022-06-11 18:15:26

KubernetesDockerLinux

2022-06-13 11:05:35

RocketMQ消費(fèi)者線程

2023-04-11 08:35:22

RocketMQ云原生

2022-07-11 11:06:11

RocketMQ函數(shù).消費(fèi)端
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)