打造100億SDK覆蓋量的大數(shù)據(jù)系統(tǒng)喷舀,個(gè)推從離線到實(shí)時(shí)演進(jìn)的三階段 | 36大數(shù)據(jù)
http://www.36dsj.com/archives/58518
基礎(chǔ)建設(shè)階段個(gè)推完成幾項(xiàng)工作:采用Lambda架構(gòu)(Batch Layer脖阵、Speed Layer瞬女、ServingLayer);引入Hadoop(Hdfs淡溯、Hive/MR、Hbase械荷、Mahout等);采用ES、SolrCloud+ HBase方案 實(shí)現(xiàn)多維度檢索;引入Flume 、Kafka朗徊、Camus和優(yōu)化改造日志傳輸和引入和優(yōu)化國(guó)產(chǎn)開源的Redis集群方案-Codis 。
大數(shù)據(jù)系統(tǒng)的Lambda架構(gòu) - 推酷
http://www.tuicool.com/articles/uiyYFf
Nathan Marz的大作Big Data: Principles and best practices of scalable real-time data systems介紹了Labmda Architecture的概念偎漫,用于在大數(shù)據(jù)架構(gòu)中爷恳,如何讓real-time與batch job更好地結(jié)合起來,以達(dá)成對(duì)大數(shù)據(jù)的實(shí)時(shí)處理象踊。
傳統(tǒng)系統(tǒng)的問題
在傳統(tǒng)數(shù)據(jù)庫的設(shè)計(jì)中温亲,無法很好地支持系統(tǒng)的可伸縮性。當(dāng)用戶訪問量增加時(shí)杯矩,數(shù)據(jù)庫無法滿足日益增長(zhǎng)的用戶請(qǐng)求負(fù)載栈虚,從而導(dǎo)致數(shù)據(jù)庫服務(wù)器無法及時(shí)響應(yīng)用戶請(qǐng)求,出現(xiàn)超時(shí)錯(cuò)誤史隆。
解決的辦法是在Web服務(wù)器與數(shù)據(jù)庫之間增加一個(gè)異步處理的隊(duì)列魂务。如下圖所示:
當(dāng)Web Server收到頁面請(qǐng)求時(shí),會(huì)將消息添加到隊(duì)列中逆害。在DB端头镊,創(chuàng)建一個(gè)Worker定期從隊(duì)列中取出消息進(jìn)行處理,例如每次讀取100條消息魄幕。這相當(dāng)于在兩者之間建立了一個(gè)緩沖相艇。
但是,這一方案并沒有從本質(zhì)上解決數(shù)據(jù)庫overload的問題纯陨,且當(dāng)worker無法跟上writer的請(qǐng)求時(shí)坛芽,就需要增加多個(gè)worker并發(fā)執(zhí)行,數(shù)據(jù)庫又將再次成為響應(yīng)請(qǐng)求的瓶頸翼抠。一個(gè)解決辦法是對(duì)數(shù)據(jù)庫進(jìn)行分區(qū)(horizontal partitioning或者sharding)咙轩。分區(qū)的方式通常以Hash值作為key。這樣就需要應(yīng)用程序端知道如何去尋找每個(gè)key所在的分區(qū)阴颖。
問題仍然會(huì)隨著用戶請(qǐng)求的增加接踵而來活喊。當(dāng)之前的分區(qū)無法滿足負(fù)載時(shí),就需要增加更多分區(qū)量愧,這時(shí)就需要對(duì)數(shù)據(jù)庫進(jìn)行reshard钾菊。resharding的工作非常耗時(shí)而痛苦帅矗,因?yàn)樾枰獏f(xié)調(diào)很多工作,例如數(shù)據(jù)的遷移煞烫、更新客戶端訪問的分區(qū)地址浑此,更新應(yīng)用程序代碼。如果系統(tǒng)本身還提供了在線訪問服務(wù)滞详,對(duì)運(yùn)維的要求就更高凛俱。稍有不慎,就可能導(dǎo)致數(shù)據(jù)寫到錯(cuò)誤的分區(qū)料饥,因此必須要編寫腳本來自動(dòng)完成蒲犬,且需要充分的測(cè)試。
即使分區(qū)能夠解決數(shù)據(jù)庫負(fù)載問題岸啡,卻還存在容錯(cuò)性(Fault-Tolerance)的問題暖哨。解決辦法:
改變queue/worker的實(shí)現(xiàn)。當(dāng)消息發(fā)送給不可用的分區(qū)時(shí)凰狞,將消息放到“pending”隊(duì)列,然后每隔一段時(shí)間對(duì)pending隊(duì)列中的消息進(jìn)行處理沛慢。
使用數(shù)據(jù)庫的replication功能赡若,為每個(gè)分區(qū)增加slave。
問題并沒有得到完美地解決团甲。假設(shè)系統(tǒng)出現(xiàn)問題逾冬,例如在應(yīng)用系統(tǒng)代碼端不小心引入了一個(gè)bug,使得對(duì)頁面的請(qǐng)求重復(fù)提交了一次躺苦,這就導(dǎo)致了重復(fù)的請(qǐng)求數(shù)據(jù)身腻。糟糕的是,直到24小時(shí)之后才發(fā)現(xiàn)了該問題匹厘,此時(shí)對(duì)數(shù)據(jù)的破壞已經(jīng)造成了嘀趟。即使每周的數(shù)據(jù)備份也無法解決此問題,因?yàn)樗恢赖降资悄男?shù)據(jù)受到了破壞(corrupiton)愈诚。由于人為錯(cuò)誤總是不可避免的她按,我們?cè)诩軜?gòu)時(shí)應(yīng)該如何規(guī)避此問題?
現(xiàn)在炕柔,架構(gòu)變得越來越復(fù)雜酌泰,增加了隊(duì)列、分區(qū)匕累、復(fù)制陵刹、重分區(qū)腳本(resharding scripts)。應(yīng)用程序還需要了解數(shù)據(jù)庫的schema欢嘿,并能訪問到正確的分區(qū)衰琐。問題在于:數(shù)據(jù)庫對(duì)于分區(qū)是不了解的也糊,無法幫助你應(yīng)對(duì)分區(qū)、復(fù)制與分布式查詢碘耳。最糟糕的問題是系統(tǒng)并沒有為人為錯(cuò)誤進(jìn)行工程設(shè)計(jì)显设,僅靠備份是不能治本的。歸根結(jié)底辛辨,系統(tǒng)還需要限制因?yàn)槿藶殄e(cuò)誤導(dǎo)致的破壞捕捂。
數(shù)據(jù)系統(tǒng)的概念
大數(shù)據(jù)處理技術(shù)需要解決這種可伸縮性與復(fù)雜性。首先要認(rèn)識(shí)到這種分布式的本質(zhì)斗搞,要很好地處理分區(qū)與復(fù)制指攒,不會(huì)導(dǎo)致錯(cuò)誤分區(qū)引起查詢失敗,而是要將這些邏輯內(nèi)化到數(shù)據(jù)庫中僻焚。當(dāng)需要擴(kuò)展系統(tǒng)時(shí)允悦,可以非常方便地增加節(jié)點(diǎn),系統(tǒng)也能夠針對(duì)新節(jié)點(diǎn)進(jìn)行rebalance虑啤。
其次是要讓數(shù)據(jù)成為不可變的隙弛。原始數(shù)據(jù)永遠(yuǎn)都不能被修改,這樣即使犯了錯(cuò)誤狞山,寫了錯(cuò)誤數(shù)據(jù)全闷,原來好的數(shù)據(jù)并不會(huì)受到破壞。
何謂“數(shù)據(jù)系統(tǒng)”萍启?Nathan Marz認(rèn)為:
如果數(shù)據(jù)系統(tǒng)通過查找過去的數(shù)據(jù)去回答問題总珠,則通常需要訪問整個(gè)數(shù)據(jù)集。
因此可以給data system的最通用的定義:
Query = function(all data)
接下來勘纯,本書作者介紹了Big Data System所需具備的屬性:
健壯性和容錯(cuò)性(Robustness和Fault Tolerance)
低延遲的讀與更新(Low Latency reads and updates)
可伸縮性(Scalability)
通用性(Generalization)
可擴(kuò)展性(Extensibility)
內(nèi)置查詢(Ad hoc queries)
維護(hù)最芯址(Minimal maintenance)
可調(diào)試性(Debuggability)
Lambda架構(gòu)
Lambda架構(gòu)的主要思想就是將大數(shù)據(jù)系統(tǒng)構(gòu)建為多個(gè)層次,如下圖所示:
理想狀態(tài)下驳遵,任何數(shù)據(jù)訪問都可以從表達(dá)式 Query = function(all data)
開始淫奔,但是,若數(shù)據(jù)達(dá)到相當(dāng)大的一個(gè)級(jí)別(例如PB)超埋,且還需要支持實(shí)時(shí)查詢時(shí)搏讶,就需要耗費(fèi)非常龐大的資源。
一個(gè)解決方式是預(yù)運(yùn)算查詢函數(shù)(precomputed query funciton)霍殴。書中將這種預(yù)運(yùn)算查詢函數(shù)稱之為 Batch View 媒惕,這樣當(dāng)需要執(zhí)行查詢時(shí),可以從Batch View中讀取結(jié)果来庭。這樣一個(gè)預(yù)先運(yùn)算好的View是可以建立索引的妒蔚,因而可以支持隨機(jī)讀取。于是系統(tǒng)就變成:
batch view = function(all data)query = function(batch view)
Batch Layer
在Lambda架構(gòu)中,實(shí)現(xiàn) batch view = function(all data)
的部分被稱之為 batch layer 肴盏。它承擔(dān)了兩個(gè)職責(zé):
存儲(chǔ)Master Dataset科盛,這是一個(gè)不變的持續(xù)增長(zhǎng)的數(shù)據(jù)集
針對(duì)這個(gè)Master Dataset進(jìn)行預(yù)運(yùn)算
顯然,Batch Layer執(zhí)行的是批量處理菜皂,例如Hadoop或者Spark支持的Map-Reduce方式贞绵。 它的執(zhí)行方式可以用一段偽代碼來表示:
function runBatchLayer(): while (true): recomputeBatchViews()
例如這樣一段代碼:
Api.execute(Api.hfsSeqfile("/tmp/pageview-counts"), new Subquery("?url", "?count") .predicate(Api.hfsSeqfile("/data/pageviews"), "?url", "?user", "?timestamp") .predicate(new Count(), "?count");
代碼并行地對(duì)hdfs文件夾下的page views進(jìn)行統(tǒng)計(jì)(count),合并結(jié)果恍飘,并將最終結(jié)果保存在pageview-counts文件夾下榨崩。
利用Batch Layer進(jìn)行預(yù)運(yùn)算的作用實(shí)際上就是將大數(shù)據(jù)變小,從而有效地利用資源章母,改善實(shí)時(shí)查詢的性能母蛛。但這里有一個(gè)前提,就是我們需要預(yù)先知道查詢需要的數(shù)據(jù)乳怎,如此才能在Batch Layer中安排執(zhí)行計(jì)劃彩郊,定期對(duì)數(shù)據(jù)進(jìn)行批量處理。此外蚪缀,還要求這些預(yù)運(yùn)算的統(tǒng)計(jì)數(shù)據(jù)是支持合并(merge)的秫逝。
Serving Layer
Batch Layer通過對(duì)master dataset執(zhí)行查詢獲得了batch view,而Serving Layer就要負(fù)責(zé)對(duì)batch view進(jìn)行操作询枚,從而為最終的實(shí)時(shí)查詢提供支撐筷登。因此Serving Layer的職責(zé)包含:
對(duì)batch view的隨機(jī)訪問
更新batch view
Serving Layer應(yīng)該是一個(gè)專用的分布式數(shù)據(jù)庫,例如Elephant DB哩盲,以支持對(duì)batch view的加載、隨機(jī)讀取以及更新狈醉。注意廉油,它并不支持對(duì)batch view的隨機(jī)寫,因?yàn)殡S機(jī)寫會(huì)為數(shù)據(jù)庫引來許多復(fù)雜性苗傅。簡(jiǎn)單的特性才能使系統(tǒng)變得更健壯抒线、可預(yù)測(cè)、易配置渣慕,也易于運(yùn)維嘶炭。
Speed Layer
只要batch layer完成對(duì)batch view的預(yù)計(jì)算,serving layer就會(huì)對(duì)其進(jìn)行更新逊桦。這意味著在運(yùn)行預(yù)計(jì)算時(shí)進(jìn)入的數(shù)據(jù)不會(huì)馬上呈現(xiàn)到batch view中眨猎。這對(duì)于要求完全實(shí)時(shí)的數(shù)據(jù)系統(tǒng)而言是不能接受的。要解決這個(gè)問題强经,就要通過speed layer睡陪。從對(duì)數(shù)據(jù)的處理來看,speed layer與batch layer非常相似,它們之間最大的區(qū)別是前者只處理最近的數(shù)據(jù)兰迫,后者則要處理所有的數(shù)據(jù)信殊。另一個(gè)區(qū)別是為了滿足最小的延遲,speed layer并不會(huì)在同一時(shí)間讀取所有的新數(shù)據(jù)汁果,相反涡拘,它會(huì)在接收到新數(shù)據(jù)時(shí),更新realtime view据德,而不會(huì)像batch layer那樣重新運(yùn)算整個(gè)view鳄乏。speed layer是一種增量的計(jì)算,而非重新運(yùn)算(recomputation)晋控。
因而汞窗,Speed Layer的作用包括:
對(duì)更新到serving layer帶來的高延遲的一種補(bǔ)充
快速、增量的算法
最終Batch Layer會(huì)覆蓋speed layer
Speed Layer的等式表達(dá)如下所示:
realtime view = function(realtime view, new data)
注意赡译,realtime view是基于新數(shù)據(jù)和已有的realtime view仲吏。
總結(jié)下來,Lambda架構(gòu)就是如下的三個(gè)等式:
batch view = function(all data)realtime view = function(realtime view, new data)query = function(batch view . realtime view)
整個(gè)Lambda架構(gòu)如下圖所示:
基于Lambda架構(gòu)蝌焚,一旦數(shù)據(jù)通過batch layer進(jìn)入到serving layer裹唆,在realtime view中的相應(yīng)結(jié)果就不再需要了。