用HBase做高性能鍵值查詢?

摘要: 最近碰到幾家用戶在使用HBase或者試圖使用HBase來做高性能查詢,場景也比較類似,就是從幾十億甚至上百億記錄中按鍵值找出相關記錄來。按說,這種key-value式的數據庫很適合用鍵值查詢,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好得多的性能體驗。請添加鏈接描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章