廣告引擎平臺化演進之路

陶然陶然發表於2022-11-21

   1、平臺背景

  廣告是網際網路最常見的商業模式,幾乎遍佈所有的網際網路產品。網易程式化廣告團隊主要負責網易系自有流量的變現,包括網易新聞、郵箱、公開課、PC&WAP等,對外承接廣點通、穿山甲、快手等外部ADX廣告流量。變現方式包括品牌廣告、效果廣告、RTB廣告。廣告投放引擎作為流量承接和廣告決策的核心繫統也逐步進行技術的重構和迭代,在滿足業務快速發展的同時,研發了廣告引擎平臺,提供統一的檢索、計費、排序、快取記憶體、日誌和分散式通訊等基礎能力,並且先後將各個業務線遷移到了引擎平臺。這次主要介紹整體平臺化的過程以及重點服務的技術演進。

  1.1 從0到1系統搭建

  從0到1搭建系統的過程,最重要的就是要快速佈局、開發、上線。系統的初期都是進行小步快跑的迭代,但是也因此欠了不少的技術債。隨著業務的不斷髮展和壯大,衍生出了品牌廣告引擎、效果廣告引擎來承接不同場景的業務。品牌廣告主要是為KA廣告主服務,售賣方式以CPM為主,效果廣告主要是為中小廣告主服務,以點選、轉化效果為核心目標。綜合來看投放引擎基本上有以下特點:

  高併發:每天承接10億次以上的廣告請求

  高可用:因為廣告和收入相關,需要保證系統的可用性

  實時計算:實時進行廣告的召回、計費,滿足廣告主多維度定向、使用者頻次、平滑消耗等投放要求。透過演算法模型針對流量特徵對廣告進行實時排序。

  海量儲存:記錄使用者級別廣告瀏覽點選等行為資訊、海量的廣告過程日誌儲存和分析。

  1.2 平臺化系統重構

  隨著業務的發展,單體架構的引擎逐漸變得臃腫、冗餘。在業務上品牌和效果廣告雖然有所差別,但是技術上有很多可以共用的地方。結合多年廣告行業的經驗以及對於業務的理解、技術的抽象,團隊進行了廣告投放平臺的領域建模,透過基礎架構的升級改造,將單體結構的引擎升級成了分散式系統架構。主要包括以下方面:

  構建統一的服務層,提供廣告索引、計費、使用者標籤、頻次控制、排序等技術能力,使每個領域的能力都能深度發展,與業務解耦;

  各個業務線按需接入所需的服務能力,避免重複開發,統一技術架構;

  對於上層業務提供投放全鏈路的統一監控和報警能力;

  完成技術的積累和提升,使技術可以和業務並行發展,深入研究。

  平臺化的發展是以易效引擎為基礎進行迭代的,歷時半年的時間完成了平臺化的建設、服務的搭建、易效業務的遷移。整個廣告平臺的系統架構如下圖所示,主要分為:業務層、服務層、能力層和資料層。  

  業務層:易效總控,易投總控,易品總控。涵蓋了品效三條具體的業務線。其中,易投是有著10年曆史的老系統。

  服務層:索引服務、計費服務、效果服務、uts服務、頻次服務、演算法服務,為上層提供公共的服務能力。

  能力層:監控服務、配置中心、註冊中心、實驗平臺,主要是為了服務層提供更加完善的輔助能力,使得服務層更加高效和穩定。

  資料層:使用NCR、MySQL和hive等元件,提供統一資料儲存功能。

  技術架構升級完成之後,帶來了技術和業務兩方面的收益:

  機器成本:節約30%。開發成本和程式碼維護成本平均減少了50%。

  效能提升:在整個架構的演進過程中,不斷重構了業務模型,刪除老舊程式碼,最佳化各類資料結構和協議。比如易投廣告業務在接入平臺之後,廣告檢索平均耗時從原來的12ms降到了9ms。

  靈活高效:在整個架構、業務重構的過程中,我們將各個業務線的個性元素抽象成可配置廣告策略,共性元素下沉到服務層,更好地支援業務層的靈活變動。

  各個服務可以各自進行技術演進,這個也是平臺化建設的重點。平臺化之後,每個服務可以脫離語言、技術和平臺等限制,分別演進,更好地為業務發展保駕護航。

  平臺化搭建完成之後,我們又將有10年曆史的CPD投放系統接入了引擎平臺,依託於引擎平臺提供的通用技術能力,解決了這個系統不可維護、開發效率低、伺服器資源佔用多等問題。截止到目前,所有投放引擎的廣告投放都是基於引擎平臺提供的服務來完成的,達到了資源最大化的複用,以及保證了各個系統的穩定。在引擎平臺下各個服務的縱向深度進化,主要包括:索引服務、使用者標籤服務、監控服務。

   2、引擎平臺主要服務能力

  2.1 索引服務

  廣告索引服務主要功能是提供實時廣告召回。擁有一個高效能、高可用的索引服務是廣告平臺最基本的要求之一。在廣告業務中,該服務主要提供倒排檢索和正排檢索兩個功能。倒排檢索:透過輸入廣告請求的使用者、位置資訊等相關特徵,返回一批符合條件的廣告素材。正排檢索:輸入廣告素材id,返回該廣告的物料、監測等資訊。

  索引服務需要解決的問題就是如何保證在大流量、海量資料下的廣告資料查詢、更新和儲存。索引服務是我們廣告平臺中的重點專案之一,為了不斷最佳化效能、將功能檢索能力下沉,我們對該服務進行了多次的技術升級。

  2.1.1 索引服務v1 :服務抽象和平臺能力建設

  最初,品牌廣告和效果廣告因為業務需求的不同是分開部署和開發的,都有自己的基於記憶體的索引模組,造成了很多功能的重複開發,所以就產生了構建統一索引服務的想法:如果能開發一個索引服務提供給上層業務呼叫,那麼人力和運營成本都將大大減少。為此,我們將在梳理各個業務方的需求之後,將該服務拆分出來,那就是索引服務v1。整個索引服務v1主要有兩個角色,分別是queryNode和updateNode。

  queryNode:負責提供廣告檢索功能,以叢集方式部署。主要提供廣告檢索功能。為了保證高效的水平擴/縮容、該角色被設計成無狀態的服務。並且採用bitset作為儲存結構,bitsit做交、並等操作使用位運算,並且佔用空間非常小,保證倒排查詢的效率。

  updateNode:負責資料同步、資料結構打平和索引建立,同時負責排程queryNode讀取索引資料。 主要解決廣告資料更新的問題。在業務中,我們發現不同的廣告資訊,對於資料的實時性的要求是不一樣的。比如投放狀態這類相關的屬性欄位,對於實時性有較高的要求。但是有些資訊,比如投放條件等,用於廣告召回的欄位,對於實時性要求不高。所以,我們採用分而治之的策略去解決這個問題。首先,對於實時性要求高的欄位,我們稱之為屬性欄位,我們可以直接修改正排,毫秒級就能生效。其次,對於第二種實時性要求沒有那麼高的欄位,我們稱之為索引欄位,我們透過修改倒排資訊,定期重建倒排索引,來使它生效。

  兩個角色接入配置中心和註冊中心。註冊中心接入主要是為了updateNode對於queryNode的排程,其中包括健康檢查,索引更新通知等等。比如流量突然增大,需要加機器,我們只需要在新機器上啟動queryNode,它就會自動註冊到服務中心,此時updateNode便可感知到它,開始對它開始進行排程,從而使得提供廣告檢索服務,從而做到平滑擴容。整體的架構如下圖所示:  

  索引服務v1除了將索引功能抽取出來之外,為了更好地支撐廣告業務高速發展,還提供了統一增量更新、資料備份、廣告追蹤等功能,透過索引服務能力的建設,使品牌和效果產品線的總控服務得到了簡化,索引服務提供的能力可以同時支撐多條業務線,節省了開發資源。但經過業務的迭代發現了v1版本的幾個問題:

  資料同步、索引建立都是和業務強耦合,接入新業務時候工作量很大;

  查詢功能不夠靈活;

  效果廣告需要支撐海量資料場景,當資料膨脹後v1版本的弊端逐漸暴露;

  所以,為了解決上述的問題,我們進一步繼續索引服務v2的研發。

  2.1.2 索引服務v2 :為海量檢索場景提供技術服務能力  

  索引服務v2 主要包括queryNode叢集和es叢集,v2版本主要有以下3個特點:

  技術引入:為了支援當時的業務規劃進行海量的素材資料檢索,並且需要快速落地,引入了es叢集。透過調研,es支援海量儲存、分散式、索引的分片和副本,這樣的架構能解決1.0單機記憶體瓶頸的問題。自帶持久化功能,可以讓我們擺脫使用資料庫備份資料的困擾。

  開源擴充套件:es並不是拿來就能使用的,在某些地方達不到我們的要求。對此,我們做了些針對性最佳化,並且根據現有業務場景,在es上層完成了一系列模組擴充套件。

  業務隔離:V2另外一個重點就是將業務從索引服務中剝離出來,把業務相關的邏輯拆分成一個單獨的同步服務,這樣整個索引服務通用性更強,業務接入的效率更高。

  索引V2服務的改進主要體現在資料同步、層級索引、檢索最佳化:

  資料同步:在v1中全量同步任務效率是比較低的,因為是序列地從業務端拉取所有的資料到記憶體,如果資料量很大的情況下,耗時會很長。在V2版本中,對此進行了最佳化,將整個同步任務大致分為任務觸發,資料匯入,任務完成,三個階段。在資料匯入階段,透過並行的方式,完成廣告資料匯入。實現方式是使用多個執行緒按照分片規則,同時從儲存中讀取廣告資料,傳輸給queryNode節點,然後寫入進es,所有分片資料寫入成功之後,才會算是任務結束。耗時從2分鐘縮短到30秒以內。全量同步改成批次匯入之後,雖然效能提高了,但是任務流程的增加,會帶來一些不穩定的因素,為此我們研發了--同步任務管理功能,保證分散式任務的高可用。  

  層級索引:在資料查詢方面,在V2.0中為了保證檢索效能做了很多工作,效果最為明顯的就是層級索引和檢索流程的最佳化。透過層級索引解決了多類文件關聯查詢效能的問題,在資料同步的時候,根據配置資訊,為每條廣告資料生成文件id和父文件id,讓不同廣告實體之間建立父子關係,從而能提前建立層級索引,這樣在查詢的時候,只需要將查詢條件組裝好,一次就能將資料都查詢出來,降低了檢索耗時。  

  檢索最佳化:為了進一步縮短檢索耗時,我們簡化了es索引流程。原生檢索流程是,資料寫入es之後,會生成兩份資料,一份source_儲存原始文件,一份倒排索引。查詢的時候,查詢倒排索引獲取文件id,透過文件id去原始文件中查詢欄位資訊並返回。索引架構2.0中,queryNode需要對每個請求都透傳es返回的資訊,不僅增加沒有必要的解析工作,還因為傳輸資料變大,提高耗時。為此我們對這塊進行如下最佳化:

  禁用了source原始文件:當禁用source原始文件之後,es中只有倒排資訊,缺少原始文件資訊。為了解決這個問題,我們在建立索引之前對每條記錄,構造出一個fulldata欄位儲存原始文件,並且將其快取到queryNode中。

  透過queryNode實現正排檢索:透過文件id查詢文件欄位資訊。es返回的資料只需要將文件id返回給queryNode,然後queryNode會根據配置資訊,組裝文件資訊。大幅度降低了耗時。 這樣還有個好處就是,正排資料查詢只需要訪問queryNode,不用再訪問es叢集,在降低正排查詢耗時的同時,也減少了es叢集的壓力,一舉兩得。  

  索引服務V2上線之後,在可用性、擴充套件性和效能各個方面都有所提升,目前檢索平均耗時在10ms左右。下一步,我們會繼續研發3.0版本,結合網易廣告自身的特點,為了進一步節省資源,自研分散式檢索核心替換es,更好地支撐業務發展。

  2.2 使用者標籤服務

  使用者標籤服務(UTS)是為了廣告請求時實時獲取使用者的興趣標籤的服務,以實現廣告的精準投放,從業務角度考慮UTS服務其實很簡單,就是透過各種資料來源的使用者資訊組成使用者畫像,但是從技術角度來看,使用者標籤服務的構建是一個典型的單體架構到服務架構的應用。現階段使用者資料主要分為三大類:

  dmp資料:主要包括使用者的資訊:性別、年齡、興趣、裝置型別等等。

  人群包:根據業務策略生成人群包,完成目標人群的投放。

  廣告標籤:是廣告平臺內部生成標籤資訊,主要是根據使用者的廣告行為生成的偏好資訊,比如使用者的長期偏好、短期偏好等等。

  在平臺化之前,每條業務線都要自己單獨維護自己對於使用者標籤資料的寫入、儲存和讀取功能,這樣會有以下這些問題:

  資料種類多:由於每種資料種類,使用規則和格式都不一樣,當業務發展到較大規模時,這部分功能的接入和維護都消耗了非常大的人力和時間。

  資料與業務耦合:如果遇到底層資料服務升級、資料遷移或者協議升級,那麼每條業務線也會受到很大的影響。

  重複開發:由於引擎對接了三條業務線,有的資料在其中一條業務線落地之後,在其他業務線使用時需要進行再次開發,造成了資料對接功能重複開發。

  資源浪費:在儲存資源上沒有統一的規劃和管理,存在資源浪費的現象。  

  所以在平臺升級過程中,對於各條業務的相關使用者資訊的業務功能進行了重新梳理,目的是降低模組耦合,減少重複建設,將使用者標籤的管理和查詢功能單獨抽離出來,成為一個服務。所有的業務端(易品、易投、易效)脫離了和資料來源的耦合,所有對於資料來源的管理都由UTS統一負責接入和管理,另外UTS服務還負責標籤的路由、選取策略實現、標籤查詢。所有的資料來源都是透過配置實現的,各個業務線可以配置所需資料來源,由UTS統一負責資料的組織、加工、查詢。UTS服務的架構如下圖;  

  該系統主要分為三模組:策略模組,標籤查詢,標籤推薦。為了解決海量使用者數儲存的問題,統一將所有標籤資料都存成pb格式,利用pb效能高、相容性、壓縮比例大的優勢,節省了約30%的空間。同時UTS還接入了配置中心、AB實驗平臺,實現流量切分,對於不同的流量資源,使用不同的資料策略,挑選合適的使用者標籤。策略現在主要分為兩類:

  常規策略:UTS收到上游廣告請求時,從配置中心拉取該業務線的資料查詢規則,透過規則組合在UTS內部進行資料查詢,透過DMP或者人群包資料來源來豐富使用者的標籤資訊。

  推薦策略:根據使用者歷史廣告行為(點選、瀏覽、啟用)的資料,透過協同過濾的方式找到標籤相似度高的興趣標籤,最佳化廣告的檢索邏輯,實現效果優先。

  2.3 計費服務

  索引解決廣告召回問題,UTS解決使用者識別問題,計費服務則主要負責解決廣告的消耗能力問題。計費服務的核心問題是:減少超投,平滑消耗。所以計費服務有對外提供兩個功能用以完成控量和計費功能,分別是預算過濾和效果回收。  

  預算過濾:將請求中不符合預算限制的廣告過濾掉。這裡預算限制的策略包括:預算平均策略、平臺預算限制策略、廣告位預算分配策略、尾量控制等等,這些策略的目的就是將預算合理的分配到合適的流量上去,使得廣告主和媒體方都能收益最大化。

  效果回收:主要完成使用者觀看廣告之後產生的行為監測收集功能,需要記錄使用者的每一次請求、廣告出價、曝光、點選、轉化等等行為資料。效果回收服務每天需要承接億級別的請求,並根據行為進行使用者頻控、計費等。為了保證相關業務的可靠性,需要將使用者行為以日誌的形式存下,並且實時更新使用者的效果資料。最終透過離線+實時的方式將日誌採集到HDFS和Druid中。

  該服務中過濾模組、效果模組和預算計算模組都是以叢集方式部署,保證無單點,而且計費資料是非常重要的資料,使用多重資料備份方案,並且接入了詳細的實時監控和自動恢復機制,一定要保證服務的極高可用性。除此外,預算過濾也是廣告請求流程中的一環,對效能也有較高要求。為此,我們在實現中使用無鎖設計、多級快取等機制等等來保證耗時,目前平均耗時在1ms。

   3、服務保障與監控

  廣告投放業務是涉及到收入的核心業務,這對我們整個平臺的健壯性和監控能力提出了非常高的要求。為了保證廣告平臺上所有的廣告服務的正常執行,我們後期也對廣告平臺上的所有監控服務做出了梳理和分類,搭建了scout監控服務。目前廣告平臺上的監控主要分為三大類:系統監控,指標監控,業務監控。

  系統監控:主要包括每個服務下各個模組耗時、機器節點的CPU、記憶體等一些系統級別的監控資訊。

  指標監控:主要包括各個業務線、重點位置、重點平臺等維度的廣告請求、返回、勝出和收入等廣告業務中的一些核心指標資料。實時監控這些資料的變動,如果發現波動較大的情況,能立馬用郵件、電話、popo的方式通知相關人員。

  業務監控:主要包括對於上層業務流程的監控,比如廣告日誌欄位監控,廣告投放追蹤監控等等。本類監控和指標監控的區別在於兩點。第一,相比指標監控,業務監控更加關注過程,而指標資料更加關注結果。我們在分析投放效果的時候,光有結果資料是沒有辦法去做投放效果的最佳化和提高,需要過程資料的支撐,而且當系統出現問題的時候,一般過程資料要比結果資料更快的表現出來,從而能更加減少對於業務的損失。第二,本類監控更加貼近上層業務,會去根據不同的廣告業務模型去做跨系統的監控和分析,針對性地分析不同業務的核心產品的廣告資料,並且做好定製化的報警。讓投放過程的每一步都有據可查。  

  對於系統監控,我們直接使用集團的哨兵系統。

  對於指標監控和業務監控構建了scout監控服務。該服務以jar的方式接入到平臺上各條業務線,將採集資料傳送到kafka。之後會有叢集會去消費kafka中的資料,進行過濾、聚合等操作,將總控、索引、頻次、計費、排序等各個服務採集資料串聯起來,進行儲存和預警。此外,我們也會從Druid中拉取各類指標資料進行環比、同比的相關規則的檢查和報警。並且按照指標的不同重要性,使用不同的通知方式去報警。

   4、未來的發展

  永恆不變的就是變化,廣告業務在不停地發展,這就需要我們主動去做技術升級和架構演進,擁抱變化,時刻感知上層業務。這樣才能實實在在地解決各種的核心使用者、場景問題,而不是讓技術與業務脫節。我們最開始做服務拆分的主要目標之一,就想讓每個服務可以各自迭代,深入研究,達到“又精又專”。到目前我們也是如此在做,接下來每個服務進入了新版的迭代研發中。

  索引服務3.0 ,主要解決2.0強依賴es的問題。此外,進一步收集廣告業務其他的大資料查詢、儲存的場景,準備自研索引服務框架,提供統一的索引解決方案。

  計費服務2.0 ,目標透過調研國外論文和行業方案,引入“參競率”引數,完成預算釋放的自適應調節,最佳化計費主體流程,使得預算更加平滑,進一步減少超投。

  語言升級,考慮到廣告業務大部分都是高併發的場景,java的gc對於某些基礎服務的影響還是比較明顯。為了進一步地提高服務效能,未來我們可能會分批次,分服務地進行語言升級。對於業務敏感的服務繼續使用java,對於效能要求高的、變化不大的基礎服務,替換成go。

  最後,廣告技術團隊仍然任重而道遠,希望發揚務實、重積累、重技術的團隊文化,最終透過團隊技術能力支撐業務的快速發展。

來自 “ 網易傳媒技術團隊 ”, 原文作者:李偉、何萌鑫;原文連結:http://server.it168.com/a2022/1121/6776/000006776218.shtml,如有侵權,請聯絡管理員刪除。

相關文章