前言:老劉目前為明年校招而努力,寫文章主要是想用大白話把自己複習的大資料知識點詳細解釋出來,拒絕資料上的生搬硬套,做到有自己的理解!
01 HBase知識點
第6點:HRegionServer架構
為什麼要了解HRegionServer的架構呢?因為HBase叢集中資料的儲存和HRegionServer有著非常大的關係,只有搞清楚了它的架構,才能理清楚資料儲存的邏輯。
那就讓老劉好好介紹下HRegionServer架構。
StoreFile
在HRegionServer架構圖中,StoreFile是儲存實際資料的物理檔案,StoreFile是以HFile的形式儲存在HDFS上,每個Store會有一個或多個StoreFile,並且資料在每個StoreFile中都是有序的。為什麼是有序的,會在MEMStore中介紹。
對於HFile是什麼,老劉目前只能理解為它是StoreFile存在HDFS上的儲存格式,也就是說StoreFile是以HFile這種形式儲存在HDFS上。
MemStore
它是寫快取的意思。由於HFile是要求資料是有序的,要按照儲存在HDFS上的資料需要按照rowkey排序,所以資料先儲存在MemStore中,排好序後,達到閾值後才會flush到StoreFile中,每次flush生成一個新的StoreFIle。
那MemStore是如何將資料排序的呢?
很多機構的教學資料都沒講,老劉查了很多資料後,老劉只有一個相對較淺的理解,實現MemStore模型的資料結構是SkipList跳錶,跳錶它可以實現高效的查詢、插入、刪除操作。因為跳錶本質上是由有序連結串列構成的,很多KV資料庫都會使用跳錶實現有序資料集合。所以呢,資料傳入MemStore後,會利用跳錶實現這些資料的有序。
WAL
WAL,全稱是Write Ahead Log,預先寫日誌的意思。由於資料要經MemStore排序後才能刷寫到HFile,但把資料儲存在記憶體中會有很高的概率導致資料丟失的,所以為了解決這個問題,資料會先寫在一個叫做Write Ahead Log的檔案中,然後再寫入MemStore中。所以當系統出現故障的時候,資料就可以通過這個日誌檔案重建,避免資料丟失。
BlockCache
它是讀快取的意思。每次查詢出來的資料會先快取在BlockCache中,方便下次查詢資料。
第7點:HBase讀資料流程
首先要說的是,在HBase中只有一張meta表(後設資料表),此表只有一個region表,該region資料儲存在一個HRegionServer上。
還記得HBase的第一篇文章說的ZooKeeper的作用嗎,ZooKeeper裡面儲存了HBase的後設資料meta。再想想我們要讀取資料,是不是相當於去學校訪問一個老師,是不是要先在校門口登記,搞清楚這個老師在學校哪個部門、哪個辦公室之類的。
所以呢,HBase讀資料流程如下:
1、HBase讀取資料首先要與zk進行連線,從zk找到meta表的region位置,就是查詢meta表儲存在哪個HRegionServer,得到訊息後,客戶端就會立馬與這個HRegionServer建立連線,然後讀取meta表中的資料,這個meta表中的資訊有:HBase叢集有哪些表、每個表有哪些Region、都儲存在哪些RegionServer上以及儲存了所有使用者表的Region資訊。
2、我們根據要查詢的namespace(名稱空間,相當於關係型資料庫的資料庫名稱)、表名和rowkey資訊。找到寫入資料對應的Region資訊。
3、然後找到這個Region對應的RegionServer,然後傳送請求。
4、現在就可以查詢並定位到對應的Region了。
5、我們會先從MemStore中查詢資料,如果沒有,就會再從BlockCache上讀取,如果BlockCache中也沒有找到,那就會從最後的StoreFile中讀取,從StoreFile中讀取到資料之後,並不是直接把結果資料返回到客戶端,而是把資料先寫入到BlockCache中,目的是為了加快後續的查詢;然後在返回結果給客戶端。
第8點:HBase寫資料流程
1、客戶端首先會從zk找到meta表的region位置,然後讀到meta表中的資料,meta表中儲存了使用者表的region資訊。
2、根據我們根據要寫入資料的namespace(名稱空間,相當於關係型資料庫的資料庫名稱)、表名和rowkey資訊。找到寫入資料對應的Region資訊。
3、然後找到這個Region對應的RegionServer,然後傳送請求。
4、現在就可以把資料順序寫入(追加)到WAL。
5、將資料寫入對應的MemStore,資料會在MemStore進行排序。
6、達到MemStore的刷寫時機後,將資料刷寫到StoreHFile中。
但是大家好好想想,如果資料不停的寫入,是不是會產生很多很多StoreFile?
在HBase叢集中,針對產生的很多很多StoreFile,它會把它們合併為一個大的StoreFile(這是一個小合併),最終所有的StoreFile會進行一個大合併。但是在資料不斷寫入過程中,Region中的資料會越來越大,此時Region就會進行拆分(一分為二),拆分過程比較耗效能,就有了預分割槽。老劉大致說了下HBase中為什麼會有flush和compact機制、Region拆分合並以及預分割槽,下面就詳細講講這些知識點。
第9點:HBase中的flush、compact機制
Flush機制
資料要刷寫到磁碟,它是有很多刷寫時機的,並不是想刷寫就刷寫的。
第一個是達到Memtore級別的限制,當Region中任意一個MemStore的大小達到了上限,預設是128M,就會觸發MemStore重新整理。這個上限的設定如下:
<property> <name>hbase.hregion.memstore.flush.size</name> <value>134217728</value> </property>
第二個是達到Region級別的限制,當Region中所有的MemStore的大小總和達到了上限,預設是2*128M=256M,會觸發MemStore重新整理。這個上限的設定如下:
<property> <name>hbase.hregion.memstore.flush.size</name> <value>134217728</value> </property> <property> <name>hbase.hregion.memstore.block.multiplier</name> <value>2</value> </property>
第三個是達到RegionServer級別限制,當一個RegionServer中所有MemStore的大小總和超過低水位閾值,RegionServer開始強制Flush;先Flush MemStore最大的Region,再執行次大的,依次執行;
如果寫入速度大於flush寫出的速度,最後導致總MemStore大小超過高水位閾值(預設為JVM記憶體的40%),此時RegionServer會阻塞更新並強制執行flush,直到總MemStore大小低於低水位閾值。這些閾值的設定如下:
<property> <name>hbase.regionserver.global.memstore.size.lower.limit</name> <value>0.95</value> </property> <property> <name>hbase.regionserver.global.memstore.size</name> <value>0.4</value> </property>
第四個是當WAL檔案的數量超過hbase.regionserver.max.logs,region會按照時間順序依次進行刷寫,直到WAL檔案數量減小到hbase.regionserver.max.log以下(該屬性名已經廢棄,現無需手動設定,最大值為32)。
第五個是定期重新整理MemStore,預設週期為1小時,確保MemStroe不會長時間沒有持久化。為避免所有的MemStore在同一時間都進行flush導致的問題,定期的flush操作會有20000左右的隨機延時。
Compact合併機制
為什麼有Compact合併機制?
hbase為了防止小檔案過多,以保證查詢效率,hbase需要在必要的時候將這些小的store file合併成相對較大的store file,這個過程就稱之為compaction。
在hbase中主要存在兩種型別的compaction合併:
minor compaction 小合併
它會將Store中多個HFile合併為一個HFile。在這個過程中它會選取一些小的、相鄰的StoreFile將他們合併成一個更大的StoreFile。
對於超過了TTL(生存時間)的資料、更新的資料、刪除的資料僅僅只是做了標記。並沒有進行物理刪除,進行一次Minor Compaction的結果是產生數量上更少並且記憶體上更大的StoreFile。這種合併的觸發頻率很高。
minor compaction觸發條件由以下幾個引數共同決定:
<!--表示至少需要三個滿足條件的store file時,minor compaction才會啟動--> <property> <name>hbase.hstore.compactionThreshold</name> <value>3</value> </property> <!--表示一次minor compaction中最多選取10個store file--> <property> <name>hbase.hstore.compaction.max</name> <value>10</value> </property> <!--預設值為128m, 表示檔案大小小於該值的store file 一定會加入到minor compaction的store file中 --> <property> <name>hbase.hstore.compaction.min.size</name> <value>134217728</value> </property> <!--預設值為LONG.MAX_VALUE, 表示檔案大小大於該值的store file 一定會被minor compaction排除--> <property> <name>hbase.hstore.compaction.max.size</name> <value>9223372036854775807</value> </property>
major compaction 大合併
將所有的StoreFile合併成一個StoreFile,在這個過程中還會清理三類無意義資料:被刪除的資料、TTL過期資料、版本號超過設定版本號的資料。它的合併頻率比較低,預設7天執行一次,並且效能的消耗是非常大的,一般建議生產關閉,在應用空閒時間手動觸發。一般可以是手動控制進行合併,這樣可以防止出現在業務高峰期。
major compaction觸發時間條件(7天)
<!--預設值為7天進行一次大合併,--> <property> <name>hbase.hregion.majorcompaction</name> <value>604800000</value> </property>
手動觸發
#使用major_compact命令
major_compact tableName
第10點:Region拆分
region中儲存的是大量的rowkey資料,當region中的資料條數過多的時候,直接影響查詢效率。當region過大的時候。hbase會拆分region,這也是Hbase的一個優點。
HBase的region split策略一共有以下幾種,先說說3種。
1、ConstantSizeRegionSplitPolicy
它是0.94版本前預設切分策略。
當region的大小大於某個閾值(hbase.hregion.max.filesize=10G)之後就會觸發切分,一個region會等分為2個region。但是這種切分策略卻有相當大的弊端:切分策略對於大表和小表沒有明顯的區分。閾值設定較大對大表比較友好,但是小表就有可能不會觸發分裂,極端情況下可能就1個,這對業務來說並不是什麼好事。如果設定較小則對小表友好,但一個大表就會在整個叢集產生大量的region,這對於叢集的管理、資源使用、failover來說都不是一件好事。
2、IncreasingToUpperBoundRegionSplitPolicy
它是0.94版本~2.0版本預設切分策略。
切分策略稍微有點複雜,總體看和ConstantSizeRegionSplitPolicy思路相同,一個region大小大於設定閾值就會觸發切分。但是這個閾值並不像ConstantSizeRegionSplitPolicy是一個固定的值,而是會在一定條件下不斷調整,調整規則和region所屬表在當前regionserver上的region個數有關係。
3、SteppingSplitPolicy
它是2.0版本預設切分策略
這種切分策略的切分閾值又發生了變化,就是一般剛設計出來都會存在一些不合理的地方,隨著慢慢的發展,設計師們逐漸完善。
相比之前的IncreasingToUpperBoundRegionSplitPolicy,它會簡單一些,依然和待分裂region所屬表在當前regionserver上的region個數有關係,如果region個數等於1,切分閾值為flush size * 2,否則為MaxRegionFileSize。這種切分策略對於大叢集中的大表、小表會比 IncreasingToUpperBoundRegionSplitPolicy 更加友好,小表不會再產生大量的小region,而是適可而止。
還有幾個不講了,老劉快記不住了。
第11點:Region合併
什麼時候需要Region合併?
比如有一張表在拆分後,一分為二,但是在使用過程中,對這兩個表進行了資料的刪除,資料量變小了,為了方便管理之類的,可以把他們合併。
又比如刪除了大量的資料 ,這個時候每個Region都變得很小 ,儲存多個Region就浪費了 ,這個時候可以把Region合併起來,進而可以減少一些Region伺服器節點 。
總之,Region合併不是為了效能,而是為了方便維護管理。
第12點:HBase表的預分割槽
當一個table表剛被建立的時候,HBase會預設的分配一個region給這個table。這就相當於說,在這個時候,所有的讀寫請求都會訪問到同一個regionServer的同一個region中,這個時候就達不到負載均衡的效果了,因為叢集中的其他regionServer就可能會處於比較空閒的狀態。出現了一人幹活,其他人看戲的現象。
解決這個問題可以用預分割槽,在建立table表的時候就配置好,生成多個region。
預分割槽原理
每一個region都維護著startRow與endRowKey,如果加入的資料符合某個region維護的rowKey範圍,就會把該資料交給這個region維護。如何手動指定預分割槽
方式一:
create 'person','info1','info2',SPLITS => ['1000','2000','3000','4000']
就會有如下這種效果:
方式二:
把分割槽規則建立於檔案中
cd /kkb/install
vim split.txt
在裡面新增這樣的內容:
aaa
bbb
ccc
ddd
在執行這樣的命令:
create 'student','info',SPLITS_FILE => '/kkb/install/split.txt'
就會得到這樣的效果:
02 總結
好啦,大資料HBase的第二部分知識點就總結的差不多了,內容比較多,大家需要仔細理解,爭取做到用自己的話把這些知識點講述出來。
最後,如果覺得有哪裡寫的不好或者有錯誤的地方,可以聯絡公眾號:努力的老劉,進行交流哦!希望能夠對大資料開發感興趣的同學有幫助,希望能夠得到同學們的指導。