您好,登錄后才能下訂單哦!
這篇文章主要講解了“Apache HBase內核知識點有哪些”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Apache HBase內核知識點有哪些”吧!
跳躍表
暫時先不說跳躍表是什么,在Java里面有一個Map叫:ConcurrentSkipListMap,通過對HBase的源碼跟蹤,我們發現這些地方使用了它:
簡單的列了幾個,但是觀察這幾個類所在的模塊就可以發現,HBase從客戶端,到請求處理,到元數據再到文件存儲貫穿HBase的整個生命周期中的各個重要環節,都能看到它的身影,Map那么多,為何偏偏HBase選擇了這個?接下來我們仔細分析下。
在算法概念里面有一種數據結構叫跳躍表,顧名思義,之所以叫跳躍表就是因為在查找的時候可以快速的跳過部分列表,用來提升查找效率,跳躍表的查找效率可以和二叉樹相比為O(log(N)),這個算法的實現在Java中的ConcurrentSkipListMap就是實現跳躍表的相關算法。
首先我們看一個有序的全量表:
假設我們要從中找出 可以發現需要比較的次數(比較次數不是循環次數)為<3,5,8>共計16次,可以看到對這樣一個有序鏈表進行查找比較的次數會非常多,那么有沒有辦法對這種查找做優化。當然是有的,對于這種查找耳熟能詳從數據結構的基礎課程開始大家就知道二叉樹,折半查找,值查找都屬于解決這類問題的方法,自然跳躍表也是解決這類問題的方法之一。
跳躍表的思路和如今大部分大數據組件像kylin對海量數據下的快速查找的解決思路非常相似,都是通過某種邏輯提前將部分數據做預處理,然后查找的時候進行快速匹配,典型的空間換時間,那么對于跳躍表來說,它的預處理的方式如下:
可以看到,跳躍表是按照層次構造的,最底層是一個全量有序鏈表,依次向上都是它的精簡版,而在上層鏈表中節點的后續下一步的節點是以隨機化的方式進行的,因此在上層鏈表中可以跳過部分列表,也叫跳躍表,特點如下:
鏈表層從上往下查找
跳躍表由很多層組成
每一層都是一個有序鏈表
最底層是全量有序鏈表
如果一個元素出現在上層的某個節點那么它一定會出現在下層的鏈表
每一個元素都有兩個指針,一個指向當前鏈表的下一個元素,一個指向下一層鏈表的相同節點
假設根據前面的圖表我們要查詢G這個字母,那么在上面的跳躍表中經過的路徑如下:
其中紅色代表查找所走過的路徑。
LSM樹
前面講到了跳躍表的原理,在HBase中較大規模的使用了跳躍表,就是為了增快其查找效率,除了跳躍表之外HBase還使用到了LSM樹,LSM樹本質上和B+相似,是一種存儲在磁盤上的數據的索引格式,但是差異點在于LSM對寫入非常高效,實現來說就是無論什么樣的寫入LSM都是當成一次順序寫入,這一點和HDFS的優點正好契合,HDFS不支持隨機寫,支持順序寫。LSM數據存儲在兩個地方,一個是磁盤上一個是內存中,內存中同樣使用的跳躍表,內存中是多個有序的文件。
HBase對LSM的應用采用了如上的結構方式,對于HBase具體的存儲文件的分析,在后面專門針對HBase的存儲部分進行深入的分析。
布隆過濾器
布隆過濾器解決的問題是,如何快速的發現一個元素是否存在于某個集合里面,最簡單的辦法就是在集合或者鏈表上查找一遍,但是考慮到在大數據場景下,數據量非常大,即便不考慮性能,也不見得會有足夠多的機器來加載對應的集合。所以需要一種新的思路去解決此類問題,那么布隆過濾器就是一種,它的思想為:
由一個長度為N的數組構成,每一個元素為0或者1,默認都為0
對集合的每個元素做K次哈希,到第i次的時候對N取一個模,會得到一個index
將數組中的array[index]變為1
上圖是長度為18,進行3次哈希得到的結果,那么在HBase中是如何利用布隆過濾器的呢,首先從操作來說,HBase的Get就經過布隆過濾器,同時HBase支持度對不同的列設置不同的布隆過濾器。
可以看到對HBase來講可以啟用或者禁用過濾器,對于不同的過濾器的實現分別在不同的類中,在查詢的時候分別根據不同的過濾器采用不同的實現類:
所以可以通過如上的代碼找到對應的過濾器實現,甚至可以新增自己的過濾器。
前面提到HBase的相關算法,現在我們講一下HBase的整個操作的讀寫流程。首先,擺出HBase的架構圖,如下所示:
從這個圖可以看到,HBase的一個寫操作,大的流程會經過三個地方:1. 客戶端,2. RegionServer 3. Memstore刷新到磁盤。也就是說對于HBase的一次寫入操作來講,數據落到Memstore就算寫入完成,那么必然需要考慮一個問題,那就是沒有落盤的數據,萬一機器發生故障,這部分數據如何保障不丟失。解析來我們逐步分解一下這三個部分。
客戶端:HBase的客戶端和服務器并不是單一的鏈接,而是在封裝完數據后,通過請求HMaster獲取該次寫入對應的RegionServer的地址,然后直接鏈接RegionServer,進行寫入操作,對于客戶端的數據封裝來講,HBase支持在客戶端設置本地緩存,也就是批量提交還是實時提交。因為HBase的hbase:meta表中記錄了RegionServer的信息,HBase的數據均衡是根據rowkey進行分配,因此客戶端會根據rowkey查找到對應的RegionServer,定義在Connection中:
而實現在:AsyncRegionLocator
RegionServer寫入:當客戶端拿到對應的RegionServer后,便和HMaster沒有關系了,開始了直接的數據傳輸,我們前面提到一個問題,那就是HBase如何防止數據丟失,畢竟HBase的寫入是到內存,一次請求就返回了,解決這個問題是通過WAL日志文件來解決的,任何一次寫入操作,首先寫入的是WAL,這類日志存儲格式和Kafka類似的順序追加,但是具有時效性,也就是當數據落盤成功,并且經過檢查無誤之后,這部分日志會清楚,以保障HBase具有一個較好的性能,當寫完日志文件后,再寫入Memstore。
那么在RegionServer的寫入階段會發生什么呢?首先我們知道,HBase是具有鎖的能力的,也就是行鎖能力,對于HBase來講,HBase使用行鎖保障對同一行的數據的更新要么都成功要么都失敗,所以在RegionServer階段,會經過以下步驟:
申請行鎖,用來保障本次寫入的事務性
更新LATEST_TIMESTAMP字段,HBase默認會保留歷史的所有版本,但是查詢過濾的時候始終只顯示最新的數據,然后進行寫入前提條件的檢查:
以上相關操作的代碼都在HRegion,RegionAsTable中,可以以此作為入口去查看,所以這里就不貼大部分的代碼了。
寫入WAL日志文件,在WALProvider中定義了兩個方法:
append用來對每一次的寫入操作進行日志追蹤,因為有事物機制,所以HBase會將一次操作中的所有的key value變成一條日志信息寫入日志文件,aync用來同步將該日志文件落盤到HDFS的文件系統,入場中間發生失敗,則立即回滾。
4. 寫入Memstore,釋放鎖,本次寫入成功。
所以可以看到對于HBase來講寫入通過日志文件再加Memstore進行配合,最后HBase自身再通過對數據落盤,通過這樣一系列的機制來保障了寫入的一套動作。
講完了HBase的寫入操作,再來看看HBase的讀取流程。
對于讀來講,客戶端的流程和寫一樣,HBase的數據不會經過Master進行轉發,客戶端通過Master查找到元信息,再根據元信息拿到meta表,找到對應的Region Sever直接取數據。對于讀操作來講,HBase內部歸納下來有兩種操作,一種是GET,一種是SCAN。GET為根據rowkey直接獲取一條記錄,而SCAN則是根據某個條件進行掃描,然后返回多條數據的過程。可以看到GET經過一系列的判斷,例如檢查是否有coprocessor hook后,直接返回了存儲數據集的List:
那么我們再看SCAN就不那么一樣了,可以看到,對于SCAN的操作來講并不是一次的返回所有數據,而是返回了一個Scanner,也就是說在HBase里面,對于Scan操作,將其分成了多個RPC操作,類似于數據的ResultSet,通過next來獲取下一行數據。
HBase文件格式
前面講了HBase的操作流程,現在我們看下HBase的存儲機制,首先HBase使用的HDFS存儲,也就是在文件系統方面沒有自身的文件管理系統,所以HBase僅僅需要設計的是文件格式,在HBase里面,最終的數據都是存儲在HFile里面,HFile的實現借鑒了BigTable的SSTable和Hadoop的TFile,一張圖先展示HFile的邏輯結構:
可以看到HFie主要由四個部分構成:
Scanned block section: 顧名思義,表示順序掃描HFile時所有的數據塊將會被讀取,包括Leaf Index Block和Bloom Block。
Non-scanned block section: 表示在HFile順序掃描的時候數據不會被讀取,主要包括Meta Block和* Intermediate Level Data Index Blocks兩部分。
Load-on-open-section: 這部分數據在HBase的region server啟動時,需要加載到內存中。包括FileInfo、Bloom filter block、data block index和meta block index。
Trailer: 這部分主要記錄了HFile的基本信息、各個部分的偏移值和尋址信息。
對于一個HFile文件來講,最終落盤到磁盤上的時候會將一個大的HFile拆分成多個小文件,每一個叫做block塊,和HDFS的塊相似,每一個都可以自己重新設定大小,在HBase里面默認為64KB,對于較大的塊,在SCAN的時候可以在連續的地址上讀取數據,因此對于順序SCAN的查詢會非常高效,對于小塊來講則更有利于隨機的查詢,所以塊大小的設置,也是HBase的調參的一個挑戰,相關的定義在源碼里面使用的HFileBlock類中,HFileBlock的結構如下所示:
每一個block塊支持兩種類型,一種是支持Checksum的,一種是不支持Checksum的,通過參數usesHBaseChecksum在創建block的時候進行設置:
HFileBlock主要包含兩個部分,一個是Header一個是Data,如下圖所示:
(HFileBlock結構,來自網絡)
BlockHeader主要存儲block元數據,BlockData用來存儲具體數據。前面提到一個大的HFile會被切分成多個小的block,每一個block的header都相同,但是data不相同,主要是通過BlockType字段來進行區分,也就是HFile把文件按照不同使用類型,分成多個小的block文件,具體定義在BlockType中,定義了支持的Type類型:
下面我們仔細分解一下HBase的Data部分的存儲,HBase是一個K-V的數據庫,并且每條記錄都會默認保留,通過時間戳進行篩選,所以HBase的K-V的格式在磁盤的邏輯架構如下所示:
每個KeyValue都由4個部分構成,而Key又是一個復雜的結構,首先是rowkey的長度,接著是rowkey,然后是ColumnFamily的長度,再是ColumnFamily,之后是ColumnQualifier,最后是時間戳和KeyType(keytype有四種類型,分別是Put、Delete、 DeleteColumn和DeleteFamily),而value相對簡單,是一串純粹的二進制數據。
最開始的時候我們介紹了布隆過濾器,布隆過濾器會根據條件減少和跳過部分文件,以增加查詢速度:
每一個HFile有自己的布隆過濾器的數組,但是我們也會發現,這樣的一個數組,如果HBase的塊數足夠多,那么這個數組會更加的長,也就意味著資源消耗會更多,為了解決這個問題,在HFile里面又定義了布隆過濾器的塊,用來檢索對應的Key需要使用哪個數組:
一次get請求進來,首先會根據key在所有的索引條目中進行二分查找,查找到對應的Bloom Index Entry,就可以定位到該key對應的位數組,加載到內存進行過濾判斷。
聊完了HBase的流程和存儲格式,現在我們來看一下HBase的RegionServer,RegionServer是HBase響應用戶讀寫操作的服務器,內部結構如下所示:
一個RegionServer由一個HLog,一個BlockCache和多個Region組成,HLog保障數據寫入的可靠性,BlockCache緩存查詢的熱點數據提升效率,每一個Region是HBase中的數據表的一個分片,一個RegionServer會承擔多個Region的讀寫,而每一個Region又由多個store組成。store中存儲著列簇的數據。例如一個表包含兩個列簇的話,這個表的所有Region都會包含兩個Store,每個Store又包含Mem和Hfile兩部分,寫入的時候先寫入Mem,根據條件再落盤成Hfile。
RegionServer管理的HLog的文件格式如下所示:
HLog的日志文件存放在HDFS中,hbase集群默認會在hdfs上創建hbase文件夾,在該文件夾下有一個WAL目錄,其中存放著所有相關的HLog,HLog并不會永久存在,在整個HBase總HLog會經歷如下過程:
HLog構建: 任何寫入操作都會先記錄到HLog,因此在發生寫入操作的時候會先構建HLog。
HLog滾動: 因為HLog會不斷追加,所以整個文件會越來越大,因此需要支持滾動日志文件存儲,所以HBase后臺每間隔一段時間(默認一小時)會產生一個新的HLog文件,歷史HLog標記為歷史文件。
HLog失效: 一旦數據進入到磁盤,形成HFile后,HLog中的數據就沒有存在必要了,因為HFile存儲在HDFS中,HDFS文件系統保障了其可靠性,因此當該HLog中的數據都落地成磁盤后,該HLog會變為失效狀態,對應的操作是將該文件從WAL移動到oldWAl目錄,此時文件依舊存在,并未進行刪除。
HLog刪除: hbase有一個后臺進程,默認每間隔一分鐘會對失效日志文件進行判斷,如果沒有任何引用操作,那么此時的文件會被徹底的從物理刪除。
對于RegionServer來講,每一個RegionServer都是一個獨立的讀寫請求服務,因此HBase可以水平增加多個RegionServer來達到水平擴展的效果,但是多個RegionServer之間并不存在信息共享,也就是如果一個海量任務計算失敗的時候,客戶端重試后,鏈接新的RegionServer后,整個計算會重新開始。
雖然HBase目前使用非常廣泛,并且默認情況下,只要機器配置到位,不需要特別多的操作,HBase就可以滿足大部分情況下的海量數據處理,再配合第三方工具像phoenix,可以直接利用HBase構建一套OLAP系統,但是我們還是要認識到HBase的客觀影響,知道其對應的細節差異,大概來說如果我們使用HBase,有以下點需要關心一下:
因為HBase在RegionServer對寫入的檢查機制,會導致客戶端在符合條件的情況下出現重試的情況,所以對于較為頻繁的寫入操作,或者較大數據量的寫入操作,推薦使用直接產生HFlie然后load到HBase中的方式,不建議直接使用HBase的自身的Put API。
從使用來講如果業務場景導致HBase中存儲的列簇對應的數據量差異巨大,那么不建議創建過多的列簇,因為HBase的存儲機制會導致不同列簇的數據存儲在同一個HBase的HFile中,但是split機制在數據量增加較大的情況下,會發生拆分,則會導致小數據量的列簇被頻繁的split,反而降低了查詢性能。
RegionServer是相互獨立的,所以如果想要讓集群更加的穩定高效,例如如果想實現RegionServer集群,達到信息共享,任務增量計算,需要自己修改RegionServer的代碼。
對于HBase來講,很多場景下,像如果Region正在Split,或者Mem正在Dump,則無法進行對應的操作,此時錯誤信息會被以異常的形式返回到客戶端,再由客戶端進行重試,因此在使用過程中,需要結合我們的應用場景,考慮如何設置類似于buffer大小的參數,以盡可能少的降低因為內部操作引起的客戶端重試,特別是在使用類似opentsdb的這類集成hhbase的數據的情況下。
感謝各位的閱讀,以上就是“Apache HBase內核知識點有哪些”的內容了,經過本文的學習后,相信大家對Apache HBase內核知識點有哪些這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。