突破局限!廣告計(jì)費(fèi)系統(tǒng)高可用升級(jí)之路
1 背景介紹
服務(wù)穩(wěn)定性和高可用性在現(xiàn)代業(yè)務(wù)中扮演著至關(guān)重要的角色。服務(wù)穩(wěn)定性指的是系統(tǒng)能夠持續(xù)地提供可靠、無(wú)故障的服務(wù),而高可用性則強(qiáng)調(diào)系統(tǒng)在遇到故障或異常情況時(shí)依然能夠保持正常運(yùn)作。這兩個(gè)方面的重要性在于它們直接影響到用戶體驗(yàn)、業(yè)務(wù)連續(xù)性和企業(yè)聲譽(yù)。當(dāng)服務(wù)不穩(wěn)定或不可用時(shí),用戶可能會(huì)面臨訪問(wèn)中斷、數(shù)據(jù)丟失或延遲等問(wèn)題,從而降低用戶滿意度并可能導(dǎo)致客戶流失。另外,對(duì)于廣告投放和計(jì)費(fèi)業(yè)務(wù),高可用性尤為重要。廣告是互聯(lián)網(wǎng)企業(yè)最常見(jiàn)的盈利手段,即使短暫的中斷也可能導(dǎo)致巨大的財(cái)務(wù)損失。因此,投資和優(yōu)化服務(wù)穩(wěn)定性與高可用性是必須考慮的關(guān)鍵因素。
本次主要介紹廣告計(jì)費(fèi)系統(tǒng)在穩(wěn)定性和可用性方面所做的優(yōu)化改進(jìn)和升級(jí)。
1.1 廣告計(jì)費(fèi)方式介紹
互聯(lián)網(wǎng)廣告大家應(yīng)該都不陌生,日常 pc 和 app 應(yīng)該見(jiàn)過(guò)很多彈窗廣告,視頻廣告等,那么這些廣告是怎樣計(jì)費(fèi)的,先來(lái)了解下幾種常見(jiàn)的計(jì)費(fèi)模式。
圖片
廣告投放主要是為了提高曝光和轉(zhuǎn)化,使用得比較多的為 CPT、CPM、CPC、 CPA 和 CPS 幾種;不同的計(jì)費(fèi)方式會(huì)對(duì)廣告主和平臺(tái)的收益產(chǎn)生不同的影響:
- CPT(Cost Per Time):按時(shí)間計(jì)費(fèi)的商業(yè)產(chǎn)品,比如頻道頁(yè)的頂部展位,用于店鋪快速引流;
- CPM(Cost Per Mille):按曝光計(jì)費(fèi)的商業(yè)產(chǎn)品,比如開(kāi)屏廣告、視頻廣告、朋友圈廣告,用于品牌推廣或app拉新促活;
- CPC(Cost Per Click):按點(diǎn)擊計(jì)費(fèi)的商業(yè)產(chǎn)品,電商行業(yè)常用于站內(nèi)廣告資源位推廣商品;
- CPA(Cost Per Action):按行為計(jì)費(fèi)的商業(yè)產(chǎn)品,如打電話、關(guān)注、收藏;
- CPS(Cost Per Sale):按成交計(jì)費(fèi)的商業(yè)產(chǎn)品,多用于站外引流,如:淘寶聯(lián)盟、京東聯(lián)盟、多多進(jìn)寶;
圖片
1.2 廣告計(jì)費(fèi)系統(tǒng)功能介紹
圖片
從圖中可以看出,廣告計(jì)費(fèi)系統(tǒng)主要功能包括兩大部分
- 廣告檢索階段: 根據(jù)廣告信息生成唯一的扣費(fèi)憑證,作為扣費(fèi)階段的扣費(fèi)依據(jù)。能否正常生成扣費(fèi)憑證直接決定了后續(xù)能否正常扣費(fèi),因此,提高系統(tǒng)的可用性能夠降低對(duì)收入的影響。
- 廣告計(jì)費(fèi)階段: 我們對(duì)扣費(fèi)請(qǐng)求進(jìn)行了一系列的處理,包括反作弊措施、扣費(fèi)操作以及事后處理等邏輯。這一階段的核心任務(wù)是確保扣費(fèi)不遺漏,并保障扣費(fèi)的實(shí)時(shí)性??圪M(fèi)的實(shí)時(shí)性不僅對(duì)上游超時(shí)量產(chǎn)生影響,還關(guān)乎下游業(yè)務(wù)的及時(shí)性。多種下游業(yè)務(wù)場(chǎng)景,如推廣活動(dòng)、廣告主通知等,都依賴于準(zhǔn)確的計(jì)費(fèi)結(jié)果。例如,當(dāng)預(yù)算不足時(shí),系統(tǒng)需要自動(dòng)下線推廣活動(dòng);當(dāng)余額不足時(shí),系統(tǒng)應(yīng)向廣告主發(fā)送提醒通知。
2 升級(jí)背景
2.1 初始流程
圖片
在廣告計(jì)費(fèi)階段,我們采用異步線程處理扣費(fèi)請(qǐng)求,以提升系統(tǒng)的并發(fā)性能和響應(yīng)速度。當(dāng)扣費(fèi)請(qǐng)求失敗時(shí),我們將相關(guān)信息存儲(chǔ)到 Redis 中,以便后續(xù)定時(shí)任務(wù)進(jìn)行失敗數(shù)據(jù)處理。通過(guò)定時(shí)任務(wù)的方式,我們能夠處理失敗的扣費(fèi)請(qǐng)求,避免遺漏,確??圪M(fèi)過(guò)程的完整性和準(zhǔn)確性。
- 優(yōu)點(diǎn): 異步處理扣費(fèi)邏輯,可以提高服務(wù)吞吐量和響應(yīng)性能,減少上游等待時(shí)間
- 缺點(diǎn):
- 高并發(fā)情況下丟失扣費(fèi),對(duì)丟失的扣費(fèi)補(bǔ)償無(wú)法做到及時(shí)處理
- 目前的定時(shí)任務(wù)每次只能在一臺(tái)服務(wù)器上執(zhí)行,導(dǎo)致服務(wù)壓力分布不均衡
- 扣費(fèi)鏈路較長(zhǎng),涉及的內(nèi)部線程池較多,容易發(fā)生交叉使用導(dǎo)致死鎖的情況
2.1 升級(jí)契機(jī)
2.1.1 問(wèn)題發(fā)現(xiàn)
起初,我們收到了線上的告警通知:扣費(fèi)服務(wù)的線程池任務(wù)隊(duì)列大小遠(yuǎn)遠(yuǎn)超出了報(bào)警設(shè)定的閾值,而且隊(duì)列大小隨著時(shí)間推移還在持續(xù)變大。詳細(xì)告警內(nèi)容如下:
圖片
圖片
相應(yīng)的,廣告業(yè)務(wù)指標(biāo):點(diǎn)擊數(shù)、收入等也出現(xiàn)了非常明顯的下滑,幾乎同時(shí)發(fā)出了業(yè)務(wù)告警通知。其中,點(diǎn)擊數(shù)指標(biāo)對(duì)應(yīng)的曲線表現(xiàn)如下:
圖片
2.1.2 原因分析
通過(guò)線程池的報(bào)警通知,可以清楚地發(fā)現(xiàn)有線程受到了阻塞,導(dǎo)致需要不斷創(chuàng)建新線程來(lái)處理請(qǐng)求。通過(guò)生成線程快照,我們發(fā)現(xiàn)用于扣費(fèi)業(yè)務(wù)的線程池中的所有線程都處于等待狀態(tài),并且全部卡在了 countDownLatch.await()
方法處,這表明它們正在等待計(jì)數(shù)器變?yōu)?后釋放共享鎖。
具體導(dǎo)致線程阻塞的原因:
1. 數(shù)據(jù)庫(kù)中的數(shù)據(jù)抽取任務(wù)存在慢查詢,導(dǎo)致數(shù)據(jù)庫(kù)出現(xiàn)阻塞現(xiàn)象,進(jìn)而使得創(chuàng)建扣費(fèi)訂單的耗時(shí)增加。
2. 由于創(chuàng)建扣費(fèi)訂單的耗時(shí)增加,導(dǎo)致扣費(fèi)任務(wù)的整體執(zhí)行時(shí)間變長(zhǎng)。此外,扣費(fèi)服務(wù)中存在線程池使用不當(dāng)?shù)那闆r,父子任務(wù)使用了同一個(gè)線程池。當(dāng)線程池中的所有線程都在執(zhí)行父任務(wù),且所有父任務(wù)都存在未執(zhí)行完的子任務(wù)時(shí),就發(fā)生了死鎖現(xiàn)象。
通過(guò)下面一張圖再來(lái)直觀地看下死鎖的情況:
一次扣費(fèi)行為被視為父任務(wù),其中包含多個(gè)子任務(wù),這些子任務(wù)用于執(zhí)行反作弊策略。假設(shè)線程池的核心線程數(shù)為2,目前正在執(zhí)行扣費(fèi)父任務(wù)1和2。此外,反作弊子任務(wù)1和3已完成執(zhí)行,而反作弊子任務(wù)2和4仍在任務(wù)隊(duì)列中等待調(diào)度。
由于反作弊子任務(wù)2和4尚未執(zhí)行完畢,導(dǎo)致扣費(fèi)父任務(wù)1和2也無(wú)法完成執(zhí)行,從而發(fā)生了死鎖現(xiàn)象。這種情況下,核心線程永遠(yuǎn)無(wú)法釋放,最終導(dǎo)致任務(wù)隊(duì)列不斷積壓,直至程序遭遇 OOM 崩潰。
圖片
2.1.3 解決方案
1. 通過(guò)重啟服務(wù),可以快速恢復(fù)業(yè)務(wù)正常運(yùn)行。
2. 通過(guò)規(guī)范線程池的使用,為父子任務(wù)分配獨(dú)立的線程池,可以避免死鎖情況的發(fā)生,確保任務(wù)的順利執(zhí)行。
2.1.4 問(wèn)題反思
雖然隔離父子任務(wù)的線程池可以有效地解決死鎖問(wèn)題,但這次線上事故也暴露了計(jì)費(fèi)系統(tǒng)補(bǔ)償機(jī)制的不完善。盡管我們?cè)O(shè)置了定時(shí)任務(wù)來(lái)處理失敗的扣費(fèi),但這種方式存在明顯的缺點(diǎn)。
1. 無(wú)法及時(shí)執(zhí)行:由于定時(shí)任務(wù)的執(zhí)行是按照預(yù)設(shè)的時(shí)間間隔進(jìn)行的,因此對(duì)于一些突發(fā)性的扣費(fèi)失敗情況,可能無(wú)法做到及時(shí)處理。
2. 對(duì)于此次的問(wèn)題,由于失敗的扣費(fèi)數(shù)據(jù)還未被加入到 Redis 中,系統(tǒng)就重啟了,這給線上的收入造成了不良影響。
針對(duì)上述問(wèn)題,我們對(duì)扣費(fèi)系統(tǒng)的高可用方案進(jìn)行了升級(jí)。
3 升級(jí)版
3.1 改進(jìn)后流程
圖片
首先整個(gè)扣費(fèi)流程仍然是異步化處理,當(dāng)收到實(shí)時(shí)扣費(fèi)請(qǐng)求后,系統(tǒng)先將扣費(fèi)信息打印日志用于災(zāi)難恢復(fù),然后發(fā)送 MQ 消息,這兩步完成后扣費(fèi)動(dòng)作就算結(jié)束了。
3.2 改進(jìn)點(diǎn)1
使用了 MQ 代替異步線程池來(lái)處理扣費(fèi)請(qǐng)求,MQ 相比較異步線程池的主要優(yōu)點(diǎn)是解耦和可靠性。MQ 提供了一種基于消息的分布式通信機(jī)制,可以將數(shù)據(jù)以消息的形式發(fā)送到隊(duì)列中,由消費(fèi)者進(jìn)行異步處理。這種解耦能力使得生產(chǎn)者與消費(fèi)者之間的耦合度降低,提高了系統(tǒng)的可伸縮性和靈活性。更重要的是,MQ 還具有高度可靠性,在消息傳遞過(guò)程中能夠確保消息的可靠投遞和持久化存儲(chǔ),即使在消費(fèi)者不可用或重啟時(shí)也能保證消息不丟失。
這樣做的好處是利用 MQ 的可靠性投遞和重試機(jī)制不僅確保了機(jī)器的流量均衡同時(shí)還保證了整個(gè)扣費(fèi)流程的最終一致性。
圖片
圖片
3.3 改進(jìn)點(diǎn)2
針對(duì) MQ 不可用的情況采用了降級(jí)方案。當(dāng) MQ 不可用時(shí),使用異步線程處理作為降級(jí)方案;這樣可以使系統(tǒng)保持可用性并繼續(xù)運(yùn)行。異步線程處理允許將數(shù)據(jù)直接提交給線程池進(jìn)行處理,而不依賴于MQ的消息傳遞機(jī)制。這樣可以在MQ不可用的情況下,臨時(shí)繞過(guò)MQ,通過(guò)異步線程池來(lái)處理扣費(fèi)請(qǐng)求,以確保系統(tǒng)的穩(wěn)定性和扣費(fèi)功能的可用性。
雖然這種降級(jí)方案可能會(huì)導(dǎo)致一些延遲或性能損失,但它可以有效地應(yīng)對(duì) MQ 故障或不可用的情況,并避免完全的系統(tǒng)停機(jī)。當(dāng) MQ 恢復(fù)正常后,系統(tǒng)可以再次切換回 MQ 作為主要的消息傳遞機(jī)制,從而實(shí)現(xiàn)正常的異步處理流程。
圖片
3.4 改進(jìn)點(diǎn)3
在獲取扣費(fèi)憑證時(shí),扣費(fèi)信息是存儲(chǔ)在 Redis 中的。當(dāng) Redis 不可用時(shí),借助了 TiKV 來(lái)確保系統(tǒng)的持續(xù)可用性。
召回階段獲取扣費(fèi)憑證時(shí) Redis 和 TiKV 同時(shí)存儲(chǔ)扣費(fèi)信息。主存儲(chǔ)同步寫(xiě)入 Redis,調(diào)用方等待結(jié)果;從存儲(chǔ)異步寫(xiě)入 TiKV,在不影響系統(tǒng)性能的前提下,使用TiKV作為備份。
圖片
圖片
3.5 改進(jìn)點(diǎn)4
任務(wù)補(bǔ)償除了 MQ 的重試機(jī)制,還新增了 Spark 任務(wù)用于恢復(fù)大批量扣費(fèi)失敗的情況;Spark 任務(wù)可以從相關(guān)日志文件中提取關(guān)鍵信息,并對(duì)需要進(jìn)行扣費(fèi)操作的數(shù)據(jù)進(jìn)行篩選和分析。一旦扣費(fèi)失敗的數(shù)據(jù)被確認(rèn),Spark 任務(wù)會(huì)重新發(fā)送扣費(fèi) MQ,系統(tǒng)重新進(jìn)行消費(fèi),做到跟系統(tǒng)無(wú)縫銜接。
通過(guò)使用Spark進(jìn)行日志采集和數(shù)據(jù)處理,可以有效地自動(dòng)化和加速扣費(fèi)失敗數(shù)據(jù)的確認(rèn)過(guò)程。Spark 的并行計(jì)算和分布式架構(gòu)使得它能夠處理大規(guī)模的日志數(shù)據(jù),并通過(guò)靈活的數(shù)據(jù)轉(zhuǎn)換和篩選功能提取所需的信息。這種離線方式可以提供更高的可靠性和效率,同時(shí)減少對(duì)人工干預(yù)的依賴,從而提升整體的數(shù)據(jù)處理效能和系統(tǒng)穩(wěn)定性。
圖片
4 結(jié)語(yǔ)
廣告計(jì)費(fèi)系統(tǒng)的穩(wěn)定性是確保廣告商正常結(jié)算和交易的基礎(chǔ),對(duì)于建立信任與合作關(guān)系至關(guān)重要;持續(xù)優(yōu)化廣告計(jì)費(fèi)系統(tǒng)的穩(wěn)定性和可用性是非常必要的,以適應(yīng)變化的業(yè)務(wù)需求,同時(shí)最大化系統(tǒng)效率和資源利用。有助于為廣告行業(yè)持續(xù)創(chuàng)造價(jià)值,并保持競(jìng)爭(zhēng)優(yōu)勢(shì)。
關(guān)于作者
張蓉,轉(zhuǎn)轉(zhuǎn)商業(yè)高級(jí)開(kāi)發(fā)工程師,目前負(fù)責(zé)廣告檢索、計(jì)費(fèi)以及特征工程等系統(tǒng)。