天天看點

用HBase做高性能鍵值查詢?

最近碰到幾家使用者在使用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

本文作者:蔣步星

本文來自雲栖社群合作夥伴“

資料蔣堂

”,了解相關資訊可以關注“

”。