軟件系統(tǒng)的一大優(yōu)點(diǎn)是它們具有極強(qiáng)的適應(yīng)性。然而,在復(fù)雜軟件系統(tǒng)的演進(jìn)過程中,這種可塑性會(huì)阻礙而不是促進(jìn)其發(fā)展。在某種程度上,軟件將進(jìn)入一個(gè)不再服務(wù)于其目的——為人們提供幫助——的階段。
這就是2019年初Twitter AdServer的情況。經(jīng)過10年的迭代開發(fā)之后,系統(tǒng)的效率已經(jīng)太低,無法與組織的發(fā)展保持同步。剛開始的時(shí)候,我們是一個(gè)非常小的工程師團(tuán)隊(duì),只提供單一類型的廣告格式(推廣推文),創(chuàng)造了大約2800萬美元的收入。如今,Twitter的收入組織包括10倍以上的工程師和約30億美元的收入,支持多種廣告格式——品牌、視頻、卡片。
新產(chǎn)品發(fā)布慢,團(tuán)隊(duì)之間緊密依賴,管理成本很高,這些都增加了組織的復(fù)雜性。為了進(jìn)一步擴(kuò)大規(guī)模,我們就得進(jìn)行根本性的改革。
我們是如何投放廣告的?
AdServer漏斗(funnel)主要由Admixer和Adshard組成。Admixer是上游客戶端和AdServer管道之間的接口。當(dāng)Admixer收到一個(gè)廣告請(qǐng)求時(shí),在將請(qǐng)求分發(fā)給Adshard之前,它會(huì)將額外的用戶信息補(bǔ)充到請(qǐng)求中。Adshard在分片架構(gòu)下運(yùn)行,每個(gè)Adshard負(fù)責(zé)一個(gè)廣告子集,通過AdServer漏斗的3個(gè)主要階段運(yùn)行請(qǐng)求:
·候選項(xiàng)選擇:為用戶選擇一組有效的活動(dòng)子項(xiàng)(即一組具有相同目標(biāo)市場選擇標(biāo)準(zhǔn)的廣告;有關(guān)詳細(xì)信息,請(qǐng)參考活動(dòng)子項(xiàng)定義)。在這一階段,(1)我們應(yīng)用了所有標(biāo)準(zhǔn)的活動(dòng)目標(biāo)選擇條件,最終為用戶提供符合條件的廣告(例如地理位置、年齡、興趣等);(2)剔除用戶可能不喜歡的不相關(guān)的廣告;(3)確保我們只提供有效的廣告(例如,只提供沒有結(jié)束的活動(dòng))。
·產(chǎn)品邏輯:此階段根據(jù)一些業(yè)務(wù)規(guī)則將來自候選項(xiàng)選擇階段的每個(gè)活動(dòng)子項(xiàng)擴(kuò)展為一組創(chuàng)意,并添加額外的產(chǎn)品特性豐富這些創(chuàng)意。(創(chuàng)意是實(shí)際展示給用戶的廣告,例如一條推廣推文——請(qǐng)參考創(chuàng)意定義了解更多細(xì)節(jié))。
·候選項(xiàng)排名:完成上述階段后,對(duì)廣告進(jìn)行排名。每個(gè)廣告都會(huì)得到一個(gè)分?jǐn)?shù)(表示用戶瀏覽該廣告的可能性),并根據(jù)這個(gè)分?jǐn)?shù)對(duì)廣告進(jìn)行排名。我們使用一些實(shí)時(shí)訓(xùn)練的機(jī)器學(xué)習(xí)模型和廣告客戶數(shù)據(jù)來計(jì)算我們?cè)诟們r(jià)管道中使用的分?jǐn)?shù)。
在這個(gè)漏斗中,不同的組件還附加了與廣告請(qǐng)求和廣告候選相關(guān)聯(lián)的元數(shù)據(jù),并會(huì)將這些元數(shù)據(jù)寫入AdMixer中我們的底層鍵值存儲(chǔ)中。稍后,在反饋循環(huán)中,分析管道將使用這些數(shù)據(jù),用于賬單、欺詐檢測和其他分析。
過去,我們是通過盡可能減少網(wǎng)絡(luò)跳數(shù)來優(yōu)化系統(tǒng),以最小化延遲和操作開銷。這導(dǎo)致單個(gè)服務(wù)(即Adshard)完成了大部分繁重的工作,進(jìn)而形成了一個(gè)單體模型。
熵增
當(dāng)Twitter只有兩種廣告產(chǎn)品——推廣推文和推廣賬戶時(shí),這個(gè)單體平臺(tái)運(yùn)行得很好。然而,當(dāng)我們擴(kuò)大業(yè)務(wù)時(shí),單體模式帶來的挑戰(zhàn)便多于解決方案了。
新增一個(gè)廣告產(chǎn)品
在舊的Adserver中,由于遺留代碼的挑戰(zhàn)和復(fù)雜性,重用現(xiàn)有模式和實(shí)踐就成了常態(tài)。上圖是一個(gè)在舊的AdServer上新增一個(gè)廣告產(chǎn)品(如推廣趨勢)的例子。該廣告產(chǎn)品具有以下特點(diǎn):
1.應(yīng)該總是根據(jù)條件Geo==Country選??;
2.應(yīng)該不需要競價(jià),從而可以跳過排名階段。
通常,新增一個(gè)廣告產(chǎn)品需要做一些零零碎碎的工作??紤]到現(xiàn)有框架的性質(zhì)和其他遺留代碼的約束,跳過排名階段不是可行的選項(xiàng),于是我們采用了一種不合常規(guī)的變通方法,在排名管道里向代碼中添加基于產(chǎn)品的條件邏輯if(product_type=='PROMOTED_TREND'){...}else{..}。這種基于產(chǎn)品的邏輯也存在于選擇管道中,導(dǎo)致了這些階段緊密耦合,增加了日益增多的意大利面式代碼的復(fù)雜性。
開發(fā)速度
下面是所有基于大量的遺留代碼進(jìn)行開發(fā)的團(tuán)隊(duì)都面臨的一些挑戰(zhàn)。
·過度膨脹的數(shù)據(jù)結(jié)構(gòu):請(qǐng)求和響應(yīng)對(duì)象的大小隨著業(yè)務(wù)邏輯的增加而快速增長。由于請(qǐng)求/響應(yīng)對(duì)象在這3個(gè)階段中共享,所以不變性保證是一項(xiàng)挑戰(zhàn)。在候選排名階段添加一個(gè)新特性,需要了解該特性所需的字段在上游(選擇和創(chuàng)意階段)和下游(Admixer)是在何處如何設(shè)置的。要想修改的話,就幾乎需要了解整個(gè)服務(wù)管道。這是一個(gè)令人畏縮的過程,尤其是對(duì)新工程師來說。
·數(shù)據(jù)訪問挑戰(zhàn):從歷史上看,Admixer一直是負(fù)責(zé)獲取用戶相關(guān)數(shù)據(jù)的服務(wù),這主要是為了延遲和資源優(yōu)化。(由于采用分片架構(gòu),在Adshard中獲取相同的用戶數(shù)據(jù)需要25x RPC)。因此,要在Adshard中使用一個(gè)新屬性,我們需要在Admixer中添加相應(yīng)的用戶數(shù)據(jù)獲取器,并將其發(fā)送給Adshard。這個(gè)過程非常耗時(shí),并且,取決于用戶屬性的類型,可能會(huì)對(duì)AdServer的性能產(chǎn)生影響。這個(gè)過程也使得解耦平臺(tái)與產(chǎn)品變得非常具有挑戰(zhàn)性。
·技術(shù)債務(wù):復(fù)雜的遺留代碼增加了技術(shù)債務(wù)。棄用舊字段以及清理未使用代碼的風(fēng)險(xiǎn)越來越大。這通常會(huì)導(dǎo)致功能的意外更改,引入bug并拉低整體生產(chǎn)力。
解決方案:我們?nèi)绾卧O(shè)計(jì)這些服務(wù)
這些長期存在的工程問題以及開發(fā)人員的生產(chǎn)力損失,使得我們需要改變系統(tǒng)設(shè)計(jì)的范式。我們?cè)诩軜?gòu)中缺乏明確的關(guān)注點(diǎn)分離,并且不同的產(chǎn)品領(lǐng)域之間高度耦合。
在軟件行業(yè)中,這些問題相當(dāng)常見,而將單體分解成微服務(wù)是解決這些問題的流行方法。然而,它本身也是有利有弊,如果倉促設(shè)計(jì),反而會(huì)導(dǎo)致生產(chǎn)率降低。讓我們通過一個(gè)例子看下分解服務(wù)時(shí)可能采用的一種方法。
服務(wù)分解思考練習(xí):每個(gè)產(chǎn)品一個(gè)AdServer
由于單體AdServer對(duì)每個(gè)產(chǎn)品團(tuán)隊(duì)而言都是一個(gè)瓶頸,而不同的產(chǎn)品可能有不同的架構(gòu)需求,所以我們可以選擇將單個(gè)AdServer分解為N個(gè)不同的AdServer,每個(gè)產(chǎn)品一個(gè),或者一組類似的產(chǎn)品一個(gè)。
在上面的架構(gòu)中,我們有三個(gè)不同的AdServer,分別用于Video Ad Product、Takeover Ad Product和Performance Ad Product。它們由各自的產(chǎn)品工程團(tuán)隊(duì)負(fù)責(zé),每個(gè)團(tuán)隊(duì)都有自己的代碼庫和部署管道。這似乎提供了自主性,并有助于分離關(guān)注點(diǎn),解耦不同的產(chǎn)品領(lǐng)域,然而,實(shí)際上,這樣的分離可能會(huì)使事情變得更糟。
現(xiàn)在,每個(gè)產(chǎn)品工程團(tuán)隊(duì)都必須增加人手來維護(hù)整個(gè)AdServer。每個(gè)團(tuán)隊(duì)都必須維護(hù)和運(yùn)行自己的候選生成和候選排名管道,即使他們很少修改它們(這些通常是由機(jī)器學(xué)習(xí)領(lǐng)域?qū)<邑?fù)責(zé)修改)。對(duì)于這些領(lǐng)域,情況變得更糟?,F(xiàn)在,要發(fā)布一個(gè)用于廣告預(yù)測的新特性,我們需要修改三個(gè)不同服務(wù)的代碼,而不是一個(gè)!最后,很難確保來自所有AdServer的分析數(shù)據(jù)和日志能夠融合到一起,以確保下游系統(tǒng)的正常運(yùn)行(分析是跨產(chǎn)品的橫切關(guān)注點(diǎn))。
經(jīng)驗(yàn)總結(jié)
我們認(rèn)識(shí)到,僅僅分解是不夠的。我們?cè)谏厦鏋槊總€(gè)產(chǎn)品構(gòu)建的AdServer架構(gòu)既缺少內(nèi)聚性)(每個(gè)AdServer仍然做了太多的事情),也缺少可重用性(例如,在所有三個(gè)服務(wù)中都運(yùn)行著的廣告候選排名)。我們突然認(rèn)識(shí)到,如果我們要為產(chǎn)品工程團(tuán)隊(duì)提供自主性,就必須用可以跨產(chǎn)品重用的橫向平臺(tái)組件來為他們提供支持!為橫切關(guān)注點(diǎn)提供即插即用的服務(wù)可以為工程團(tuán)隊(duì)創(chuàng)造乘數(shù)效應(yīng)。
我們構(gòu)建了橫向平臺(tái)組件
因此,我們確定了可以被大多數(shù)廣告產(chǎn)品直接使用的“通用廣告技術(shù)功能”,包括:
·候選項(xiàng)選擇:給定用戶屬性,確定可以針對(duì)用戶需求展開競逐的廣告候選項(xiàng)。
·候選項(xiàng)排名:給定用戶屬性和廣告候選項(xiàng),根據(jù)與用戶的相關(guān)性給廣告候選項(xiàng)打分。
·回調(diào)和分析:定義契約,標(biāo)準(zhǔn)化所有提供廣告服務(wù)的服務(wù)的分析數(shù)據(jù)集。
我們圍繞這些功能構(gòu)建服務(wù),并將自己重組為平臺(tái)團(tuán)隊(duì),每個(gè)團(tuán)隊(duì)擁有其中一個(gè)功能。以前架構(gòu)中的產(chǎn)品AdServer現(xiàn)在變成了更精簡的組件,它們依賴于橫向平臺(tái)組件,并在其上構(gòu)建特定于產(chǎn)品的邏輯。
好處
便于添加新產(chǎn)品
讓我們重新審視上面提到的與聚光燈廣告有關(guān)的問題,以及新架構(gòu)如何處理這個(gè)問題。通過構(gòu)建不同的廣告候選項(xiàng)選擇服務(wù)和廣告候選項(xiàng)排名服務(wù),我們可以更好地將關(guān)注點(diǎn)分離開來。它打破了廣告產(chǎn)品必須采用AdServer管道的3階段范式這一模式。現(xiàn)在,聚光燈廣告有了靈活性,可以只與選擇服務(wù)集成,使得這些廣告可以跳過排名階段。這讓我們擺脫了為繞過推廣趨勢廣告排名而采用的笨拙方法,實(shí)現(xiàn)了一個(gè)更干凈、更健壯的代碼庫。
隨著廣告業(yè)務(wù)的持續(xù)增長,添加新產(chǎn)品將會(huì)很容易,只要在需要的時(shí)候引入這些橫向平臺(tái)服務(wù)就可以了。
提升速度
通過定義良好的API,我們可以在團(tuán)隊(duì)之間實(shí)現(xiàn)職責(zé)分離。修改候選項(xiàng)排名管道不需要理解選擇或創(chuàng)意階段。這是一種雙贏的局面,每個(gè)團(tuán)隊(duì)只需要理解和維護(hù)他們自己的代碼,這讓他們可以更快地采取行動(dòng)。這也使得故障更加容易診斷,因?yàn)槲覀兛梢愿綦x服務(wù)中的問題并獨(dú)立地測試它們。
風(fēng)險(xiǎn)與利弊
在Twitter,這種廣告模式的轉(zhuǎn)變必然會(huì)伴隨著風(fēng)險(xiǎn)和權(quán)衡。我們想列出其中一些,以提醒讀者,在決定對(duì)現(xiàn)有系統(tǒng)進(jìn)行大規(guī)模重構(gòu)之前,必須識(shí)別和承認(rèn)存在的弊端。
·增加硬件成本:從一個(gè)服務(wù)創(chuàng)建許多不同的服務(wù)無疑意味著增加運(yùn)行這些系統(tǒng)的計(jì)算成本。為了確保增長在可接受的范圍內(nèi),我們?yōu)樽约涸O(shè)定了一個(gè)具體目標(biāo),將廣告服務(wù)系統(tǒng)的運(yùn)營成本控制在收入的5%以內(nèi)。這有助于我們?cè)谛枰臅r(shí)候優(yōu)先考慮效率,讓我們更容易做出設(shè)計(jì)決策。就計(jì)算資源而言,新架構(gòu)的開銷大約是前一個(gè)架構(gòu)的兩倍,但這在我們可以接受的限度之內(nèi)。
·增加了產(chǎn)品開發(fā)團(tuán)隊(duì)的運(yùn)營成本:擁有多個(gè)新服務(wù)意味著維護(hù)和運(yùn)營這些服務(wù)的工程成本,其中一些新增的負(fù)擔(dān)落在了產(chǎn)品開發(fā)團(tuán)隊(duì)身上(而不是像之前那樣更多地落在平臺(tái)團(tuán)隊(duì)身上)。這意味著除了要加速開發(fā)新特性外,產(chǎn)品開發(fā)團(tuán)隊(duì)還需要適當(dāng)?shù)爻砷L以支持他們擁有的新系統(tǒng)。
·新特性開發(fā)的暫時(shí)放緩:這項(xiàng)工作需要花費(fèi)超過40名工程師以及工程和產(chǎn)品經(jīng)理1.5年的時(shí)間。我們估計(jì),在此期間,新特性的開發(fā)速度會(huì)降低大約15%(主要是在廣告服務(wù)方面)。為了支持這個(gè)項(xiàng)目,組織負(fù)責(zé)人會(huì)愿意做出這樣的權(quán)衡。
·競價(jià)排名的復(fù)雜性增加:這是對(duì)新架構(gòu)的技術(shù)考量——由于每個(gè)產(chǎn)品負(fù)責(zé)人都服務(wù)于自己的請(qǐng)求,我們部分失去了在更低粒度上對(duì)廣告排名和競價(jià)做出全局最優(yōu)決策的能力。通過將這種邏輯轉(zhuǎn)移到更高粒度的集中式平臺(tái)服務(wù)上,可以在某種程度上彌補(bǔ)這一點(diǎn)。
我們?cè)u(píng)估了這些風(fēng)險(xiǎn),并且確定,新架構(gòu)的好處大于這些風(fēng)險(xiǎn)造成的影響。整體開發(fā)速度的提高和更可預(yù)測的特性改進(jìn)交付,對(duì)于我們?yōu)樽约涸O(shè)定的雄心勃勃的業(yè)務(wù)目標(biāo)至關(guān)重要。新架構(gòu)提供了一個(gè)模塊化系統(tǒng),讓我們可以更快的試驗(yàn),并降低了耦合度。
我們已經(jīng)開始看到這種決策的好處了:
·對(duì)于大多數(shù)規(guī)劃好的項(xiàng)目,沒有一個(gè)團(tuán)隊(duì)會(huì)成為瓶頸,而在規(guī)劃好的廣告服務(wù)項(xiàng)目中,90%以上的都可以執(zhí)行。
·試驗(yàn)速度快了許多——在廣告服務(wù)空間進(jìn)行的在線排名試驗(yàn)現(xiàn)在快了50%。
遷移
多個(gè)團(tuán)隊(duì)每天都推送新代碼這樣一個(gè)部署節(jié)奏,再加上數(shù)十萬QPS的龐大規(guī)模,使得AdServer的分解非常具有挑戰(zhàn)性。
在開始遷移時(shí),我們采用了內(nèi)存內(nèi)API優(yōu)先的方法,對(duì)代碼進(jìn)行邏輯分離。另外,這還使我們能夠運(yùn)行一些初始的系統(tǒng)性能分析,保證與舊系統(tǒng)相比,CPU和內(nèi)存占用的增量是可接受的。這奠定了橫向平臺(tái)服務(wù)的基礎(chǔ),這些基本服務(wù)源自重構(gòu)代碼并重新安排內(nèi)存版本的打包結(jié)構(gòu)。
為了確保新舊服務(wù)在功能上的一致性,我們開發(fā)了一個(gè)自定義的正確性評(píng)估框架。它分別針對(duì)舊AdServer和新AdServer重放了請(qǐng)求,以便在可接受的閾值內(nèi)比較兩個(gè)系統(tǒng)的指標(biāo)。我們?cè)陔x線測試中使用了這種方法,借此我們可以了解新系統(tǒng)的性能。它幫助我們及早發(fā)現(xiàn)問題,防止錯(cuò)誤進(jìn)入生產(chǎn)環(huán)境。
在將代碼發(fā)送到生產(chǎn)環(huán)境后,我們使用了一個(gè)試驗(yàn)框架,讓我們可以洞察生產(chǎn)環(huán)境中的總體收益指標(biāo)。許多預(yù)測和競價(jià)相關(guān)的度量標(biāo)準(zhǔn)需要一個(gè)更長的反饋循環(huán)來消除噪音和評(píng)估變更的真實(shí)影響。因此,對(duì)于遷移的真正的端到端驗(yàn)證,我們依賴這個(gè)框架來保證收入指標(biāo)的正常。
總結(jié)
分解AdServer改善了我們系統(tǒng)的狀態(tài),強(qiáng)化了Twitter廣告業(yè)務(wù)的基礎(chǔ),讓我們可以把時(shí)間和資源集中在解決真正的工程問題上,而不是與遺留基礎(chǔ)設(shè)施的問題作斗爭。隨著廣告業(yè)務(wù)和技術(shù)的發(fā)展,更多的挑戰(zhàn)將會(huì)到來,但我們很高興能夠建立可以提高系統(tǒng)效率的解決方案。
英文原文:
https://blog.twitter.com/engineering/en_us/topics/infrastructure/2020/building-twitters-ad-platform-architecture-for-the-future.html
作者|TwitterEng?
譯者|平川
策劃|Tina