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