這是我們依托Docker容器來(lái)構(gòu)建數(shù)據(jù)密集型產(chǎn)品AdRoll Prospecting系列文章中的第一篇。PPT。
一個(gè)數(shù)據(jù)驅(qū)動(dòng)產(chǎn)品
就在6月17號(hào),我們的一款新產(chǎn)品AdRoll Prospecting,發(fā)布了公網(wǎng)測(cè)試版。了不起的是,該產(chǎn)品是由一個(gè)六人小組,在六個(gè)月時(shí)間內(nèi),從頭開(kāi)發(fā)并且按時(shí)發(fā)布的。
該產(chǎn)品所做的實(shí)際上是市場(chǎng)營(yíng)銷(xiāo)的圣杯:AdRoll Prospecting的核心是一種大規(guī)模機(jī)器學(xué)習(xí)模型,通過(guò)對(duì)數(shù)十億Cookie進(jìn)行分析,能夠預(yù)測(cè)出誰(shuí)最有可能對(duì)您的產(chǎn)品感興趣,從而為您的企業(yè)發(fā)現(xiàn)新客戶。
現(xiàn)代化的數(shù)據(jù)驅(qū)動(dòng)產(chǎn)品AdRoll Prospecting,不單單是機(jī)器學(xué)習(xí),還提供一個(gè)易用的儀表盤(pán)(基于React.js構(gòu)建),讓您能夠詳細(xì)查看分析的效果。在幕后,我們連接了AdRoll的實(shí)時(shí)競(jìng)價(jià)引擎,還有許多檢查點(diǎn)和儀表盤(pán)用以監(jiān)控產(chǎn)品內(nèi)部的健康情況,這使得我們能夠在問(wèn)題影響客戶之前就將其解決。
借助于AdRoll之前開(kāi)發(fā)再定位廣告產(chǎn)品的經(jīng)驗(yàn),我們?cè)谌绾螛?gòu)建一種復(fù)雜系統(tǒng)上取得了共識(shí)。當(dāng)我們著手開(kāi)始AdRoll Prospecting產(chǎn)品之時(shí),我們回顧已有的經(jīng)驗(yàn)教訓(xùn),在不犧牲健壯性和成本前提下,如何對(duì)此類(lèi)大規(guī)模數(shù)據(jù)驅(qū)動(dòng)產(chǎn)品盡快建立一個(gè)靈活的并可持續(xù)發(fā)展的后端基礎(chǔ)架構(gòu)。
管理復(fù)雜度
我們對(duì)結(jié)果非常滿意,這也促成了本系列文章。它不僅使我們的開(kāi)發(fā)和發(fā)布按時(shí)完成,而且我們也計(jì)劃將現(xiàn)有工作負(fù)荷遷移到新系統(tǒng)。
新架構(gòu)最重要的功能是簡(jiǎn)單。知曉了我們誠(chéng)待解決的問(wèn)題是如此復(fù)雜,我們不想引入框架使其更加復(fù)雜,并迫使我們?cè)诖丝蚣苤泄ぷ鳌?/p>
我們的架構(gòu)是基于三個(gè)互補(bǔ)層所構(gòu)成的一個(gè)Stack,依賴于眾所周知并身經(jīng)百戰(zhàn)的組件:
在底層,我們使用AWS的Spot Instances和Auto-Scaling Groups來(lái)按需提供計(jì)算資源。數(shù)據(jù)存儲(chǔ)在AWS的簡(jiǎn)單存儲(chǔ)服務(wù)S3中。我們建立了一個(gè)簡(jiǎn)單內(nèi)部工作隊(duì)列,Quentin,所以可依據(jù)工作隊(duì)列的實(shí)際長(zhǎng)度,利用自定義的CloudWatch指標(biāo)觸發(fā)擴(kuò)縮容。
在中間層,我們使用Luigi來(lái)編排一套由相互依賴的批量作業(yè)組成的復(fù)雜關(guān)系圖,Luigi是基于Python的開(kāi)源工作流管理工具。
在最上層,每個(gè)獨(dú)立任務(wù)(批量作業(yè))均被打包成一個(gè)Docker容器。
上述Stack允許任何人使用Docker快速構(gòu)建新任務(wù),根據(jù)輸入和輸出使用Luigi定義任務(wù)間依賴關(guān)系,并使任務(wù)可在任意數(shù)量的EC2實(shí)例上執(zhí)行,而無(wú)須考慮服務(wù)供應(yīng)(這要感謝我們的調(diào)度和自動(dòng)擴(kuò)縮容組),如下圖所示。
這一簡(jiǎn)單的架構(gòu)使大量復(fù)雜性可被很好的管理起來(lái)。Docker容器封裝了用7種不同語(yǔ)言實(shí)現(xiàn)的批量作業(yè)。Luigi用來(lái)編排約50種作業(yè)緊密相連的關(guān)系圖,Quentin和Auto-Scaling Groups(自動(dòng)擴(kuò)縮容組)技術(shù),允許我們?cè)趶椥缘臄?shù)百臺(tái)大規(guī)模EC2 Spot Instances實(shí)例上,以最為經(jīng)濟(jì)的方式執(zhí)行作業(yè)。
擁抱這一錯(cuò)綜復(fù)雜、集市化方式的最大好處是我們可以安全的為每個(gè)任務(wù)選用最適合的語(yǔ)言,實(shí)例類(lèi)型和分布式模式。
舊新范式
將批量作業(yè)容器化已經(jīng)使用了幾十年。早在上世紀(jì)60年代,在大型機(jī)上就已率先使用批量作業(yè)和虛擬化技術(shù)了。此外在本世紀(jì)初,谷歌使用操作系統(tǒng)級(jí)的虛擬化技術(shù)(谷歌內(nèi)部系統(tǒng)Borg)隔離批量作業(yè)。若干年后,使用開(kāi)源軟件如OpenVZ和LXC,這種方法廣泛流行起來(lái),后來(lái)又有了管理服務(wù),例如基于Solaris Zones的Joyent Manta。
容器技術(shù)解決了批處理中的三個(gè)棘手問(wèn)題,即:
作業(yè)打包– 一個(gè)作業(yè)可能依賴于眾多的第三方庫(kù),而這些庫(kù)也有自己的依賴包。特別是,如果作業(yè)是腳本語(yǔ)言如Python或R編寫(xiě)的,封裝整個(gè)環(huán)境在一個(gè)獨(dú)立包中的意義非凡。
作業(yè)部署– 打包好的作業(yè)需要在主機(jī)上部署,且需要在不改變系統(tǒng)資源情況下被順暢地執(zhí)行。
資源隔離– 如果多個(gè)作業(yè)在同一主機(jī)上被同時(shí)執(zhí)行,它們必須共享資源且不能相互干擾。
在Docker出現(xiàn)之前,這些問(wèn)題使用已有的虛擬化技術(shù)都可以解決,且有幾十年了。什么原因Docker如此成功?Docker的出現(xiàn)使得創(chuàng)建容器非常容易并被大眾接受,現(xiàn)在每個(gè)分析師,數(shù)據(jù)科學(xué)家,初級(jí)軟件工程師都可以使用筆記本電腦在容器里打包他們的程序。
這樣做的結(jié)果是,我們可以允許并鼓勵(lì)每個(gè)系統(tǒng)用戶使用他們最喜愛(ài)的,最適合的工具完成作業(yè),而不必學(xué)習(xí)一種新語(yǔ)言或是MapReduce等計(jì)算模型,怎么高效怎么來(lái)。每個(gè)人自然也就對(duì)他們使用Docker打包的作業(yè)負(fù)責(zé),出了問(wèn)題也在容器內(nèi)進(jìn)行修復(fù)。
其結(jié)果不僅是更快的上市時(shí)間(這要感謝使用不同技能和實(shí)戰(zhàn)工具如R語(yǔ)言帶來(lái)的高效性),也是跨組織賦權(quán)的感覺(jué)。每個(gè)人都可以訪問(wèn)數(shù)據(jù),測(cè)試新的模型,并使用他們所知道的最好的工具發(fā)布代碼到生產(chǎn)環(huán)境。
良好行為的預(yù)期
將批量作業(yè)容器化不僅是關(guān)于和平,愛(ài),和持續(xù)集成與部署。我們希望作業(yè)能夠遵循一定的規(guī)則。
大多數(shù)作業(yè)遵循的基本模式是,作業(yè)只能從S3中獲取不可變數(shù)據(jù)作為輸入,產(chǎn)生不可變數(shù)據(jù)存入S3中作為輸出。如作業(yè)堅(jiān)持這一簡(jiǎn)單模式,那此類(lèi)作業(yè)就是冪等的。
實(shí)際上,從函數(shù)式編程角度上來(lái)說(shuō),每個(gè)容器就是一個(gè)函數(shù)。在這一思路下,我們發(fā)現(xiàn),從最簡(jiǎn)單的Shell腳本到最復(fù)雜的數(shù)據(jù)處理作業(yè),很自然的就寫(xiě)好了容器化的批量作業(yè)。
另一相關(guān)要求是作業(yè)必須是原子的。我們期望,如同Hadoop一樣,作業(yè)在成功完成后,產(chǎn)生一個(gè)_SUCCESS文件。在S3中對(duì)單一文件的操作是原子的,所以這一要求很容易滿足。我們的任務(wù)依賴關(guān)系是由Luigi建立的,只有當(dāng)成功文件存在時(shí),輸出數(shù)據(jù)才被視為有效,因而部分結(jié)果并非問(wèn)題。
我們發(fā)現(xiàn)這一明確依賴S3中的文件方式,容易解釋、問(wèn)題定位和故障排除。S3是一個(gè)近乎完美的數(shù)據(jù)結(jié)構(gòu):它高度可擴(kuò)展,運(yùn)行時(shí)間有著驚人的記錄,且廉價(jià)易用。如果數(shù)據(jù)不容易被訪問(wèn),則Docker帶來(lái)的便捷性將大打折扣。
下一步:Luigi
容器化批量作業(yè)得益于關(guān)注點(diǎn)的明確劃分。這不僅使得作業(yè)編寫(xiě)變得容易了,而且也明確了每一作業(yè)執(zhí)行時(shí)間長(zhǎng)短,是幾分鐘還是最多幾小時(shí),對(duì)于利用瞬時(shí)計(jì)算服務(wù)Spot Instances來(lái)說(shuō)意義重大。
一個(gè)不可避免的結(jié)果是,系統(tǒng)變成了一個(gè)作業(yè)間相互依賴的復(fù)雜毛團(tuán)。Luigi已被證明是管理這一依賴關(guān)系圖的最直接的方式,我們將在下一篇博客中探討這一主題。
譯者介紹
Andrew,PPTV總監(jiān),樂(lè)于分享對(duì)于云計(jì)算的一些想法和對(duì)未來(lái)科技的猜想。