Hi茎用,大家好睬罗!我是祝威廉,本來微博也想叫祝威廉的古涧,可惜被人占了董饰,于是改名叫·祝威廉二世。然后總感覺哪里不對啄栓。目前在樂視云數(shù)據(jù)部門里從事實時計算也祠,數(shù)據(jù)平臺、搜索和推薦等多個方向堪旧。曾從事基礎(chǔ)框架奖亚,搜索研發(fā)四年昔字,大數(shù)據(jù)平臺架構(gòu)首繁、推薦三年多陨囊,個人時間現(xiàn)專注于集群自動化部署,服務(wù)管理胁塞,資源自動化調(diào)度等方向压语。
這次探討的主題是:
*** 基于 HBase 做 Storm 實時計算指標存儲 ***
HBase 實時指標存儲是我入職樂視云后對原有的實時系統(tǒng)改造的一部分无蜂。部分分享內(nèi)容其實還處于實施階段。架構(gòu)方案設(shè)計的話應(yīng)該是仁者見仁智者見智训桶,也會有很多考慮不周的地方酣倾,歡迎大家批評指正。說不定大家聽完分享后好的提議我們會用到工程上午绳,也為后面的實際課程做好準備映之。
我之前做過一次大數(shù)據(jù)的課,比較 Naive赎败,但是也包含了我對數(shù)據(jù)平臺的一些看法蠢甲。
參看:http://www.stuq.org/course/detail/999
好了鹦牛,步入正文,O(∩_∩)O~
- HBase 存儲設(shè)計
- Storm 結(jié)果如何存儲到 HBase
- HBase 寫入性能優(yōu)化
- 與傳統(tǒng)方案 (Redis/MySQL) 對比
樂視云內(nèi)部用 Storm 做 CDN窍仰,點播礼殊,直播流量的計算鲫忍,同時還有慢速比,卡頓比等統(tǒng)計指標坝辫。相應(yīng)的指標會由指標名稱近忙,業(yè)務(wù)類型,客戶未辆,地域锯玛,ISP 等多個維度組成。指標計算一個比較大的問題是 Key 的集合很大拙友。
舉個例子歼郭,假設(shè)我們有客戶 10w,計算指標假設(shè) 100 個牍蜂,5 個 ISP泰涂,30 個地域负敏,這樣就有億級以上的 Key 了,我們還要統(tǒng)計分鐘級別顶考,小時級別妖泄,天級別,月級別渊季。所以寫入量和存儲量都不小。
如果采用 Redis/Memcached 寫入速度是沒有問題的驯妄,畢竟完全的內(nèi)存操作合砂。但是 key 集合太大翩伪,其實壓力也蠻大的,我去的時候因為加了指標凛剥,結(jié)果導(dǎo)致 Memcache 被寫爆了轻姿,所以緊急做了擴容。
首先是 Redis 查起來的太麻煩盲憎「炜妫客戶端為了某個查詢慕爬,需要匯總成千上萬個 Key。磅甩。姥卢。業(yè)務(wù)方表示很蛋疼,我們也表示很蛋疼
其次僧叉,內(nèi)存是有限的棺榔,只能存當天的症歇。以前的數(shù)據(jù)需要轉(zhuǎn)存谭梗。
第三激捏,你還是繞不過持久化存儲凄吏,于是引入 MySQL,現(xiàn)在是每天一張表。那 Redis 導(dǎo)入到 MySQL 本身就麻煩盖喷。所以工作量多了难咕,查詢也麻煩,查一個月半年的數(shù)據(jù)就吐血了暮刃。
鑒于以上原因椭懊,我們就想著有沒有更合適的方案步势。
我們首先就想到了 HBase,因為 HBase 還是具有蠻強悍的寫入性功能以及優(yōu)秀的可擴展性盅抚。而事實上經(jīng)過調(diào)研倔矾,我們發(fā)現(xiàn) HBase 還是非常適合指標查詢的哪自,可以有效的通過列來減少 key 的數(shù)量。
舉個例子烫沙,我現(xiàn)在想繪制某一個視頻昨天每一分鐘的播放量的曲線圖隙笆。如果是 Redis,你很可能需要查詢 1440 個 Key瘸爽。如果是 HBase剪决,只要一條記錄就搞定。
我們現(xiàn)在上圖:
這里享言,我們一行可以追蹤某個指標一天的情況。如果加再加個維度辐董,無非增加一條記錄。而如果是 redis,可能就多了一倍偏化,也就是 2880 個 key 了镐侯。
假設(shè)該視頻是 A析孽,已經(jīng)在線上 100 天了。我們會記錄這個視頻所有的 1 分鐘播放數(shù)怜俐,用 Redis 可能有 100*1440 個 key邓尤,但是 HBase只要獲取 100 條記錄就可以找出來汞扎,我們把時間粒度轉(zhuǎn)化為了 hbase 的列,從而減少行 (Key)景鼠。
我們知道 HBase 是可以多列族,多 Column溯香,Schemaless 的玫坛。所以這里包晰,我們建了一個列族伐憾,在該列族上,直接建了 1440 個 Column蚀腿。Column 的數(shù)目和時間粒度有關(guān)扫外。如果是一分鐘粒度廓脆,會有 1440 個停忿,如果是五分鐘粒度的會有 288 個,如果是小時粒度的吮铭,會有 24 個颅停。不同的粒度癞揉,我們會建不同的表。
寫入的時候柏肪,我們可以定位到 rowkey芥牌,以及對應(yīng)的 column壁拉,這里一般不會存在并發(fā)寫。當然 HBase 的 increment 已經(jīng)解決了并發(fā)問題凤瘦,但是會造成一定的性能影響蔬芥。
查詢的時候,可根據(jù)天的區(qū)間查出一條相應(yīng)的記錄返吻。我們是直接把記錄都取出來乎婿,Column 只是一個 Int/Long 類型谢翎,所以 1440 個 Column 數(shù)據(jù)也不算大森逮。
Storm 計算這一塊,還有一個比較有意思的地方良风。假設(shè) A 指標是五分鐘粒度的闷供,也就是說我們會存儲 A 指標每個五分鐘的值歪脏。但是在實際做存儲的時候疑俭,他并不是五分鐘結(jié)束后就往 HBase 里存儲婿失,而是每隔(幾秒/或者一定條數(shù)后)就 increment 到 HBase 中移怯,然后清除重新計數(shù)。
這里其實我要強調(diào)的是葡秒,到 HBase 并不是覆蓋某個 Rowkey 特定的 Cloumn 值眯牧,而是在它原有的基礎(chǔ)上,做加法剪个。這樣做可以防止時間周期比較長的指標扣囊,其累計值不會因為有拓撲當?shù)袅硕鴣G失數(shù)據(jù)(其實還是會丟的绒疗,但可能損失的計數(shù)比較少而已)吓蘑。
丟數(shù)據(jù)比如你 kill-9 了。
大家可以想象一下溃蔫,如果我計算一個五分鐘的指標酒唉,到第三分鐘掛掉了沸移,此時累計值是 1000侄榴,接著拓撲重啟了癞蚕,五分鐘還沒完,剩下的兩分鐘它會接著累計攒射,此時是 500会放。如果是覆蓋寫钉凌,就會得到不正確的結(jié)果,實際上整個完整的計數(shù)是 1500滥搭。
防止拓撲當?shù)舨⒉皇沁@樣設(shè)計的主要原因捣鲸,還有一點是計算延時了栽惶,比如某個數(shù)據(jù)片段因為某個原因愁溜,延時了十分鐘才到 Storm 實時計算集群,這個時候新得到的值還可以加回去媒役,如果是覆蓋祝谚,數(shù)據(jù)就錯誤了。
所以 HBase 存儲這塊就變成做加法操作而不僅僅是簡單的更新了酣衷。目前 HBase 添加了計數(shù)的功能 (Increment)交惯,而另外一個比較神奇的接口設(shè)計的地方是,竟然沒有從名字上看的出是批量increment接口穿仪,一開始我以為沒有席爽,后面是去看源碼,才發(fā)現(xiàn)是有的只锻,就是batch接口,put,increment等都可以使用這種接口去批量提交紫谷,提高查詢效率齐饮。
另外 HBase 的 Client 也是非常的奇特,比如 HTablePool 竟然是對象池而不是真實的Connection連接池笤昨,多個 HTable 對象是共享一個 Connection 鏈接的祖驱。當然,這里 HTable 的 Connection 會比較復(fù)雜瞒窒,因為要連 Zookeeper 還有各個 Region捺僻。如果過多了,可能會對Zookeeper造成壓力崇裁,這倒也問題不大匕坯。
如果不使用批量接口,客戶端的寫入量死活是上不去拔稳。16 臺 32G葛峻,24 核的服務(wù)器,我做了預(yù)分區(qū) (60個左右)巴比,用了四十個進程泞歉,300 個左右的線程去寫逼侦,也就只能寫到 60000/s 而已。
但實際并發(fā)應(yīng)該是只有 40 左右的腰耙。300 個線程并沒有起到太多作用榛丢。
還有就是,HBase 的 incrementColumnValue 的性能確實不高挺庞。至少和批量 Put 差距很大晰赞。所以一定要使用Batch接口。性能可以提升很多倍选侨。
我們的測試中掖鱼,還是比較平穩(wěn)的,整個寫入狀態(tài)援制。抖動不大戏挡。
在整個過程中,有兩點要注意:
- 預(yù)分區(qū)
- rowkey的設(shè)計要滿足兩個均勻晨仑,** 數(shù)量分布均勻 **褐墅, ** 讀寫分布均勻 **。尤其是第二個均勻洪己。
預(yù)分區(qū)是要看場景的妥凳,在我們這個場景下是預(yù)分區(qū)是非常重要的。否則一開始都集中在一臺機器的一個 Regin 上寫答捕,估計很快寫的進程就都堵住了逝钥。上線就會掛。
所以我事先收集了幾天的 key拱镐,然后預(yù)先根據(jù) key 的分布做了分區(qū)艘款。我測試過,在我們的集群上沃琅,到了 60 個分區(qū)就是一個瓶頸哗咆,再加分區(qū)已經(jīng)不能提升寫入量。
寫入我們也做了些優(yōu)化阵难,因為寫的線程和 Storm 是混用的(其實就是 Storm 在寫)。我們不能堵住了 Storm芒填。這點我們是通過rowkey的設(shè)計來解決呜叫,保證寫入和讀取都能均勻的分布在HBase的各個Regin上。如果寫入出現(xiàn)問題(比如HBase出現(xiàn)堵塞)殿衰,一個可選的方案是將數(shù)據(jù)回寫到kafka,然后再起一個拓撲嘗試重新寫朱庆。第二個就是HBase的主從高可用,這個有機會以后再談闷祥。
上面的設(shè)計稿中娱颊,大家可以看到Rowkey的組成傲诵。我的建議是這樣
真實key的md5 + 時間(精確到天) + 真實的key
因為md5還是有可能碰撞,所以真實的key必須存在箱硕,這點很重要拴竹,否則一旦有碰撞,計費就出問題了剧罩。
我們總結(jié)下上面的內(nèi)容:
- Redis/Mysql 存儲方案存在的一些缺點栓拜。
- HBase 表結(jié)構(gòu)設(shè)計,充分利用了 HBase 自身的特點惠昔,有效的減少Key的數(shù)量幕与,提高查詢效率。
- Storm 寫入方案镇防,用以保證出現(xiàn)數(shù)據(jù)延時或者 Storm 拓撲當?shù)艉蟛粫?dǎo)致數(shù)據(jù)不可用啦鸣。
我們再看看整個存儲體系完整的拓撲圖。
第五個圓圈是為了在實時計算出錯時来氧,通過 Spark/MR 進行數(shù)據(jù)恢復(fù)诫给。
第二個圓圈和第四個圓圈是為了做維度復(fù)制,比如我計算了五分鐘的值饲漾,這些值其實可以自動疊加到對應(yīng)的小時和天上蝙搔。我們稱為分裂程序
第三個圓圈就是對外吐出數(shù)據(jù)了,由我們的統(tǒng)一查詢引擎對外提供支持查詢支持了考传。
我們對查詢做一個推演吃型。如果我要給用戶繪制流量的一個月曲線圖。曲線的最小粒度是小時僚楞,小時的值是取 12 個五分鐘里最高的值勤晚,我們看看需要取多少條記錄完成這個查詢。
我們需要取 31 條五分鐘的記錄泉褐,每條記錄有 288 個點赐写,對這 288 個點分成 24 份(具體就是把分鐘去掉 groupBy 一下),求出每份里的最大值(每組 SortBy 一下)膜赃,這樣就得到了 24 個值挺邀。
我取過兩天的,整個 HTTP 響應(yīng)時間可以控制 50ms 左右(本機測試)跳座。
上面的整體架構(gòu)中端铛,分裂程序是為了緩解實時寫入 HBase 的壓力,同時我們還利用 MR/Spark 做為恢復(fù)機制疲眷,如果實時計算產(chǎn)生問題禾蚕,我們可以在小時內(nèi)完成恢復(fù)操作,比如日志的收集程序狂丝、分揀程序换淆、以及格式化程序哗总。格式化程序處理完之后是 kafka,Storm 對接的是 Kafka 和 HBase倍试。
上面就是今天分享的內(nèi)容了讯屈。
感謝大家。
課程 Q&A
Q:海量存儲容災(zāi)備份怎么做易猫?
A:這個問得比較大耻煤。我只能從 HBase 的角度大概說下。HBase 是基于 HDFS 做的准颓,HDFS 本身數(shù)據(jù)就會有 replication哈蝇。通常是 3 份。所以一般機器故障是沒什么問題的攘已。但是要做到災(zāi)備炮赦,可能就要涉及到多機房問題了。比如冷備或者所謂的多活等方案样勃。
Q:祝同學(xué)現(xiàn)在的工作主要是哪些吠勘?我也是做云服務(wù)器的,想請教下以后的職業(yè)發(fā)展峡眶。
A:目前現(xiàn)階段主要工作是實時計算的架構(gòu)調(diào)整剧防,以及數(shù)據(jù)平臺的構(gòu)建,為未來的更詳細的數(shù)據(jù)分析和推薦等做好準備辫樱。云服務(wù)這塊峭拘,我覺得方向可以多參看 DaoCloud,數(shù)人科技狮暑。
深入容器技術(shù)或者資源調(diào)度鸡挠,或者整合現(xiàn)有技術(shù)做完整解決方案。在整個大數(shù)據(jù)領(lǐng)域搬男,算法工程師最吃香拣展,架構(gòu)也不錯。
Q:祝老師能介紹下架構(gòu)中數(shù)據(jù)恢復(fù)的機制么缔逛?
A:數(shù)據(jù)恢復(fù)是通過離線 MR/Spark 完成的备埃。其實就是對原始日志重新做一遍處理。這個主要是應(yīng)對實時計算出現(xiàn)故障褐奴,補錄數(shù)據(jù)用的按脚。
Q:distinctcount,是該如何計算歉糜,比如在這一個月 ip 數(shù)乘寒?
A:通過 Redis 來去重的望众。
Q:祝老師匪补,您好伞辛,對于初學(xué)者進入打數(shù)據(jù)領(lǐng)域?qū)W習,有什么建議于指導(dǎo)夯缺,是否需要這么大量的支撐蚤氏,平時可能遇不到您說的那種情況。
A:對于大數(shù)據(jù)踊兜,我覺得首先要有個一個正確的理念竿滨。這個參看我之前的課程:↓請點擊“閱讀原文”查看,第一節(jié)講的就是如何正確認識大數(shù)據(jù)捏境。通常會有五個方向:
- 平臺架構(gòu)
- 基于平臺之上的應(yīng)用開發(fā)
- 算法
- BI/可視化
- 數(shù)據(jù)分析
目前比較炙手可熱的是算法于游,薪資較高。其實各有各的挑戰(zhàn)垫言。做的好都行贰剥。除了你自己想要的做的,公司的發(fā)展其實對你的職業(yè)發(fā)展影響也會比較大筷频。
Q:老師我對您那個架構(gòu)有一個問題既然有 1在計算為啥還要有 2 和 4蚌成?
A:我們是做實時計算的。但是實時計算可能出現(xiàn)故障凛捏,比如 crash 或者有些 bug,這個時候就需要 2/4 離線補錄重算担忧。
Q:針對你們的一分鐘設(shè)計,如果列值比較復(fù)雜坯癣,比如要分析用戶數(shù)瓶盛,用戶來源,用戶 ip 等等坡锡,這個時候怎么設(shè)計表結(jié)構(gòu)蓬网?
A:用戶來源,用戶 ip 應(yīng)該設(shè)計在 key 里而不是列里鹉勒。列里存的是某個 key 在某天的某個一分鐘里產(chǎn)生的數(shù)帆锋。對于 HBase 理論上其實我也是不怕 key 多的,它本來就是為了海量存儲設(shè)計的禽额。
Q:HBase 是否適合做實時統(tǒng)計分析锯厢,比如 group by 操作如何能夠支撐高并發(fā)?
A:不適合脯倒。只適合簡單的 key 查詢或者 rowkey 的 range 查詢实辑。我不建議在其之上做復(fù)雜運算。
Q:祝老師您好藻丢,我最近要一個協(xié)處理器的功能剪撬,但是業(yè)務(wù)需要區(qū)別 hbase 的新增和更新,我在 Google 找到 incrementcolumnvalue 可以做到悠反,但是目前并沒有試成功残黑,請問您有沒有這方面的經(jīng)驗或者建議呢馍佑?謝謝!
A:無法使用是版本問題么梨水?incrementcolumnvalue 就是新增拭荤,不存在則視初始值為 0,并且它會直接返回新增后的結(jié)果值疫诽,并且能保證原子操作舅世。