用HBase做高效能鍵值查詢?

技術小能手發表於2018-07-04

最近碰到幾家使用者在使用HBase或者試圖使用HBase來做高效能查詢,場景也比較類似,就是從幾十億甚至上百億記錄中按鍵值找出相關記錄來。按說,這種key-value式的資料庫很適合用鍵值查詢,HBase看起來就是個不錯的選擇。

然而,已經實施過的使用者卻反映:效果非常差!

其實,這是預料之中的結果,因為HBase根本不適合做這件事!

從實現原理上看,key-value式的資料庫無非也就是按key建了索引來查詢。而索引技術,無論是傳統資料庫用的B樹還是NoSQL資料庫常用的LSM樹,其本質都是利用鍵值有序,把遍歷查詢變成二分(或n-分)查詢,在查詢效能上並沒有根本差異。LSM樹的優勢在於一定程度克服了B樹在更新時要面對的複雜的平衡調整,並利用了硬體的特點,對於併發高頻寫入的操作更為擅長,在讀取方面卻反而有所犧牲。而對於很少更新的歷史資料,用NoSQL資料庫在按鍵值查詢時,和傳統關聯式資料庫相比,並不會有優勢,大概率還會有劣勢。

不過,對於只要找出一條記錄的情況,這個優勢或劣勢是察覺不到的,就算差了10倍,也不過是10毫秒和100毫秒的差別,對前端操作人員來講都是立即響應。所以,人們一般也不容易有直觀的體驗。

但是,如果要找出成千上萬甚至幾十萬行記錄時,那感覺就明顯了,100毫秒執行1萬次就要1000秒了。上面說的使用者應用效果差也是這種情況。

用鍵值取數時,可以通過索引直接跳到資料所在地,這樣硬碟訪問量非常小,所以能做到很快。而如果鍵值非常多時,涉及的資料到處都是,硬碟訪問量就會加大很多。而且資料在外存中是按塊儲存的,你不可能只讀取一條記錄本身的資料,而要把這個記錄周邊的資料都讀出來,多讀出的內容常常比要讀的資料量還大很多倍。在總共只取一條記錄時,即使這樣,使用者體驗也不會有多差(10毫秒和100毫秒的差異);而要取出很多記錄時,這個多讀的內容也就跟著翻倍了,使用者體驗也就很糟糕了。

如果這些鍵值是連續的,那麼適當設計儲存,讓資料的物理儲存也按鍵值有序,這樣就不會有浪費的讀取內容,效能損失也就很少。商用關聯式資料庫一般會按插入次序儲存資料,基本可以保證這一點。在儲存塊中會留有一部分空間應付少量改寫,這樣有些資料改動了也能大體保證連續性,按鍵值區間查詢的效能也還不錯。但HDFS沒有改寫能力,HBase在有資料改寫時只能先扔到後面(LSM樹也是這麼設計的),這樣會導致資料儲存的不連續性,增加多餘的讀取,降低效能。

如果鍵值不連續(這是更常見的情況),那這種多餘讀就無論如何不能避免,這時候想再優化的辦法就是壓縮,直接減少物理儲存量。但是在這方面,HBase這種key-value資料庫的表現也不如人意。這些NoSQL允許同一表中不同記錄有不同欄位,它不象關聯式資料庫那樣對每個表有一個所有記錄統一的資料結構定義,這樣帶來了寫入的靈活性,但勢必要將資料結構資訊附在記錄上,導致儲存量加大很多,給讀取造成巨大的負擔。而且,這種key-value方式也沒法採用列存(嚴格地說,就沒有列的概念),而列存+排序後可以極大提升壓縮率(這個問題以後可以再專門講)。HBase有個列族的概念,可以充當列的作用,這方面問題一定程度會有所緩解,但用起來並不方便。

總結下來,大多數key-value資料庫是為了高頻寫入而設計的,而不是為了高速讀取!用來做高效能查詢完全是個方向性錯誤。用於鍵值查詢都不合適,而其它非鍵值查詢的效果就更為惡劣(以前文中也說過這個問題)。

明明不合適,為什麼還有這麼多人用或想用HBase來解決這個問題呢?可能是Hadoop名聲太大吧,只要有大資料就會想到用Hadoop。而且,很多傳統關聯式資料庫也確實搞不定太大量的資料,資料量大到一定程度,儲存都是問題,查詢就無從提起了。不過,有些新的資料技術方案已經能夠解決這些問題,延續了傳統資料倉儲的某些技術手段,比如事先確定資料結構、為讀而優化的索引、列存及壓縮等,再有合理的儲存機制以支撐巨大資料量,這樣就能得到比HBase好得多的效能體驗。

原文釋出時間為:2018-07-03
本文作者:蔣步星
本文來自雲棲社群合作伙伴“資料蔣堂”,瞭解相關資訊可以關注“資料蔣堂”。


相關文章