1. 程式人生 > 實用技巧 >大資料學習(17)—— HBase表設計

大資料學習(17)—— HBase表設計

為啥要把表設計拿出來獨立成章?因為我覺得像我這樣搞了很多年Java後端開發的技術人員,在學習HBase的時候,會受到關係型資料庫3NF、BCNF的影響。事實上,資料庫正規化在HBase裡完全沒用,必須轉變思想。因此把這一點單獨寫出來,供類似情況的技術人員參考。

HBase邏輯檢視

這個圖看起來像是Excel表格,不同的是,它的一個單元格可以有多個版本的資料,這是HBase的多版本特性,預設版本數是1。實際儲存格式是每個單元格一行記錄,如下圖。

hbase(main):003:0> scan 'test'
ROW                         COLUMN+CELL                                                                    
 rowkey1                    column
=cf:level, timestamp=1608108298860, value=P9 rowkey1 column=cf:name, timestamp=1607677762394, value=guanyu rowkey2 column=cf:salary, timestamp=1607328820620, value=200w rowkey3 column
=cf:corp, timestamp=1607330730061, value=Alibaba rowkey4 column=cf:name, timestamp=1607331563986, value=XiaoYaoZi 4 row(s) Took 1.7952 seconds

我們再來看看存放在HDFS裡的hfile檔案內容。

[hadoop@server01 hadoop]$ hbase hfile -p -f /hbase/data/default/test/bc89689612a0269a2216349bd23133ec/cf/c66c7553a5d6488a9e1e57ca2b0a5577
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding 
in [jar:file:/usr/hadoop-3.3.0/share/hadoop/common/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [jar:file:/usr/hbase-2.2.6/lib/client-facing-thirdparty/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory] 2020-12-16 18:30:46,116 INFO [main] metrics.MetricRegistries: Loaded MetricRegistries class org.apache.hadoop.hbase.metrics.impl.MetricRegistriesImpl K: rowkey1/cf:level/1608108298860/Put/vlen=2/seqid=27 V: P9 K: rowkey1/cf:name/1607677762394/Put/vlen=6/seqid=14 V: guanyu K: rowkey2/cf:salary/1607328820620/Put/vlen=4/seqid=0 V: 200w K: rowkey3/cf:corp/1607330730061/Put/vlen=7/seqid=0 V: Alibaba K: rowkey4/cf:name/1607331563986/Put/vlen=9/seqid=0 V: XiaoYaoZi Scanned kv count -> 5

這個檔案可以很明顯地看出,它是一個鍵值儲存系統,鍵包含rowkey、列族、列名(列識別符號)、時間戳、資料型別(Put、Delete)、字元陣列長度、seqid。值就是單元格儲存的值。

這個鍵佔用了大量的空間,而且不同資料它們的列族列名完全是一樣的,太浪費空間了,這就需要用到HBase的壓縮,壓縮方式請自行檢視官網。

seqid是個什麼東西?百度了一下,可能是一個時間序列的標識,提示老的HLog是否可以刪除。

HBase表設計原則

  • 行鍵根據需求來設計,儘量短,儘量只調用一次API就可以完成需求。
  • HBase原生語法不支援表join操作,適當使用冗餘來簡化查詢操作。
  • 列名(列識別符號)可以儲存資料,每一條記錄的列名可以完全不同,但是儘量短。

表設計實戰

以微博關注為例來做一個小小的表設計,可能與微博實際不符,僅用於說明設計方法。

關注關係如下:

景天關注重樓、龍葵、雪見

飛蓬關注景天、重樓

重樓關注飛蓬、紫萱

龍葵關注景天

雪見關注景天

紫萱關注雪見

這是一個多對多的關係,如果是關係型資料庫,至少要兩張表來存放。一張表存放人物資訊,一張表存放人物關注關係。

時刻要想到,HBase沒有join操作,只能用一張表來存放關注和被關注的資訊,這肯定會存在資料冗餘。不要怕,HBase可以支援十億級別的列和百萬級別的行,冗餘不是問題。

我們可以這麼設計

行鍵 列族(關注誰) 列族(被誰關注)
001_景天 cf:003=重樓,cf:004=龍葵,cf:005=雪見 cf:002=飛蓬,cf:004=龍葵,cf:005=雪見
002_飛蓬 cf:001=景天,cf:003=重樓 cf:003=重樓
003_重樓 cf:002=飛蓬,cf:006=紫萱 cf:001=景天,cf:002=飛蓬
004_龍葵 cf:001=景天 cf:001=景天
005_雪見 cf:001=景天 cf:001=景天,cf:006=紫萱
006_紫萱 cf:005=雪見 cf:003=重樓

是不是驚呆了,這都什麼玩意。這種設計可以只用一次API呼叫就查出每個人關注了誰,每個人被誰關注了,按照需求來合理設計。