免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
AdMaster 如何駕馭百億級Key實時Redis 集群,高效實現(xiàn)數(shù)據(jù)商業(yè)價值

已獲轉(zhuǎn)載授權(quán)



作為技術(shù)驅(qū)動的營銷數(shù)據(jù)公司,AdMaster每天處理超過100億的數(shù)據(jù)請求,每天對1000億數(shù)據(jù)進行上千種維度計算,每天增加超過5T數(shù)據(jù)量,為來自各行業(yè)的客戶提供7*24小時數(shù)據(jù)應(yīng)用服務(wù)。在這樣領(lǐng)先的技術(shù)布局下,無論是數(shù)據(jù)實時性還是數(shù)據(jù)安全,都能得到最高級別的保障。在數(shù)據(jù)實時處理方面,以AdMaster旗下兩款領(lǐng)先和已獲行業(yè)認可的重型SaaS產(chǎn)品AdMaster DMP和SmartServing來說,如何強大的底層構(gòu)架技術(shù)能夠支持AdMaster DMP和SmartServing為廣告主提供營銷過程中的數(shù)據(jù)實時查詢、透明、高效直采媒介優(yōu)質(zhì)資源的投放控制及復(fù)雜人群的實時定向等領(lǐng)先功能?以下唯技術(shù)牛才懂的火星語,帶大家感受下大數(shù)據(jù)技術(shù)之美!
1. 應(yīng)用場景

該應(yīng)用場景為解決AdMaster DMP緩存存儲需求,DMP需要管理非常多的第三方id數(shù)據(jù),其中包括各媒體cookie id與自身cookie id(以下統(tǒng)稱admckid)的mapping關(guān)系,還包括了admckid的人口標簽、移動端id(主要是idfa和imei)的人口標簽,以及一些黑名單id、ip等數(shù)據(jù)。


在HDFS的幫助下離線存儲千億記錄并不困難,然而DMP還需要提供毫秒級的實時查詢。由于cookie這種id本身具有不穩(wěn)定性,所以很多的真實用戶的瀏覽行為會導(dǎo)致大量的新cookie生成,只有及時同步mapping的數(shù)據(jù)才能命中DMP的人口標簽,無法通過預(yù)熱來獲取較高的命中,這就跟緩存存儲帶來了極大的挑戰(zhàn)。


經(jīng)過實際測試,對于上述數(shù)據(jù),常規(guī)存儲超過五十億的kv記錄就需要1T多的內(nèi)存,如果需要做高可用多副本那帶來的消耗是巨大的,另外kv的長短不齊也會帶來很多內(nèi)存碎片,這就需要超大規(guī)模的存儲方案來解決上述問題。

2. 存儲何種數(shù)據(jù)

人口標簽主要是cookie id、imei、idfa以及其對應(yīng)的gender(性別)、age(年齡段)、geo(地域)等;mapping關(guān)系主要是媒體cookie id對admckid的映射。以下是數(shù)據(jù)存儲示例:


3. 數(shù)據(jù)特點

1)  短key短value:其中superid為19位字符:比如s17b2661d0354ba3380;imei為小寫md5:比如2d131005dc0f37d362a5d97094103633;idfa為大寫帶”-”md5:比如:51DFFC83-9541-4411-FA4F-356927E39D04;

2)  媒體自身的cookie id長短不一;

3)  需要為全量數(shù)據(jù)提供服務(wù),admckid是百億級(一個月)、媒體映射是千億級、移動id是幾十億級;

4)  每天有幾十億級別的mapping關(guān)系產(chǎn)生;

5)  對于較大時間窗口內(nèi)可以預(yù)判熱數(shù)據(jù)(有一些存留的穩(wěn)定cookie);

6)  對于當前mapping數(shù)據(jù)無法預(yù)判熱數(shù)據(jù),有很多是新生成的cookie;

4. 存在的技術(shù)挑戰(zhàn)

1)長短不一容易造成內(nèi)存碎片;

2)由于指針大量存在,內(nèi)存膨脹率比較高,一般在7倍,純內(nèi)存存儲通?。?/span>

3)雖然可以通過cookie的行為預(yù)判其熱度,但每天新生成的id依然很多(百分比比較敏感,暫不透露);

4)由于服務(wù)要求在公網(wǎng)環(huán)境(國內(nèi)公網(wǎng)延遲60ms以下)下100ms以內(nèi),所以原則上當天新更新的mapping和人口標簽需要全部in memory,而不會讓請求落到后端的冷數(shù)據(jù);

5)業(yè)務(wù)方面,所有數(shù)據(jù)原則上至少保留1個月甚至更久;

6)內(nèi)存至今也比較昂貴,百億級Key乃至千億級存儲方案勢在必行!

5. 解決方案

5.1 淘汰策略


存儲吃緊的一個重要原因在于每天會有很多新數(shù)據(jù)入庫,所以及時清理數(shù)據(jù)尤為重要。主要方法就是發(fā)現(xiàn)和保留熱數(shù)據(jù)淘汰冷數(shù)據(jù)。


網(wǎng)民的量級遠遠達不到幾十億的規(guī)模,id有一定的生命周期,會不斷的變化。所以很大程度上我們存儲的id實際上是無效的。而查詢其實前端的邏輯就是廣告曝光,跟人的行為有關(guān),所以一個id在某個時間窗口的(可能是一個項目,半個月、幾個月)訪問行為上會有一定的重復(fù)性。


數(shù)據(jù)初始化之前,我們先利用hbase將日志的id聚合去重,劃定TTL的范圍,一般是1個月,這樣可以砍掉近1個月未出現(xiàn)的id。另外在Redis中設(shè)置過期時間是1個月,當有訪問并命中時,對key進行續(xù)命,延長過期時間,未在1個月出現(xiàn)的自然淘汰。這樣可以針對穩(wěn)定cookie或id有效,實際證明,續(xù)命的方法對idfa和imei比較實用,長期積累可達到非常理想的命中。

5.2 減少膨脹


Hash表空間大小和Key的個數(shù)決定了沖突率(或者用負載因子衡量),再合理的范圍內(nèi),key越多自然hash表空間越大,消耗的內(nèi)存自然也會很大。再加上大量指針本身是長整型,所以內(nèi)存存儲的膨脹十分可觀。先來談?wù)勅绾伟裬ey的個數(shù)減少。


大家先來了解一種存儲結(jié)構(gòu)。我們期望將key1=>value1存儲在Redis中,那么可以按照如下過程去存儲。先用固定長度的隨機散列md5(key)值作為Redis的key,我們稱之為BucketId,而將key1=>value1存儲在hashmap結(jié)構(gòu)中,這樣在查詢的時候就可以讓client按照上面的過程計算出散列,從而查詢到value1。


過程變化簡單描述為:get(key1) ->hget(md5(key1), key1) 從而得到value1。


如果我們通過預(yù)先計算,讓很多key可以在BucketId空間里碰撞,那么可以認為一個BucketId下面掛了多個key。比如平均每個BucketId下面掛10個key,那么理論上我們將會減少超過90%的Redis key的個數(shù)。



key-value存儲示意圖


具體實現(xiàn)起來有一些麻煩,而且用這個方法之前你要想好容量規(guī)模。我們通常使用的md5是32位的hexString(16進制字符),它的空間是128bit,這個量級太大了,我們需要存儲的是百億級,大約是33bit,所以我們需要有一種機制計算出合適位數(shù)的散列,而且為了節(jié)約內(nèi)存,我們需要利用全部字符類型(ASCII碼在0~127之間)來填充,而不用HexString,這樣Key的長度可以縮短到一半。


下面是具體的實現(xiàn)方式:




參數(shù)bit決定了最終BucketId空間的大小,空間大小集合是2的整數(shù)冪次的離散值。這里解釋一下為何一個字節(jié)中只有7位可用,是因為Redis存儲key時需要是ASCII(0~127),而不是byte array。如果規(guī)劃百億級存儲,計劃每個桶分擔10個kv,那么我們只需2^30=1073741824的桶個數(shù)即可,也就是最終key的個數(shù)。

5.3 減少碎片


碎片主要原因在于內(nèi)存無法對齊、過期刪除后,內(nèi)存無法重新分配。通過上文描述的方式,我們可以將人口標簽和mapping數(shù)據(jù)按照上面的方式去存儲,這樣的好處就是Redis key是等長的。另外對于hashmap中的key我們也做了相關(guān)優(yōu)化,截取cookie或者deviceid的后六位作為key,這樣也可以保證內(nèi)存對齊,理論上會有沖突的可能性,但在同一個桶內(nèi)后綴相同的概率極低(試想id幾乎是隨機的字符串,隨意10個由較長字符組成的id后綴相同的概率*桶樣本數(shù)=發(fā)生沖突的期望值<<0.05,也就是說出現(xiàn)一個沖突樣本則是極小概率事件,而且這個概率可以通過調(diào)整后綴保留長度控制期望值)。而value只存儲age、gender、geo等的編碼,用三個字節(jié)去存儲。


另外提一下,減少碎片還有個很low但是有效的方法,將slave重啟,然后強制的failover切換主從,這樣相當于給master整理的內(nèi)存的碎片。


推薦Google-tcmalloc, facebook-jemalloc內(nèi)存分配,可以在value不大時減少內(nèi)存碎片和內(nèi)存消耗。有人測過大value情況下反而libc更節(jié)約。


6. md5散列桶的方法需要注意的問題


1)kv存儲的量級必須事先規(guī)劃好,浮動的范圍大概在桶個數(shù)的十到十五倍,比如我就想存儲百億左右的kv,那么最好選擇30bit~31bit作為桶的個數(shù)。也就是說業(yè)務(wù)增長在一個合理的范圍(10~15倍的增長)是沒問題的,如果業(yè)務(wù)太多倍數(shù)的增長,會導(dǎo)致hashset增長過快導(dǎo)致查詢時間增加,甚至觸發(fā)zip-list閾值,導(dǎo)致內(nèi)存急劇上升。


2)適合短小value,如果value太大或字段太多并不適合,因為這種方式必須要求把value一次性取出,比如人口標簽是非常小的編碼,甚至只需要3、4個bit(位)就能裝下。


3)典型的時間換空間的做法,由于我們的業(yè)務(wù)場景并不是要求在極高的QPS之下,一般每天億到十億級別的量,所以合理利用CPU租值,也是十分經(jīng)濟的。


4)由于使用了信息摘要降低了key的大小以及約定長度,所以無法從Redis里面random出key。如果需要導(dǎo)出,必須在冷數(shù)據(jù)中導(dǎo)出。


5)expire需要自己實現(xiàn),目前的算法很簡單,由于只有在寫操作時才會增加消耗,所以在寫操作時按照一定的比例抽樣,用HLEN命中判斷是否超過15個entry,超過才將過期的key刪除,TTL的時間戳存儲在value的前32bit中。


6)桶的消耗統(tǒng)計是需要做的。需要定期清理過期的key,保證Redis的查詢不會變慢。

7. 測試結(jié)果

人口標簽和mapping的數(shù)據(jù)100億條記錄。


優(yōu)化前用2.3T,碎片率在2左右;優(yōu)化后500g,而單個桶的平均消耗在4左右。碎片率在1.02左右。查詢時這對于cpu的耗損微乎其微。

 

另外需要提一下的是,每個桶的消耗實際上并不是均勻的,而是符合多項式分布的。



上面的公式可以計算桶消耗的概率分布。公式是唬人用的,只是為了提醒大家不要想當然的認為桶消耗是完全均勻的,有可能有的桶會有上百個key。但事實并不沒有那么夸張。試想一下投硬幣,結(jié)果只有兩種正反面。相當于只有兩個桶,如果你投上無限多次,每一次相當于一次伯努利實驗,那么兩個桶必然會十分的均勻。概率分布就像上帝施的魔咒一樣,當你面對大量的桶進行很多的廣義的伯努利實驗。桶的消耗分布就會趨于一種穩(wěn)定的值。接下來我們就了解一下桶消耗分布具體什么情況:


通過采樣統(tǒng)計

31bit(20多億)的桶,平均4.18消耗


桶消耗

占比

1

14.9%

2

17.7%

3

15.7%

4

13.9%

5

11.4%

6

9.6%

7

7%

8

4.8%

9

3.2%

10

1.7%

11

0.8%

12

<0.2%

 

100億節(jié)約了1.8T內(nèi)存。相當于節(jié)約了原先的78%內(nèi)存,而且桶消耗指標遠沒有達到預(yù)計的底線值15。


對于未出現(xiàn)的桶也是存在一定量的,如果過多會導(dǎo)致規(guī)劃不準確,其實數(shù)量是符合二項分布的,對于2^30桶存儲2^32kv,不存在的桶大概有(百萬級別,影響不大):

 

Math.pow((1 - 1.0 / Math.pow(2,30)), Math.pow(2, 32)) * Math.pow(2, 30);

 

對于桶消耗不均衡的問題不必太擔心,隨著時間的推移,寫入時會對HLEN超過15的桶進行削減,根據(jù)多項式分布的原理,當實驗次數(shù)多到一定程度時,桶的分布就會趨于均勻(硬幣投擲無數(shù)次,那么正反面出現(xiàn)次數(shù)應(yīng)該是一致的),只不過我們通過expire策略削減了桶消耗,實際上對于每個桶已經(jīng)經(jīng)歷了很多的實驗發(fā)生。

8.總結(jié)

信息摘要在這種場景下不僅能節(jié)約key存儲,對齊了內(nèi)存,還能讓key按照多項式分布均勻的散列在更少量的key下面從而減少膨脹,另外無需在給key設(shè)置expire時間,也很大程度上節(jié)約了空間。


這也印證了時間換空間的基本理論,合理利用CPU租值也是需要考慮的。



●本文編號191,以后想閱讀這篇文章直接輸入191即可。

●輸入m可以獲取到文章目錄

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Redis百億級Key存儲方案
Redis中的關(guān)系查詢
Redis和Memcache有什么區(qū)別?Python基礎(chǔ)
[Redis專題]Memcache和Redis對比
搞定 Redis 數(shù)據(jù)存儲原理,別只會 set、get 了
memcache與redis有何區(qū)別,redis有哪些優(yōu)勢呢?
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服