修改HBase的rowkey设计把应用的QPS从5W提升到50W
摘要:?正確設(shè)計(jì)Hbase的rowkey可以讓你的應(yīng)用飛起來,前提是你需要了解一些Hbase的存儲(chǔ)機(jī)制。
UTT是Aliexpress的營銷消息運(yùn)營平臺(tái),運(yùn)營希望促銷活動(dòng)時(shí)APP消息推送的QPS達(dá)到34W。
UTT剛接入APP消息推送時(shí),QPS只能達(dá)到5W,離運(yùn)營的要求有很大的距離。
通過改造,QPS達(dá)到了50W,其中最主要的改造是對Hbase的rowkey的改造。
首先介紹一下UTT大致工作流程:
1、運(yùn)營人員在UTT的小二控制臺(tái)配置運(yùn)營任務(wù)(job),在任務(wù)中設(shè)置商品選擇參數(shù)、目標(biāo)人群參數(shù)和消息發(fā)送渠道;
2、UTT調(diào)用算法平臺(tái)計(jì)算出要發(fā)送的消息,數(shù)據(jù)生成在阿里云飛天系統(tǒng)的云梯表中;
3、UTT把云梯表中的數(shù)據(jù)導(dǎo)入到hbase,并生成N個(gè)可以并發(fā)執(zhí)行的發(fā)送任務(wù)(segment),segment的信息存儲(chǔ)在mysql表中;
4、UTT按計(jì)劃發(fā)送時(shí)間撈取segment,把存儲(chǔ)在Hbase中的segment對應(yīng)的消息讀取出來調(diào)用阿里巴巴移動(dòng)消息推送網(wǎng)關(guān)發(fā)送出去。
步驟1、2、3是提前執(zhí)行的,我們要優(yōu)化的是步驟4。
改造中,我們主要做了如下幾件事:
1、修改了Hbase的rowkey規(guī)則和數(shù)據(jù)讀取方式;
2、優(yōu)化了記錄發(fā)送進(jìn)度的邏輯;
3、優(yōu)化了消息發(fā)送到阿里巴巴移動(dòng)消息推送網(wǎng)關(guān)的流程。
其中最主要的是對Hbase的rowkey的修改。
改造前的rowkey設(shè)計(jì):
rowkey=segmentSalt+”_"+dataIndexInSegment+”_”+segmentId+”_”+jobTime+”_”+jobId
說明如下:
job:job對應(yīng)運(yùn)營在后臺(tái)頁面配置的任務(wù),一個(gè)job可能多次運(yùn)行,用jobId+jobTime可以唯一標(biāo)識(shí)一個(gè)job的一次發(fā)送任務(wù)。
segment:一個(gè)job的一次發(fā)送任務(wù)拆分為多個(gè)segment,每個(gè)segment對應(yīng)10萬條消息。多個(gè)segment的消息可以并行發(fā)送。
segmentSalt:4位的隨機(jī)字母,每個(gè)segment有一個(gè)salt,用于把數(shù)據(jù)均勻分散到Hbase的不同region中;
dataIndexInSegment:每條消息在segment中的序號(hào),從0到99999;
改造前UTT按計(jì)劃發(fā)送時(shí)間撈出要發(fā)送的segment后,從按0到99999的順序從Hbase中讀取消息,然后發(fā)送出去。為了提高效率使用了hbase的批量get方法。
這個(gè)設(shè)計(jì)存在一個(gè)很大的問題,同一個(gè)segment里的相鄰消息的rowkey不是連續(xù)的,之間可能隔的非常遠(yuǎn)。
如下圖所示,10000號(hào)消息rowkey和10000
1號(hào)消息rowkey之間可能隔了很多rowkey。
這會(huì)帶來啥問題?這就需要了解Hbase的存儲(chǔ)機(jī)制。
Hbase的存儲(chǔ)是以storeFile為單位,以LSM樹(Log-structured merge tree)方式存儲(chǔ)。
此結(jié)構(gòu)優(yōu)化寫性能,犧牲讀性能。寫數(shù)據(jù)的時(shí)候先按rowkey計(jì)算出region和store,順序?qū)懭氲絪tore的memeStoreFile中,memoStoreFile達(dá)到指定大小后flush到磁盤的storeFile中。因此同一個(gè)store里,多個(gè)storeFile的rowkey的范圍是會(huì)有重疊的。
按rowkey讀取數(shù)據(jù)時(shí),計(jì)算該rowkey可能存儲(chǔ)的storeFile,把這些storeFile全部讀取到內(nèi)存中,最后把多個(gè)storeFile里查詢到的結(jié)果合并后輸出。
為了提高讀性能,Hbase會(huì)在后臺(tái)把多個(gè)storeFile進(jìn)行merge,形成rowkey范圍互不重疊的storeFile。
另外Hbase采用按列值KV方式存儲(chǔ)數(shù)據(jù),也就是說每個(gè)列的值都是獨(dú)立存儲(chǔ)的。每個(gè)列值KV對里的key包括了rowkey和列名,key里的大部分?jǐn)?shù)據(jù)是重復(fù)的,storeFile采用壓縮算法減小空間。
改造前同一個(gè)segment里的消息的rowkey很分散,讀取一個(gè)segment的消息時(shí)要從磁盤上裝載大量的storeFile,消耗大量的cpu進(jìn)行解壓縮,這也會(huì)導(dǎo)致storeFile 的cache命中率不高。并且讀出來的大部分storeFile是沒有包含所需數(shù)據(jù)的。
分析UTT的場景,多個(gè)segment是并發(fā)讀寫的,每個(gè)segment有segmentSalt,保證了讀寫均勻分布到Hbase的不同region。如果讀取一個(gè)segment的消息時(shí)能從盡量少的storeFile讀取數(shù)據(jù),就能夠減少磁盤IO,減少解壓縮及數(shù)據(jù)查找的CPU,還能提高storeFile cache的命中率。
改造后的rowkey設(shè)計(jì):
rowkey=segmentSalt+”_”+jobTime+”_”+jobId+”_”+segmentId+”_”+dataIndexInSegment(前補(bǔ)零到定長5位)
這樣多個(gè)segment并發(fā)讀寫均勻分散到不同region,同一個(gè)segment的消息順序?qū)懙较嗤膕toreFile中,讀取的時(shí)候不再使用get方法而是使用scan方法。最后qps提升了一個(gè)數(shù)量級(jí)。
附一個(gè)hbase的知識(shí)腦圖,不知道作者是誰,挺好的。
原文鏈接?
本文為云棲社區(qū)原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。
總結(jié)
以上是生活随笔為你收集整理的修改HBase的rowkey设计把应用的QPS从5W提升到50W的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PyODPS DataFrame:统一的
- 下一篇: 企业如何采用机器学习