美團(tuán)最初的數(shù)據(jù)處理以Hive SQL為主,底層計(jì)算引擎為MapReduce,部分相對復(fù)雜的業(yè)務(wù)會(huì)由工程師編寫MapReduce程序?qū)崿F(xiàn)。隨著業(yè)務(wù)的發(fā)展,單純的Hive SQL查詢或者M(jìn)apReduce程序已經(jīng)越來越難以滿足數(shù)據(jù)處理和分析的需求。
一方面,MapReduce計(jì)算模型對多輪迭代的DAG作業(yè)支持不給力,每輪迭代都需要將數(shù)據(jù)落盤,極大地影響了作業(yè)執(zhí)行效率,另外只提供Map和Reduce這兩種計(jì)算因子,使得用戶在實(shí)現(xiàn)迭代式計(jì)算(比如:機(jī)器學(xué)習(xí)算法)時(shí)成本高且效率低。
另一方面,在數(shù)據(jù)倉庫的按天生產(chǎn)中,由于某些原始日志是半結(jié)構(gòu)化或者非結(jié)構(gòu)化數(shù)據(jù),因此,對其進(jìn)行清洗和轉(zhuǎn)換操作時(shí),需要結(jié)合SQL查詢以及復(fù)雜的過程式邏輯處理,這部分工作之前是由Hive SQL結(jié)合Python腳本來完成。這種方式存在效率問題,當(dāng)數(shù)據(jù)量比較大的時(shí)候,流程的運(yùn)行時(shí)間較長,這些ETL流程通常處于比較上游的位置,會(huì)直接影響到一系列下游的完成時(shí)間以及各種重要數(shù)據(jù)報(bào)表的生成。
基于以上原因,美團(tuán)在2014年的時(shí)候引入了Spark。為了充分利用現(xiàn)有Hadoop集群的資源,我們采用了Spark on Yarn模式,所有的Spark app以及MapReduce作業(yè)會(huì)通過Yarn統(tǒng)一調(diào)度執(zhí)行。Spark在美團(tuán)數(shù)據(jù)平臺架構(gòu)中的位置如圖所示:
下面將介紹Spark在美團(tuán)的實(shí)踐,包括基于Spark所做的平臺化工作以及Spark在生產(chǎn)環(huán)境下的應(yīng)用案例。其中包含Zeppelin結(jié)合的交互式開發(fā)平臺,也有使用Spark任務(wù)完成的ETL數(shù)據(jù)轉(zhuǎn)換工具,數(shù)據(jù)挖掘組基于Spark開發(fā)了特征平臺和數(shù)據(jù)挖掘平臺,另外還有基于Spark的交互式用戶行為分析系統(tǒng)以及在SEM投放服務(wù)中的應(yīng)用,以下是詳細(xì)介紹。
Spark交互式開發(fā)平臺
在推廣如何使用Spark的過程中,我們總結(jié)了用戶開發(fā)應(yīng)用的主要需求:
數(shù)據(jù)調(diào)研:在正式開發(fā)程序之前,首先需要認(rèn)識待處理的業(yè)務(wù)數(shù)據(jù),包括:數(shù)據(jù)格式,類型(若以表結(jié)構(gòu)存儲則對應(yīng)到字段類型)、存儲方式、有無臟數(shù)據(jù),甚至分析根據(jù)業(yè)務(wù)邏輯實(shí)現(xiàn)是否可能存在數(shù)據(jù)傾斜等等。這個(gè)需求十分基礎(chǔ)且重要,只有對數(shù)據(jù)有充分的掌控,才能寫出高效的Spark代碼;
代碼調(diào)試:業(yè)務(wù)的編碼實(shí)現(xiàn)很難保證一蹴而就,可能需要不斷地調(diào)試;如果每次少量的修改,測試代碼都需要經(jīng)過編譯、打包、提交線上,會(huì)對用戶的開發(fā)效率影響是非常大的;
聯(lián)合開發(fā):對于一整個(gè)業(yè)務(wù)的實(shí)現(xiàn),一般會(huì)有多方的協(xié)作,這時(shí)候需要能有一個(gè)方便的代碼和執(zhí)行結(jié)果共享的途徑,用于分享各自的想法和試驗(yàn)結(jié)論。
基于這些需求,我們調(diào)研了現(xiàn)有的開源系統(tǒng),最終選擇了Apache的孵化項(xiàng)目Zeppelin,國內(nèi)服務(wù)器租用服務(wù)器托管,將其作為基于Spark的交互式開發(fā)平臺。Zeppelin整合了Spark,Markdown,Shell,Angular等引擎,集成了數(shù)據(jù)分析和可視化等功能。
我們在原生的Zeppelin上增加了用戶登陸認(rèn)證、用戶行為日志審計(jì)、權(quán)限管理以及執(zhí)行Spark作業(yè)資源隔離,打造了一個(gè)美團(tuán)的Spark的交互式開發(fā)平臺,不同的用戶可以在該平臺上調(diào)研數(shù)據(jù)、調(diào)試程序、共享代碼和結(jié)論。
集成在Zeppelin的Spark提供了三種解釋器:Spark、Pyspark、SQL,分別適用于編寫Scala、Python、SQL代碼。對于上述的數(shù)據(jù)調(diào)研需求,無論是程序設(shè)計(jì)之初,還是編碼實(shí)現(xiàn)過程中,當(dāng)需要檢索數(shù)據(jù)信息時(shí),通過Zeppelin提供的SQL接口可以很便利的獲取到分析結(jié)果;另外,Zeppelin中Scala和Python解釋器自身的交互式特性滿足了用戶對Spark和Pyspark分步調(diào)試的需求,同時(shí)由于Zeppelin可以直接連接線上集群,因此可以滿足用戶對線上數(shù)據(jù)的讀寫處理請求;最后,Zeppelin使用Web Socket通信,用戶只需要簡單地發(fā)送要分享內(nèi)容所在的http鏈接,所有接受者就可以同步感知代碼修改,運(yùn)行結(jié)果等,實(shí)現(xiàn)多個(gè)開發(fā)者協(xié)同工作。
Spark作業(yè)ETL模板 除了提供平臺化的工具以外,我們也會(huì)從其他方面來提高用戶的開發(fā)效率,比如將類似的需求進(jìn)行封裝,提供一個(gè)統(tǒng)一的ETL模板,讓用戶可以很方便的使用Spark實(shí)現(xiàn)業(yè)務(wù)需求。
美團(tuán)目前的數(shù)據(jù)生產(chǎn)主體是通過ETL將原始的日志通過清洗、轉(zhuǎn)換等步驟后加載到Hive表中。而很多線上業(yè)務(wù)需要將Hive表里面的數(shù)據(jù)以一定的規(guī)則組成鍵值對,導(dǎo)入到Tair中,用于上層應(yīng)用快速訪問。其中大部分的需求邏輯相同,即把Hive表中幾個(gè)指定字段的值按一定的規(guī)則拼接成key值,另外幾個(gè)字段的值以json字符串的形式作為value值,最后將得到的對寫入Tair。