可能是最易懂的Hbase架構原理解析


小史是一個非科班的程序員,雖然學的是電子專業,但是通過自己的努力成功通過了面試,現在要開始迎接新生活了。

今天,小史的姐姐和呂老師一起過來看小史,一進屋,就有一股難聞的氣味。

可不,小史姐姐走進衛生間,發現地下一個盆子里全是沒洗的襪子。

小史:當然不是,盆里的襪子滿了,就先放到這個桶里,然后再繼續裝,等到桶里的襪子滿了,然后才放到洗衣機里一次洗完,這樣不僅效率高,而且節省水電費。

小史洋洋得意地介紹起自己洗襪子的流程。

小史一聽就有點不高興,全世界都黑程序員,沒想到自己還沒變成程序員就被自家姐姐黑了。

說完就進自己房間,把姐姐和呂老師晾在外面。小史姐姐也意識到不該拿程序員開玩笑,但現在也不知道該怎么辦,就看着呂老師。

呂老師走進小史的房間。

HBase是啥

小史:別吹了,構建在 HDFS 上除了能存儲海量數據之外,缺點一大堆,上次你給我介紹的 HDFS 缺點我可沒忘啊,不支持小文件,不支持並發寫,不支持文件隨機修改,查詢效率也低。

小史仔細回憶起 HDFS 來:

呂老師:HDFS 確實有很多缺點,但是 HBase 卻是一個支持***別高並發寫入,支持實時查詢,適合存儲稀疏數據的分布式數據庫系統。

呂老師:HBase 主要用於大數據領域,在這方面,確實比 MySQL 要厲害得多啊,它和 MySQL 的存儲方式就完全不一樣。MySQL 是行式存儲,HBase 是列式存儲。

列式存儲

呂老師:沒錯,這就是行式存儲系統存儲稀疏數據的問題,我們再來看看列式存儲如何解決這個問題,它的存儲結構是這樣的:

小史:這個我看懂了,相當於把每一行的每一列拆開,然后通過 Rowkey 關聯起來,Rowkey 相同的這些數據其實就是原來的一行。

呂老師:你這里只說到了一個好處,由於把一行數據變成了這樣的 key-value 的形式。

所以 HBase 可以存儲上百萬列,又由於 HBase 基於 HDFS 來存儲,所以 HBase 可以存儲上億行,是一個真正的海量數據庫。

呂老師:這就是 HBase 的威力呀,還不只如此,其實很多時候,我們做 Select 查詢的時候,只關注某幾列,比如我現在只關心大家的工資,傳統的按行存儲,要選出所有人的工資是怎么辦的呢?

小史:哦,我大概明白了,原來是這樣,所以 HBase 的查詢效率也很高,但是我有個問題啊,如果我就要查我的所有信息,這是一行數據,HBase 查詢起來是不是反而更慢了呢?

列簇

呂老師:列簇,顧名思義,就是把一些列放在一起咯,在 HBase 中,會把列簇中的列存儲在一起,比如我們把和工作相關的 Salary 和 Job 都放在 Work 這個列簇下。

那么大概是這樣的:

小史:哦,我明白了,這樣的話,一個列簇中的列會被一次就拿出來,如果我要查所有列的信息的話,把所有信息都放在一個列簇就好了。

注意:HBase 中,其實所有列都是在列簇中,定義表的時候就需要指定列簇。生產環境由於性能考慮和數據均衡考慮,一般只會用一個列簇,最多兩個列簇。

Rowkey 設計

注:當然,有些中間件把 SQL 翻譯成 HBase 的查詢規則,從而支持了 SQL 查 HBase,不在本文討論范圍內。

小史:啊?這和我想象的不一樣啊,如果我想查詢工資比 20w 多的記錄,在 MySQL 中,只要用一條很簡單的 SQL 就行啊,這在 HBase 中怎么查呢?

呂老師:在 HBase 中,你需要把要查詢的字段巧妙地設置在 Rowkey 中,一個 Rowkey 你可以理解為一個字符串,而 HBase 就是根據 Rowkey 來建立索引的。

不熟悉 B+ 樹的同學可以看這篇文章。HBase 的 HFile 底層也是一樣的原理。

呂老師:假設員工工資 9999w 封頂,查詢的時候可能根據員工工資查詢,也可能根據名字查詢一個特定的員工,那么 Rowkey 就可以這樣設計:

注意:以上 Rowkey 是簡化版設計,只是為了講清楚范圍查詢。實際使用中由於 Rowkey 需要考慮散列性,所以可能不會這么用。后文會具體探討散列性。

呂老師:HBase 提供了三種查詢方式:

  • 全表掃描,Scan。
  • 根據一個 Rowkey 進行查詢。
  • 根據 Rowkey 過濾的范圍查詢。

比如你要查工資不少於 20w 的記錄,就可以用范圍查詢,查出從 startRow=0020 到 stopRow=9999 的所有記錄,這是 HBase 直接支持的一種查詢方式哦。

呂老師:這里要注意幾點,首先,Rowkey 是按照字符串字典序來組織成 B+ 樹的,所以數字的話需要補齊,不然的話會出現 123w 小於 20w 的情況,但是補齊的話,你就會發現 020w 小於 123w。

小史:哦,明白了,這都很好理解,因為 Rowkey 是字符串形式,所以肯定是按照字符串順序排序咯。

而且 Rowkey 有點類似於 MySQL 中的主鍵吧,所以保證其唯一性也是可以理解的。

還有就是因為每個 key-value 都包含 Rowkey,所以 Rowkey 越短,越能節省存儲空間。

注意:如果 Rowkey 復雜且查詢條件復雜,HBase 還針對 Rowkey 提供了自定義 Filter,所以只要數據在 Rowkey 中有體現,能解析,就能根據自己的條件進行查詢。

小史:但是呂老師,我有一個問題啊,之前說過 HDFS 不適合存儲小文件,而 HBase 中的一條記錄只有一點點數據,記錄條數卻很多,屬於海量小文件,存在 HDFS 中不是內存爆炸了嗎?

LSM 三層存儲模型

小史:哦,這就像把盆里的襪子放到桶里一樣。但是呂老師,如果數據量大的話,時間一長,就會有很多次刷寫,不就形成了很多個小文件嗎?這豈不又是海量小文件了?

不記得 HDFS 原理的同學可以溫習一下:

呂老師:對了,HBase 也是使用同樣的思想,其實這就是 WAL 預寫日志的思想,HBase 也會將數據的操作先寫日志,然后存到內存,哪天機器掛了,內存丟了,還能從 WAL 日志中將數據恢復。

數據修改

小史:不過呂老師,我還有問題啊,我記得 HDFS 是不能隨機修改文件的,只能追加,那么 HBase 里的數據是不是寫了之后就不能改也不能刪除呢?

呂老師:刪除同樣是追加一條版本***的記錄,只不過標記這個數據被刪除而已,查詢的時候,看到版本***的記錄是數據刪除,就知道這個數據被刪了。

呂老師:哈,小史,你思考得非常深入,還記得 LSM 的第三層嗎,HBase 會在合並的時候,將這些用不到的記錄刪除掉,節省存儲空間。

呂老師:不全對,其實 HBase 把合並分為兩種:

    • 小合並 Minor Compact,這種方式只會將少數文件進行簡單合並,不會進行數據的清理。
    • 大合並 Major Compact,這種方式會將大部分文件進行合並,並且清理數據。

呂老師:基本正確,但是你要知道,如果數據量大,這個過程是非常耗性能的,一般在生產環境都禁止大合並,否則在正常服務的時候突然來個大合並,整個集群可能資源被耗光,沒法正常服務。

HBase 架構

小史:HBase 的架構似乎也是 master-slave 架構,和 HDFS 有點像,HMaster 是用來管理集群,HRegionServer 是真正存儲數據的地方吧?

呂老師:啊,這塊不太對,HBase 在數據查詢和寫入的時候,其實並不是像 HDFS 那樣詢問 HMaster。

在 HBase 中,每一張表都會有元信息,這些信息也是被存儲為 HBase 表,稱為元信息表,也叫 Meta 表,這是一種系統表。

小史:但是這又有個問題,既然 Meta 表也是存儲在 HBase 上,那么 HBase 又如何知道 Meta 表存在哪個 HRegionServer 上呢?這豈不是一個雞生蛋蛋生雞的問題?

呂老師:小史啊,我說 Meta 表是 HBase 表,是指 Meta 表也是用 Rowkey 和 Value 的鍵值存儲,但是我並沒有說 Meta 表在 HBase 上啊。

其實 Meta 表不是存儲在 HRegionServer 上,而是存儲在那個分布式協調服務 Zookeeper 上面。

小史:哦,原來如此,所以 Meta 表其實是在一個固定地方讀取,然后根據 Meta 表就知道數據在哪個 HRegionServer 上。但是 Zookeeper 又是啥呢?

呂老師:其實 HMaster 的任務相對不繁重,但是卻比較重要,它主要是通過調整和管理 Region 分布來實現 HRegionServer 的負載均衡。

HRegionServer 架構

呂老師:其實 Region 是 HBase 在 Rowkey 上的切分,每個 Region 都可以通過 StartKey 和 EndKey 來確定 Rowkey 的范圍,一個 HRegionServer 上可能會有多個 Region。

小史:所以說數據是根據 Rowkey 和一定的哈希規則,分散到不同的 Region 上面,而 Region 又是屬於某一個 HRegionServer 上的,這個關系沒錯吧?

呂老師:沒錯,通過這里其實可以得出 Rowkey 設計的另一個原則,就是散列性。

Rowkey 的頭幾個字母,***不要是一樣的,不然會分布在同一個 HRegionServer 上面,導致這個 HRegionServer 的負載非常高,累死累活,其他 HRegionServer 卻沒事干。

一般可以根據一定規則算一個數據的摘要,比如 MD5,把 MD5 的頭幾位拼在 Rowkey 的前面。

呂老師:哈哈,名詞沒講過,原理可都是講過的喲。比如這個 Store,我們之前說過,一個列簇中的列是存儲在一起的,對應到這里,一個列簇中的數據就是存到一個 Store 中。

呂老師:沒錯,這里 StoreFile 只是一個名字,它是以 HFile 的格式存儲在 HDFS 上,HFile 是一個存儲格式,在新版本的 HFile 存儲格式中,它就是一個類似 B+ 樹的索引形式。

讀取和寫入流程

①HBase Client 要寫輸入了,先從 Zookeeper 中拿到 Meta 表信息,根據數據的 Rowkey 找到應該往哪個 RegionServer 寫。

②然后 HBase 會將數據寫入對應 RegionServer 的內存 MemStore 中,同時記錄操作日志 WAL。

③當 MemStore 超過一定閾值,就會將內存 MemStore 中的數據刷寫到硬盤上,形成 StoreFile。

④在觸發了一定條件的時候,小的 StoreFile 會進行合並,變成大的 StoreFile,有利於 HDFS 存儲。

呂老師:當大量 Rowkey 相近的數據都被分配到一個 Region 中,導致這個 Region 數據過大的時候,Region 會進行拆分,HMaster 會對拆分后的 Region 重新分配 RegionServer,這是 HMaster 的負載均衡策略。

①HBase Client 要讀數據了,先從 Zookeeper 中拿到 Meta 表信息,根據要查的 Rowkey 找到對應的數據在哪些 RegionServer 上。

②分別在這些 RegionServer 上根據列簇進行 StoreFile 和 MemStore 的查找,得到很多 key-value 結構的數據。

③根據數據的版本找到***數據進行返回。

OLTP 和 OLAP

呂老師:OLTP 應用叫聯機事務處理應用,就是類似銀行轉賬等業務的,這類應用對事務要求比較高。

而 OLAP 應用叫聯機分析處理應用,比如推薦系統,是在收集了大量用戶行為后進行分析,再得出結論的應用,主要側重分析,對事務要求非常低。

總結

小史把這次學習到的 HBase 的知識記了下來:

HBase 是列式存儲,和 MySQL 的行式存儲不一樣。

HBase 中有列簇概念,同一個列簇下的列存儲在一起,在 Region 的一個 StoreFile 中。

HBase 是按照 Rowkey 進行查找,要查詢的字段要想辦法放到 Rowkey 中。

HBase 內部使用 LSM 三層模型進行存儲,數據先寫到內存的 MemStore 中,內存達到一定閾值再刷寫到硬盤 StoreFile 中,再滿足一定條件時,小的 StoreFile 會合並為大的 StoreFile。

HBase 適合 OLAP 類的應用。

學完 HBase,記完筆記,小史開開心心地洗襪子去了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM