Kv for Hbase

Hbase是一種NoSQL數(shù)據(jù)庫,這意味著它不像傳統(tǒng)的RDBMS數(shù)據(jù)庫那樣支持SQL作為查詢語言。Hbase是一種分布式存儲(chǔ)的數(shù)據(jù)庫,技術(shù)上來講,它更像是分布式存儲(chǔ)而不是分布式數(shù)據(jù)庫,它缺少很多RDBMS系統(tǒng)的特性,比如列類型,輔助索引,觸發(fā)器,和高級(jí)查詢語言等待?!?a href="http://www.itdecent.cn/p/5e2e6c4baf44" target="_blank">Hbase 架構(gòu)圖」

那Hbase有什么特性:

  • 強(qiáng)讀寫一致,但是不是“最終一致性”的數(shù)據(jù)存儲(chǔ),這使得它非常適合高速的計(jì)算聚合
  • 自動(dòng)分片,通過Region分散在集群中,當(dāng)行數(shù)增長(zhǎng)的時(shí)候,Region也會(huì)自動(dòng)的切分和再分配
  • 自動(dòng)的故障轉(zhuǎn)移
  • Hadoop/HDFS集成,和HDFS開箱即用,不用太麻煩的銜接 「云上直接支持存算分離性」
  • 豐富的“簡(jiǎn)潔,高效”API,Thrift/REST API,Java API
  • 塊緩存,布隆過濾器,可以高效的列查詢優(yōu)化

使用場(chǎng)景:

  1. 訂單事件
    • 在線查詢訂單生命周期的各個(gè)狀態(tài),包括status、event_type、order_detail等信息
    • 在線歷史訂單詳情查詢。上層會(huì)有Redis來存儲(chǔ)近期的訂單,當(dāng)Redis不可用或者查詢范圍超出Redis,查詢會(huì)直接落到HBase
    • 離線對(duì)訂單的狀態(tài)進(jìn)行分析。
  2. 對(duì)象存儲(chǔ)
    • 頭條類、新聞?lì)惖牡男侣劇⒕W(wǎng)頁、圖片存儲(chǔ)在HBase之中,一些病毒公司的病毒庫也是存儲(chǔ)在HBase之中
  3. 時(shí)序數(shù)據(jù)
    • HBase之上有OpenTSDB模塊,可以滿足時(shí)序類場(chǎng)景的需求
  4. 推薦畫像
    • 特別是用戶的畫像,是一個(gè)比較大的稀疏矩陣,螞蟻的風(fēng)控就是構(gòu)建在HBase之上
  5. 時(shí)空數(shù)據(jù) 「需要內(nèi)部進(jìn)行一些業(yè)務(wù)適配」
    • 主要是軌跡、氣象網(wǎng)格之類,滴滴打車的軌跡數(shù)據(jù)主要存在HBase之中,另外在技術(shù)所有大一點(diǎn)的數(shù)據(jù)量的車聯(lián)網(wǎng)企業(yè),數(shù)據(jù)都是存在HBase之中
  6. CubeDB OLAP
    • Kylin一個(gè)cube分析工具,底層的數(shù)據(jù)就是存儲(chǔ)在HBase之中,不少客戶自己基于離線計(jì)算構(gòu)建cube存儲(chǔ)在hbase之中,滿足在線報(bào)表查詢的需求
  7. Feeds流
    • 典型的應(yīng)用就是xx朋友圈類似的應(yīng)用
  8. NewSQL
    • 之上有Phoenix的插件,可以滿足二級(jí)索引、SQL的需求,對(duì)接傳統(tǒng)數(shù)據(jù)需要SQL非事務(wù)的需求

知識(shí)點(diǎn)

什么是熱點(diǎn)?

HBase中的行是按照rowkey的字典順序排序的,這種設(shè)計(jì)優(yōu)化了scan操作,可以將相關(guān)的行以及會(huì)被一起讀取的行存取在臨近位置,便于scan。然而糟糕的rowkey設(shè)計(jì)是熱點(diǎn)的源頭。 熱點(diǎn)發(fā)生在大量的client直接訪問集群的一個(gè)或極少數(shù)個(gè)節(jié)點(diǎn)(訪問可能是讀,寫或者其他操作)。大量訪問會(huì)使熱點(diǎn)region所在的單個(gè)機(jī)器超出自身承受能力,引起性能下降甚至region不可用,這也會(huì)影響同一個(gè)RegionServer上的其他region,由于主機(jī)無法服務(wù)其他region的請(qǐng)求。 設(shè)計(jì)良好的數(shù)據(jù)訪問模式以使集群被充分,均衡的利用。為了避免寫熱點(diǎn),設(shè)計(jì)rowkey使得不同行在同一個(gè)region,但是在更多數(shù)據(jù)情況下,數(shù)據(jù)應(yīng)該被寫入集群的多個(gè)region,而不是一個(gè)。

下面是一些常見的避免熱點(diǎn)的方法以及它們的優(yōu)缺點(diǎn):

  • 加鹽:這里所說的加鹽不是密碼學(xué)中的加鹽,而是在rowkey的前面增加隨機(jī)數(shù),具體就是給rowkey分配一個(gè)隨機(jī)前綴以使得它和之前的rowkey的開頭不同。分配的前綴種類數(shù)量應(yīng)該和你想使用數(shù)據(jù)分散到不同的region的數(shù)量一致。加鹽之后的rowkey就會(huì)根據(jù)隨機(jī)生成的前綴分散到各個(gè)region上,以避免熱點(diǎn)。
  • 哈希:哈希會(huì)使同一行永遠(yuǎn)用一個(gè)前綴加鹽。哈希也可以使負(fù)載分散到整個(gè)集群,但是讀卻是可以預(yù)測(cè)的。使用確定的哈??梢宰尶蛻舳酥貥?gòu)完整的rowkey,可以使用get操作準(zhǔn)確獲取某一個(gè)行數(shù)據(jù)。
  • 反轉(zhuǎn):第三種防止熱點(diǎn)的方法時(shí)反轉(zhuǎn)固定長(zhǎng)度或者數(shù)字格式的rowkey。這樣可以使得rowkey中經(jīng)常改變的部分(最沒有意義的部分)放在前面。這樣可以有效的隨機(jī)rowkey,但是犧牲了rowkey的有序性。反轉(zhuǎn)rowkey的例子以手機(jī)號(hào)為rowkey,可以將手機(jī)號(hào)反轉(zhuǎn)后的字符串作為rowkey,這樣的就避免了以手機(jī)號(hào)那樣比較固定開頭導(dǎo)致熱點(diǎn)問題。
  • 時(shí)間戳反轉(zhuǎn):一個(gè)常見的數(shù)據(jù)處理問題是快速獲取數(shù)據(jù)的最近版本,使用反轉(zhuǎn)的時(shí)間戳作為rowkey的一部分對(duì)這個(gè)問題十分有用,可以用 Long.Max_Value - timestamp 追加到key的末尾,例如 [key][reverse_timestamp], [key] 的最新值可以通過scan [key]獲得[key]的第一條記錄,因?yàn)镠Base中rowkey是有序的,第一條記錄是最后錄入的數(shù)據(jù)。比如需要保存一個(gè)用戶的操作記錄,按照操作時(shí)間倒序排序,在設(shè)計(jì)rowkey的時(shí)候,可以這樣設(shè)計(jì) [userId反轉(zhuǎn)][Long.Max_Value - timestamp],在查詢用戶的所有操作記錄數(shù)據(jù)的時(shí)候,直接指定反轉(zhuǎn)后的userId,startRow是[userId反轉(zhuǎn)][000000000000],stopRow是[userId反轉(zhuǎn)][Long.Max_Value - timestamp]如果需要查詢某段時(shí)間的操作記錄,startRow是[user反轉(zhuǎn)][Long.Max_Value - 起始時(shí)間],stopRow是[userId反轉(zhuǎn)][Long.Max_Value - 結(jié)束時(shí)間]
  • 其他一些建議:盡量減少行和列的大小在HBase中,value永遠(yuǎn)和它的key一起傳輸?shù)?。?dāng)具體的值在系統(tǒng)間傳輸時(shí),它的rowkey,列名,時(shí)間戳也會(huì)一起傳輸。如果你的rowkey和列名很大,甚至可以和具體的值相比較,那么你將會(huì)遇到一些有趣的問題。HBase storefiles中的索引(有助于隨機(jī)訪問)最終占據(jù)了HBase分配的大量?jī)?nèi)存,因?yàn)榫唧w的值和它的key很大??梢栽黾觔lock大小使得storefiles索引再更大的時(shí)間間隔增加,或者修改表的模式以減小rowkey和列名的大小。壓縮也有助于更大的索引。

HBase客戶端優(yōu)化

和大多數(shù)系統(tǒng)一樣,客戶端作為業(yè)務(wù)讀寫的入口,姿勢(shì)使用不正確通常會(huì)導(dǎo)致本業(yè)務(wù)讀延遲較高實(shí)際上存在一些使用姿勢(shì)的推薦用法,這里一般需要關(guān)注四個(gè)問題:

  1. scan緩存是否設(shè)置合理?
    • 優(yōu)化原理:在解釋這個(gè)問題之前,首先需要解釋什么是scan緩存,通常來講一次scan會(huì)返回大量數(shù)據(jù),因此客戶端發(fā)起一次scan請(qǐng)求,實(shí)際并不會(huì)一次就將所有數(shù)據(jù)加載到本地,而是分成多次RPC請(qǐng)求進(jìn)行加載,這樣設(shè)計(jì)一方面是因?yàn)榇罅繑?shù)據(jù)請(qǐng)求可能會(huì)導(dǎo)致網(wǎng)絡(luò)帶寬嚴(yán)重消耗進(jìn)而影響其他業(yè)務(wù),另一方面也有可能因?yàn)閿?shù)據(jù)量太大導(dǎo)致本地客戶端發(fā)生OOM。在這樣的設(shè)計(jì)體系下用戶會(huì)首先加載一部分?jǐn)?shù)據(jù)到本地,然后遍歷處理,再加載下一部分?jǐn)?shù)據(jù)到本地處理,如此往復(fù),直至所有數(shù)據(jù)都加載完成。數(shù)據(jù)加載到本地就存放在scan緩存中,默認(rèn)100條數(shù)據(jù)大小。
    • 通常情況下,默認(rèn)的scan緩存設(shè)置就可以正常工作的。但是在一些大scan(一次scan可能需要查詢幾萬甚至幾十萬行數(shù)據(jù))來說,每次請(qǐng)求100條數(shù)據(jù)意味著一次scan需要幾百甚至幾千次RPC請(qǐng)求,這種交互的代價(jià)無疑是很大的。因此可以考慮將scan緩存設(shè)置增大,比如設(shè)為500或者1000就可能更加合適。筆者之前做過一次試驗(yàn),在一次scan掃描10w+條數(shù)據(jù)量的條件下,將scan緩存從100增加到1000,可以有效降低scan請(qǐng)求的總體延遲,延遲基本降低了25%左右。
    • 優(yōu)化建議:大scan場(chǎng)景下將scan緩存從100增大到500或者1000,用以減少RPC次數(shù)
  2. get請(qǐng)求是否可以使用批量請(qǐng)求?
    • 優(yōu)化原理:HBase分別提供了單條get以及批量get的API接口,使用批量get接口可以減少客戶端到RegionServer之間的RPC連接數(shù),提高讀取性能。另外需要注意的是,批量get請(qǐng)求要么成功返回所有請(qǐng)求數(shù)據(jù),要么拋出異常。
    • 優(yōu)化建議:使用批量get進(jìn)行讀取請(qǐng)求
  3. 請(qǐng)求是否可以顯示指定列族或者列?
    • 優(yōu)化原理:HBase是典型的列族數(shù)據(jù)庫,意味著同一列族的數(shù)據(jù)存儲(chǔ)在一起,不同列族的數(shù)據(jù)分開存儲(chǔ)在不同的目錄下。如果一個(gè)表有多個(gè)列族,只是根據(jù)Rowkey而不指定列族進(jìn)行檢索的話不同列族的數(shù)據(jù)需要獨(dú)立進(jìn)行檢索,性能必然會(huì)比指定列族的查詢差很多,很多情況下甚至?xí)?倍~3倍的性能損失。
    • 優(yōu)化建議:可以指定列族或者列進(jìn)行精確查找的盡量指定查找
  4. 離線批量讀取請(qǐng)求是否設(shè)置禁止緩存?
    • 優(yōu)化原理:通常離線批量讀取數(shù)據(jù)會(huì)進(jìn)行一次性全表掃描,一方面數(shù)據(jù)量很大,另一方面請(qǐng)求只會(huì)執(zhí)行一次。這種場(chǎng)景下如果使用scan默認(rèn)設(shè)置,就會(huì)將數(shù)據(jù)從HDFS加載出來之后放到緩存。可想而知,大量數(shù)據(jù)進(jìn)入緩存必將其他實(shí)時(shí)業(yè)務(wù)熱點(diǎn)數(shù)據(jù)擠出,其他業(yè)務(wù)不得不從HDFS加載,進(jìn)而會(huì)造成明顯的讀延遲毛刺
    • 優(yōu)化建議:離線批量讀取請(qǐng)求設(shè)置禁用緩存,scan.setBlockCache(false)
  5. 客戶端避坑 「重要」
    • RegionServer 發(fā)生宕機(jī)后客戶端meta 緩存刷新
    • 訪問 meta 表或者 zk 異常判斷邏輯,重試機(jī)制「重試之間Sleep 問題」,超時(shí)邏輯
  6. Rowkey 設(shè)計(jì) 「重要」
    • 通過rowkey(行鍵),column key(column family和qualifier)和TimeStamp(時(shí)間戳)這個(gè)三個(gè)維度可以對(duì)HBase中的數(shù)據(jù)進(jìn)行快速定位。
    • rowkey長(zhǎng)度原則:rowkey是一個(gè)二進(jìn)制碼流,可以是任意字符串,最大長(zhǎng)度 64kb ,實(shí)際應(yīng)用中一般為10-100bytes,以 byte[] 形式保存,一般設(shè)計(jì)成定長(zhǎng)。建議越短越好,不要超過16個(gè)字節(jié),原因如下:數(shù)據(jù)的持久化文件HFile中是按照KeyValue存儲(chǔ)的,如果rowkey過長(zhǎng),比如超過100字節(jié),1000w行數(shù)據(jù),光rowkey就要占用100*1000w=10億個(gè)字節(jié),將近1G數(shù)據(jù),這樣會(huì)極大影響HFile的存儲(chǔ)效率;MemStore將緩存部分?jǐn)?shù)據(jù)到內(nèi)存,如果rowkey字段過長(zhǎng),內(nèi)存的有效利用率就會(huì)降低,系統(tǒng)不能緩存更多的數(shù)據(jù),這樣會(huì)降低檢索效率。目前操作系統(tǒng)都是64位系統(tǒng),內(nèi)存8字節(jié)對(duì)齊,控制在16個(gè)字節(jié),8字節(jié)的整數(shù)倍利用了操作系統(tǒng)的最佳特性。
    • rowkey散列原則:如果rowkey按照時(shí)間戳的方式遞增,不要將時(shí)間放在二進(jìn)制碼的前面,建議將rowkey的高位作為散列字段,由程序隨機(jī)生成,低位放時(shí)間字段,這樣將提高數(shù)據(jù)均衡分布在每個(gè)RegionServer,以實(shí)現(xiàn)負(fù)載均衡的幾率。如果沒有散列字段,首字段直接是時(shí)間信息,所有的數(shù)據(jù)都會(huì)集中在一個(gè)RegionServer上,這樣在數(shù)據(jù)檢索的時(shí)候負(fù)載會(huì)集中在個(gè)別的RegionServer上,造成熱點(diǎn)問題,會(huì)降低查詢效率。
    • rowkey唯一原則:必須在設(shè)計(jì)上保證其唯一性,rowkey是按照字典順序排序存儲(chǔ)的,因此,設(shè)計(jì)rowkey的時(shí)候,要充分利用這個(gè)排序的特點(diǎn),將經(jīng)常讀取的數(shù)據(jù)存儲(chǔ)到一塊,將最近可能會(huì)被訪問的數(shù)據(jù)放到一塊。

借鑒了大量文檔之后濃縮的一些日常體會(huì),希望能給到大家?guī)椭?/p>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容