【圖文詳解】HBase 數據模型及其架構原理 HBase 簡介 HBase 數據模型 HBase 架構原理 HBase 數據模型操作 寫數據流程 讀數據流程 HBase 最佳實踐 小結 參考資料

HBase 簡介


https://hbase.apache.org/

HBase, Hadoop Database,是一個高可靠性、高性能、面向列存儲、可伸縮、 實時讀寫的分佈式開源 NoSQL 數據庫。主要用來存儲非結構化和半結構化的鬆散數據。

HBase 的設計思想,來源於 Fay Chang所撰寫的Google論文 “Bigtable:一個結構化數據的分佈式存儲系統”。

HBase 數據模型


邏輯上,HBase的數據模型同關係型數據庫很類似,數據存儲在一張表中,有行有列。但從HBase的底層物理存儲結構(K-V)來看,HBase更像是一個multi-dimensional map。

邏輯結構

物理結構

概念說明

Name Space

命名空間,類似於關係型數據庫的DatabBase概念,每個命名空間下有多個表。HBase有兩個自帶的命名空間,分別是hbase和default,hbase中存放的是HBase內置的表,default表是用戶默認使用的命名空間。

Region

類似於關係型數據庫的表概念。不同的是,HBase定義表時只需要聲明列族即可,不需要聲明具體的列。這意味着,往HBase寫入數據時,字段可以動態、按需指定。因此,和關係型數據庫相比,HBase能夠輕鬆應對字段變更的場景。

Row

HBase表中的每行數據都由一個RowKey和多個Column(列)組成,數據是按照RowKey的字典順序存儲的,並且查詢數據時只能根據RowKey進行檢索,所以RowKey的設計十分重要。


Column

HBase中的每個列都由 Column Family(列族) 和 Column Qualifier(列限定符)進行限定,例如info:name,info:age。建表時,只需指明列族,而列限定符無需預先定義。

Time Stamp

用於標識數據的不同版本(version),每條數據寫入時,如果不指定時間戳,系統會自動爲其加上該字段,其值爲寫入HBase的時間。

Cell

由  {rowkey, column Family,  column Qualifier, time Stamp}  唯一確定的單元。cell中的數據是沒有類型的,全部是字節數組形式存儲。



HBase 架構原理






Region Server

Region Server爲 Region的管理者,其實現類爲HRegionServer,主要作用如下:

對於數據的操作:get, put, delete;

對於Region的操作:splitRegion、compactRegion。

Master

Master是所有Region Server的管理者,其實現類爲HMaster,主要作用如下:

對於表的操作:create, delete, alter

對於RegionServer的操作:分配regions到每個RegionServer,監控每個RegionServer的狀態,負載均衡和故障轉移。

ZK

HBase通過Zookeeper來做Master的高可用、RegionServer的監控、元數據的入口以及集羣配置的維護等工作。

HDFS


HDFS爲HBase提供最終的底層數據存儲服務,同時爲HBase提供高可用的支持

StoreFile

保存實際數據的物理文件,StoreFile以 HFile 的形式存儲在 HDFS 上。每個Store會有一個或多個 StoreFile(HFile),數據在每個StoreFile中都是有序的。

MemStore

寫緩存,由於 HFile中的數據要求是有序的(思考:爲什麼要有序?),所以數據是先存儲在 MemStore 中,排好序後,等到刷寫時機纔會刷寫到HFile,每次刷寫都會形成一個新的HFile。

WAL

由於數據要經MemStore排序後才能刷寫到HFile,但把數據保存在內存中會有很高的概率導致數據丟失,爲了解決這個問題,數據會先寫在一個叫做 Write-Ahead logfile(HLog) 的文件中,然後再寫入MemStore中。在系統出現故障的時候,數據可以通過這個日誌文件重建。

HLog文件就是一個普通的Hadoop Sequence File,Sequence File 的Key是HLogKey對象,HLogKey中記錄了寫入數據的歸屬信息,除了table和 region名字外,同時還包括sequence number和timestamp,timestamp是” 寫入時間”,sequence number的起始值爲0,或者是最近一次存入文件系 統中sequence number。

HLog SequeceFile的Value是HBase的KeyValue對象,即對應HFile中的 KeyValue

HBase 數據模型操作

寫數據流程


寫流程:

1.Client先訪問zookeeper,獲取hbase:meta表位於哪個Region Server。

2.訪問對應的Region Server,獲取hbase:meta表,根據讀請求的namespace:table/rowkey,查詢出目標數據位於哪個Region Server中的哪個Region中。並將該table的region信息以及meta表的位置信息緩存在客戶端的meta cache,方便下次訪問。

3.與目標Region Server進行通訊;

4.將數據順序寫入(追加)到WAL;

5.將數據寫入對應的MemStore,數據會在MemStore進行排序;

6.向客戶端發送ack;

7.等達到MemStore的刷寫時機後,將數據刷寫到HFile;

MemStore Flush:

MemStore刷寫時機:

當某個memstroe的大小達到了hbase.hregion.memstore.flush.size(默認值128M),其所在region的所有memstore都會刷寫。

當memstore的大小達到了

hbase.hregion.memstore.flush.size(默認值128M) * hbase.hregion.memstore.block.multiplier(默認值4)

時, 會阻止繼續往該memstore寫數據。

當region server中memstore的總大小達到:

java_heapsize * hbase.regionserver.global.memstore.size(默認值0.4) * hbase.regionserver.global.memstore.size.upper.limit(默認值0.95)

時, region會按照其所有memstore的大小順序(由大到小)依次進行刷寫。直到region server中所有memstore的總大小減小到hbase.regionserver.global.memstore.size.lower.limit以下。

當region server中memstore的總大小達到

java_heapsize * hbase.regionserver.global.memstore.size(默認值0.4)

時,會阻止繼續往所有的memstore寫數據。

到達自動刷寫的時間,也會觸發memstore flush。

自動刷新的時間間隔由該屬性進行配置:

hbase.regionserver.optionalcacheflushinterval(默認1小時)

當WAL文件的數量超過hbase.regionserver.max.logs,region會按照時間順序依次進行刷寫,直到WAL文件數量減小到hbase.regionserver.max.log 以下(該屬性名已經廢棄,現無需手動設置,最大值爲32)

讀數據流程

讀流程:

1.Client先訪問zookeeper,獲取hbase:meta表位於哪個Region Server。

2.訪問對應的Region Server,獲取hbase:meta表,根據讀請求的namespace:table/rowkey,查詢出目標數據位於哪個Region Server中的哪個Region中, 並將該table的region信息以及meta表的位置信息緩存在客戶端的meta cache,方便下次訪問。

4.與目標Region Server進行通訊;

5.分別在Block Cache(讀緩存),MemStore和Store File(HFile)中查詢目標數據,並將查到的所有數據進行合併。此處所有數據是指同一條數據的不同版本(time stamp)或者不同的類型(Put/Delete)。

6.將從文件中查詢到的數據塊(Block,HFile數據存儲單元,默認大小爲64KB)緩存到Block Cache。

7.將合併後的最終結果返回給客戶端。


HBase 最佳實踐

1.預先分區

默認情況下,在創建 HBase 表的時候會自動創建一個 Region 分區,當導入數據的時候,所有的 HBase 客戶端都向這一個 Region 寫數據,直到這個 Region 足夠大了才進行切分。一種可以加快批量寫入速度的方法是通過預先創建一些空的 Regions,這樣當數據寫入 HBase 時,會按照 Region 分區情況,在集羣內做數據的負載均衡。

2.Rowkey優化

HBase 中 Rowkey 是按照字典序存儲,因此,設計 Rowkey 時,要充分利用排序特點,將經常一起讀取的數據存儲到一塊,將最近可能會被訪問的數據放在一塊。

此外,Rowkey 若是遞增的生成,建議不要使用正序直接寫入 Rowkey,而是採用 reverse 的方式反轉Rowkey,使得 Rowkey 大致均衡分佈,這樣設計有個好處是能將 RegionServer 的負載均衡,否則容易產生所有新數據都在一個 RegionServer 上堆積的現象,這一點還可以結合 table 的預切分一起設計。

3.減少列族數量

不要在一張表裏定義太多的 ColumnFamily。目前 Hbase 並不能很好的處理超過 2~3 個 ColumnFamily 的表。因爲某個 ColumnFamily 在 flush 的時候,它鄰近的 ColumnFamily 也會因關聯效應被觸發 flush,最終導致系統產生更多的 I/O。

4.緩存策略

創建表的時候,可以通過 HColumnDescriptor.setInMemory(true) 將表放到 RegionServer 的緩存中,保證在讀取的時候被 cache 命中。

5.設置存儲生命期

創建表的時候,可以通過HColumnDescriptor.setTimeToLive(int timeToLive)設置表中數據的存儲生命期,過期數據將自動被刪除。

6.硬盤配置

每臺 RegionServer 管理 10~1000 個 Regions,每個 Region 在 1~2G,則每臺 Server 最少要 10G,最大要1000*2G=2TB,考慮 3 備份,則要 6TB。方案一是用 3 塊 2TB 硬盤,二是用 12 塊 500G 硬盤,帶寬足夠時,後者能提供更大的吞吐率,更細粒度的冗餘備份,更快速的單盤故障恢復。

7.分配合適的內存給RegionServer服務

在不影響其他服務的情況下,越大越好。例如在 HBase 的 conf 目錄下的 hbase-env.sh 的最後添加export HBASE_REGIONSERVER_OPTS="-Xmx16000m$HBASE_REGIONSERVER_OPTS”

其中 16000m 爲分配給 RegionServer 的內存大小。

8.寫數據的備份數

備份數與讀性能成正比,與寫性能成反比,且備份數影響高可用性。有兩種配置方式,一種是將 hdfs-site.xml拷貝到 hbase 的 conf 目錄下,然後在其中添加或修改配置項 dfs.replication 的值爲要設置的備份數,這種修改對所有的 HBase 用戶表都生效,另外一種方式,是改寫 HBase 代碼,讓 HBase 支持針對列族設置備份數,在創建表時,設置列族備份數,默認爲 3,此種備份數只對設置的列族生效。

9.WAL(預寫日誌)

可設置開關,表示 HBase 在寫數據前用不用先寫日誌,默認是打開,關掉會提高性能,但是如果系統出現故障(負責插入的 RegionServer 掛掉),數據可能會丟失。配置 WAL 在調用 JavaAPI 寫入時,設置 Put 實例的WAL,調用 Put.setWriteToWAL(boolean)。

10. 批量寫

HBase 的 Put 支持單條插入,也支持批量插入,一般來說批量寫更快,節省來回的網絡開銷。在客戶端調用JavaAPI 時,先將批量的 Put 放入一個 Put 列表,然後調用 HTable 的 Put(Put 列表) 函數來批量寫。

11. 客戶端一次從服務器拉取的數量

通過配置一次拉去的較大的數據量可以減少客戶端獲取數據的時間,但是它會佔用客戶端內存。有三個地方可進行配置:

1)在 HBase 的 conf 配置文件中進行配置hbase.client.scanner.caching;

2)通過調用HTable.setScannerCaching(intscannerCaching)進行配置;

3)通過調用Scan.setCaching(intcaching)進行配置。三者的優先級越來越高。

12. RegionServer的請求處理I/O線程數

較少的 IO 線程適用於處理單次請求內存消耗較高的 Big Put 場景 (大容量單次 Put 或設置了較大 cache 的Scan,均屬於 Big Put) 或 ReigonServer 的內存比較緊張的場景。

較多的 IO 線程,適用於單次請求內存消耗低,TPS 要求 (每秒事務處理量 (TransactionPerSecond)) 非常高的場景。設置該值的時候,以監控內存爲主要參考。

在 hbase-site.xml 配置文件中配置項爲hbase.regionserver.handler.count。

13. Region的大小設置

配置項爲hbase.hregion.max.filesize,所屬配置文件爲hbase-site.xml.,默認大小256M

在當前 ReigonServer 上單個 Reigon 的最大存儲空間,單個 Region 超過該值時,這個 Region 會被自動 split成更小的 Region。小 Region 對 split 和 compaction 友好,因爲拆分 Region 或 compact 小 Region 裏的StoreFile 速度很快,內存佔用低。缺點是 split 和 compaction 會很頻繁,特別是數量較多的小 Region 不停地split, compaction,會導致集羣響應時間波動很大,Region 數量太多不僅給管理上帶來麻煩,甚至會引發一些Hbase 的 bug。一般 512M 以下的都算小 Region。大 Region 則不太適合經常 split 和 compaction,因爲做一次 compact 和 split 會產生較長時間的停頓,對應用的讀寫性能衝擊非常大。

此外,大 Region 意味着較大的 StoreFile,compaction 時對內存也是一個挑戰。如果你的應用場景中,某個時間點的訪問量較低,那麼在此時做 compact 和 split,既能順利完成 split 和 compaction,又能保證絕大多數時間平穩的讀寫性能。compaction 是無法避免的,split 可以從自動調整爲手動。只要通過將這個參數值調大到某個很難達到的值,比如 100G,就可以間接禁用自動 split(RegionServer 不會對未到達 100G 的 Region 做split)。再配合 RegionSplitter 這個工具,在需要 split 時,手動 split。手動 split 在靈活性和穩定性上比起自動split 要高很多,而且管理成本增加不多,比較推薦 online 實時系統使用。內存方面,小 Region 在設置memstore 的大小值上比較靈活,大 Region 則過大過小都不行,過大會導致 flush 時 app 的 IO wait 增高,過小則因 StoreFile 過多影響讀性能。

14.操作系統參數

Linux系統最大可打開文件數一般默認的參數值是1024,如果你不進行修改併發量上來的時候會出現“Too Many Open Files”的錯誤,導致整個HBase不可運行,你可以用ulimit -n 命令進行修改,或者修改/etc/security/limits.conf和/proc/sys/fs/file-max 的參數,具體如何修改可以去Google 關鍵字 “linux limits.conf ”

15.Jvm配置

修改 hbase-env.sh 文件中的配置參數,根據你的機器硬件和當前操作系統的JVM(32/64位)配置適當的參數。

HBASE_HEAPSIZE 4000  HBase使用的 JVM 堆的大小

HBASE_OPTS  "‐server ‐XX:+UseConcMarkSweepGC" JVM GC 選項

HBASE_MANAGES_ZKfalse  是否使用Zookeeper進行分佈式管理

16. 持久化

重啓操作系統後HBase中數據全無,你可以不做任何修改的情況下,創建一張表,寫一條數據進行,然後將機器重啓,重啓後你再進入HBase的shell中使用 list 命令查看當前所存在的表,一個都沒有了。是不是很杯具?沒有關係你可以在hbase/conf/hbase-default.xml中設置hbase.rootdir的值,來設置文件的保存位置指定一個文件夾,例如:file:///you/hbase-data/path,你建立的HBase中的表和數據就直接寫到了你的磁盤上,同樣你也可以指定你的分佈式文件系統HDFS的路徑例如:hdfs://NAMENODE_SERVER:PORT/HBASE_ROOTDIR,這樣就寫到了你的分佈式文件系統上了。

17. 緩衝區大小

hbase.client.write.buffer

這個參數可以設置寫入數據緩衝區的大小,當客戶端和服務器端傳輸數據,服務器爲了提高系統運行性能開闢一個寫的緩衝區來處理它,這個參數設置如果設置的大了,將會對系統的內存有一定的要求,直接影響系統的性能。

18. 掃描目錄表

hbase.master.meta.thread.rescanfrequency

定義多長時間HMaster對系統表 root 和 meta 掃描一次,這個參數可以設置的長一些,降低系統的能耗。

19. split/compaction時間間隔

hbase.regionserver.thread.splitcompactcheckfrequency

這個參數是表示多久去RegionServer服務器運行一次split/compaction的時間間隔,當然split之前會先進行一個compact操作.這個compact操作可能是minorcompact也可能是major compact.compact後,會從所有的Store下的所有StoreFile文件最大的那個取midkey.這個midkey可能並不處於全部數據的mid中.一個row-key的下面的數據可能會跨不同的HRegion。

20. 緩存在JVM堆中分配的百分比

hfile.block.cache.size

指定HFile/StoreFile 緩存在JVM堆中分配的百分比,默認值是0.2,意思就是20%,而如果你設置成0,就表示對該選項屏蔽。

21. ZooKeeper客戶端同時訪問的併發連接數

hbase.zookeeper.property.maxClientCnxns

這項配置的選項就是從zookeeper中來的,表示ZooKeeper客戶端同時訪問的併發連接數,ZooKeeper對於HBase來說就是一個入口這個參數的值可以適當放大些。

22. memstores佔用堆的大小參數配置

hbase.regionserver.global.memstore.upperLimit

在RegionServer中所有memstores佔用堆的大小參數配置,默認值是0.4,表示40%,如果設置爲0,就是對選項進行屏蔽。

23. Memstore中緩存寫入大小

hbase.hregion.memstore.flush.size

Memstore中緩存的內容超過配置的範圍後將會寫到磁盤上,例如:刪除操作是先寫入MemStore裏做個標記,指示那個value, column 或 family等下是要刪除的,HBase會定期對存儲文件做一個major compaction,在那時HBase會把MemStore刷入一個新的HFile存儲文件中。如果在一定時間範圍內沒有做major compaction,而Memstore中超出的範圍就寫入磁盤上了。

小結

HBase is a NoSQL database commonly referred to as the Hadoop Database, which is open-source and is based on Google's Big Table white paper. HBase runs on top of the Hadoop Distributed File System (HDFS), which allows it to be highly scalable, and it supports Hadoop's map-reduce programming model. HBase permits two types of access: random access of rows through their row keys and offline or batch access through map-reduce queries.

HBase 是一種 NoSQL 數據庫,通常稱爲 Hadoop 數據庫,它是開源的,基於 Google 的 Big Table 白皮書。 HBase 運行在 Hadoop 分佈式文件系統 (HDFS) 之上,這使其具有高度可擴展性,並且支持 Hadoop 的 map-reduce 編程模型。 HBase 允許兩種類型的訪問:通過行鍵隨機訪問行和通過 map-reduce 查詢離線或批量訪問。

參考資料

https://blog.csdn.net/weixin_40535323/article/details/81704854

https://www.jianshu.com/p/3832ae37fac4

https://hbase.apache.org/book.html#arch.overview

https://blog.csdn.net/whdxjbw/article/details/81101200

https://www.cloudduggu.com/hbase/data_model/

https://www.informit.com/articles/article.aspx?p=2253412

https://towardsdatascience.com/hbase-working-principle-a-part-of-hadoop-architecture-fbe0453a031b

https://developpaper.com/hbase-learning-1-basic-introduction/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章