作者:謝健芬
Pinterest 廣告工程團(tuán)隊(duì)的宗旨是為我們的廣告合作商提供最優(yōu)質(zhì)的服務(wù)體驗(yàn),而廣告超投,是我們極力要解決的問題之一。在Pinterest,我們使用了?Kafka Streams?,可以實(shí)現(xiàn)把廣告消耗的預(yù)測數(shù)據(jù)在數(shù)秒鐘的時(shí)間內(nèi)發(fā)送給數(shù)千個(gè)廣告投放服務(wù)。本文將會(huì)先解釋什么是超投,然后分享一下我們是如何使用 Kafka Streams 構(gòu)造預(yù)測系統(tǒng)來提供近實(shí)時(shí)的預(yù)測消耗數(shù)據(jù)、從而降低超投的。
關(guān)于超投
當(dāng)廣告主的預(yù)算耗盡時(shí),如果他們的廣告被繼續(xù)投放,這多出來的投放部分將無法再進(jìn)行收費(fèi),這種現(xiàn)象被稱之為超投。超投會(huì)減少其他還有預(yù)算盈余的廣告主的廣告展現(xiàn)機(jī)會(huì),從而降低了他們的產(chǎn)品和服務(wù)觸及潛在顧客的機(jī)會(huì)。
要降低超投率,應(yīng)從兩個(gè)方面著手:
計(jì)算實(shí)時(shí)消耗:廣告曝光展示的信息應(yīng)在數(shù)秒內(nèi)反饋給廣告系統(tǒng),系統(tǒng)才能及時(shí)關(guān)閉那些已耗盡預(yù)算的廣告計(jì)劃。進(jìn)行消耗預(yù)測:除了讓已發(fā)生的消耗數(shù)據(jù)及時(shí)傳達(dá)以外,系統(tǒng)還應(yīng)具備預(yù)測未來消耗的能力,在預(yù)計(jì)某些計(jì)劃快要達(dá)到預(yù)算上限的時(shí)候,應(yīng)降低它們的投放速度,從而使計(jì)劃平滑地到達(dá)預(yù)算上限。因?yàn)橐呀?jīng)投放出去的廣告會(huì)停留在用戶界面上,用戶依然可以對它進(jìn)行操作。這種行為的滯后性會(huì)讓短時(shí)間內(nèi)的廣告消耗難以準(zhǔn)確地衡量。而這種自然延遲是不可避免的,我們唯一能確信的只有廣告投放事件。我們舉個(gè)例子來詳細(xì)說明一下。假設(shè)有一個(gè)能提供廣告投放的互聯(lián)網(wǎng)公司,廣告主X向該公司購買了出價(jià)為$0.10元/曝光?、預(yù)算為$100元/天的廣告服務(wù)。這意味著該廣告每天最多曝光1000次。
該公司為廣告主快速實(shí)現(xiàn)了一個(gè)簡單明了的投放系統(tǒng):
當(dāng)網(wǎng)站上出現(xiàn)新的廣告展現(xiàn)機(jī)會(huì)時(shí),前端會(huì)向廣告庫(ad inventory)請求一條廣告。廣告庫根據(jù)廣告主X的剩余預(yù)算來決定是否投放他們的廣告。如果預(yù)算仍然充足,廣告庫將通知前端進(jìn)行一次廣告投放(比如在用戶端APP的一個(gè)廣告位上展示出來)。當(dāng)用戶瀏覽了該廣告后,一個(gè)曝光事件會(huì)發(fā)往計(jì)費(fèi)系統(tǒng)。
然而,當(dāng)該公司檢查他們的收入時(shí),發(fā)現(xiàn)事情的進(jìn)展與預(yù)想的并不一樣。
廣告主X的廣告實(shí)際展示了1100次,由于預(yù)算只有$100,因此平均每次曝光的價(jià)格實(shí)際只有$0.09元。比計(jì)劃多出來的100次曝光相當(dāng)于是免費(fèi)投放了,而且這些曝光機(jī)會(huì)本來可以用來展示其他廣告主的廣告。這就是業(yè)界常談的超投問題。
那么為什么會(huì)發(fā)生超投?在這個(gè)例子中,我們假設(shè)是由于結(jié)算系統(tǒng)的響應(yīng)時(shí)間太長所導(dǎo)致的。假設(shè)系統(tǒng)對一次曝光的處理有5分鐘的延遲,從而導(dǎo)致了超投。因此,這個(gè)互聯(lián)網(wǎng)公司采取了一些優(yōu)化手段來提高了系統(tǒng)性能,結(jié)果成功地多賺了$9元!因?yàn)樗言?00次無效曝光中的90次讓給了其他預(yù)算充足的廣告主,從而把超投率降低到10/1000 = 1%。
不久之后,另一位廣告主Y也聯(lián)系了這家公司,并希望以$100元/天的預(yù)算、$2.0元/點(diǎn)擊(例如,一個(gè)用戶通過點(diǎn)擊廣告鏈接到達(dá)廣告主Y自己的網(wǎng)站)、最多每天50次點(diǎn)擊的價(jià)格購買廣告。這家公司把廣告主Y加到他們的廣告投放流程里,并在他們的系統(tǒng)增加了點(diǎn)擊事件的跟蹤。
一天下來,這家公司的廣告系統(tǒng)再次發(fā)生了超投。
結(jié)算下來,廣告主Y竟然得到了10個(gè)免費(fèi)點(diǎn)擊!而這家互聯(lián)網(wǎng)公司發(fā)現(xiàn),即使結(jié)算系統(tǒng)處理速度足夠快,但卻無法預(yù)知一個(gè)投放出去的廣告是否會(huì)被點(diǎn)擊,由于缺乏這些未來的消耗信息,超投將永遠(yuǎn)都無法避免。
本例子中的主人公最后找到了一個(gè)非常聰明的解決辦法:給每個(gè)廣告主計(jì)算預(yù)測消耗。預(yù)測消耗指的是已經(jīng)投放出去了但尚未發(fā)生消耗的那部分。如果實(shí)際消耗+預(yù)測消耗>每日預(yù)算,則停止該廣告主的廣告投放。
構(gòu)建預(yù)測系統(tǒng)
初衷
我們的用戶每天在Pinterest上進(jìn)行瀏覽以獲取新的靈感:從個(gè)性化推薦,到搜索,再到運(yùn)營推薦位。我們需要構(gòu)建一個(gè)兼具可靠性和可擴(kuò)展性的廣告系統(tǒng)來進(jìn)行廣告投放,并確保利用好我們廣告主的每一筆預(yù)算。
需求
我們著手設(shè)計(jì)了一個(gè)消耗預(yù)測系統(tǒng),系統(tǒng)目標(biāo)如下:
能處理不同的廣告類型(曝光、點(diǎn)擊)必須具備每秒能處理數(shù)以萬計(jì)的事件的能力能向超過1000個(gè)消費(fèi)者廣播更新消息端到端的延遲不能超過10秒保證100%的運(yùn)行時(shí)間(Uptime)在工程上應(yīng)盡量保持輕量和可維護(hù)性為什么選擇Kafka Streams
我們評估過不同類型的流式服務(wù),其中也包括?Spark?和?Flink?。這些技術(shù)在數(shù)據(jù)規(guī)模上都能滿足我們的要求,但對我們來說,Kafka Streams還具備了一些特殊的優(yōu)勢:
毫秒級延遲:Kafka Streams提供毫秒級的延遲保證,這一點(diǎn)是Spark和Flink做不到的輕量:Kafka Streams是一個(gè)沒有重度外部依賴(比如專用集群)的Java應(yīng)用,這會(huì)減輕我們的維護(hù)成本。具體實(shí)施
下圖在高層次上展示了加入了消耗預(yù)測之后的系統(tǒng)結(jié)構(gòu):
廣告投放系統(tǒng)(Ads serving):負(fù)責(zé)分發(fā)廣告到用戶端、記錄廣告投放、并從消耗預(yù)測服務(wù)(”inflight spend” service)中獲取預(yù)測消耗數(shù)據(jù)。結(jié)算系統(tǒng)(Spend system):對廣告事件進(jìn)行聚合并把每個(gè)廣告主的當(dāng)前消耗信息告知給廣告投放系統(tǒng)。消耗預(yù)測服務(wù)(Inflight spend):廣告投放記錄(Ad insertion input):每發(fā)生一次投放,投放系統(tǒng)應(yīng)向“input” topic發(fā)送如下消息:{key: adgroupId, value: inflight_spend},其中:adgroupId是指在相同的預(yù)算約束下的廣告組的idinflight_spend = price * impression_rate * action_rate,其中:price: 當(dāng)前廣告的出價(jià)impression_rate:廣告從投放到曝光的轉(zhuǎn)化率的歷史經(jīng)驗(yàn)值。注意并不是每次投放的廣告都一定能被曝光給用戶action_rate:對按點(diǎn)擊付費(fèi)的廣告主來說,這表示用戶點(diǎn)擊這條廣告的概率;對按曝光付費(fèi)的廣告主來說,這個(gè)值為1消耗聚合器(spend aggregator):訂閱 “input” topic 并利用Kafka Streams對每個(gè) adgroup 進(jìn)行消耗數(shù)據(jù)的聚合。我們使用了一個(gè)10秒的窗口(window) 來計(jì)算每個(gè) adgroup 的預(yù)測消耗。而“output” topic會(huì)被投放系統(tǒng)進(jìn)行消費(fèi),當(dāng)收到新的消息時(shí),投放系統(tǒng)會(huì)更新預(yù)測消耗的數(shù)據(jù)。在實(shí)際應(yīng)用中,我們的消耗預(yù)測的準(zhǔn)確率非常高。在整個(gè)預(yù)算預(yù)測系統(tǒng)上線之后,我們的超投率明顯下降了。下圖是我們的實(shí)際消耗與預(yù)測消耗的一個(gè)對比測試結(jié)果樣例。
說明:圖中的橫軸是以3分鐘為單位的時(shí)間軸;縱軸表示單位時(shí)間內(nèi)的消耗。其中藍(lán)線表示預(yù)測消耗,綠線表示實(shí)際消耗
一些經(jīng)驗(yàn)
窗口(Window)如果取得不好會(huì)嚴(yán)重影響性能。我們在使?jié)L動(dòng)窗口(tumbling ?windows)代替原有的跳躍窗口(hopping windows)后得到了18倍的性能提升。最初我們的實(shí)現(xiàn)是使用跳躍窗口去計(jì)算3分鐘內(nèi)的預(yù)測消耗。在我們的實(shí)際案例中,一個(gè)窗口的大小是3分鐘,前進(jìn)步長是10秒,這樣就會(huì)產(chǎn)生180秒 / 10秒 = 18個(gè)開放窗口。每一個(gè)通過Kafka Streams處理的事件會(huì)同時(shí)更新到18個(gè)窗口中,導(dǎo)致很多不必要的計(jì)算。為了解決這個(gè)問題,我們把跳躍窗口改成了滾動(dòng)窗口。相比起跳躍窗口,滾動(dòng)窗口的特點(diǎn)是每個(gè)窗口之間不會(huì)互相重疊,意味著每收到一個(gè)事件只需要更新一個(gè)窗口就可以了。因?yàn)榘迅虏僮鲝?8減到了1,因此這個(gè)窗口類型更換的操作使整體吞吐量增加了18倍。信息壓縮策略:為了降低對消費(fèi)者廣播的數(shù)據(jù)量,我們對 adgroup ID進(jìn)行了差分編碼,并使用查找表存儲消耗數(shù)據(jù)。經(jīng)過壓縮后,我們把信息傳輸大小壓縮到原有的四分之一。結(jié)論
使用Apache Kafka Streams來構(gòu)建預(yù)測消耗系統(tǒng)是我們廣告基礎(chǔ)組件的一個(gè)新的嘗試,而該系統(tǒng)也達(dá)到了高效、穩(wěn)定、高容錯(cuò)與可擴(kuò)展的要求。我們計(jì)劃在未來將會(huì)持續(xù)探索由Confluent推出的?Kafka 1.0?和?KSQL?并應(yīng)用到系統(tǒng)設(shè)計(jì)上。
- 蜜度索驥:以跨模態(tài)檢索技術(shù)助力“企宣”向上生長
- Fortinet李宏凱:2025年在中國大陸啟動(dòng)SASE PoP節(jié)點(diǎn)部署 助力企業(yè)出海
- Fortinet李宏凱:2024年Fortinet全球客戶已超80萬
- 央國企采購管理升級,合合信息旗下啟信慧眼以科技破局難點(diǎn)
- Apache Struts重大漏洞被黑客利用,遠(yuǎn)程代碼執(zhí)行風(fēng)險(xiǎn)加劇
- Crunchbase:2024年AI網(wǎng)絡(luò)安全行業(yè)風(fēng)險(xiǎn)投資超過26億美元
- 調(diào)查報(bào)告:AI與云重塑IT格局,77%的IT領(lǐng)導(dǎo)者視網(wǎng)絡(luò)安全為首要挑戰(zhàn)
- 長江存儲發(fā)布聲明:從無“借殼上市”意愿
- 泛微·數(shù)智大腦Xiaoe.AI正式發(fā)布,千人現(xiàn)場體驗(yàn)數(shù)智化運(yùn)營場景
- IDC:2024年第三季度北美IT分銷商收入增長至202億美元
- AI成為雙刃劍!凱捷調(diào)查:97%組織遭遇過GenAI漏洞攻擊
免責(zé)聲明:本網(wǎng)站內(nèi)容主要來自原創(chuàng)、合作伙伴供稿和第三方自媒體作者投稿,凡在本網(wǎng)站出現(xiàn)的信息,均僅供參考。本網(wǎng)站將盡力確保所提供信息的準(zhǔn)確性及可靠性,但不保證有關(guān)資料的準(zhǔn)確性及可靠性,讀者在使用前請進(jìn)一步核實(shí),并對任何自主決定的行為負(fù)責(zé)。本網(wǎng)站對有關(guān)資料所引致的錯(cuò)誤、不確或遺漏,概不負(fù)任何法律責(zé)任。任何單位或個(gè)人認(rèn)為本網(wǎng)站中的網(wǎng)頁或鏈接內(nèi)容可能涉嫌侵犯其知識產(chǎn)權(quán)或存在不實(shí)內(nèi)容時(shí),應(yīng)及時(shí)向本網(wǎng)站提出書面權(quán)利通知或不實(shí)情況說明,并提供身份證明、權(quán)屬證明及詳細(xì)侵權(quán)或不實(shí)情況證明。本網(wǎng)站在收到上述法律文件后,將會(huì)依法盡快聯(lián)系相關(guān)文章源頭核實(shí),溝通刪除相關(guān)內(nèi)容或斷開相關(guān)鏈接。