馬蜂窩技術原創內容,更多幹貨請訂閱公衆號:mfwtech
廣告是互聯網變現的重要手段之一。編程
以馬蜂窩旅遊 App 爲例,當用戶打開咱們的應用時,有可能會在首屏或是信息流、商品列表中看到推送的廣告。若是恰好對廣告內容感興趣,用戶就可能會點擊廣告瞭解更多信息,進而完成這條廣告但願完成的後續操做,以下載廣告推薦的 App 等。後端
廣告監測平臺的任務就是持續、準確地收集用戶在瀏覽和點擊廣告這些事件中攜帶的信息,包括來源、時間、設備、位置信息等,並進行處理和分析,來爲廣告主提供付費結算以及評估廣告投放效果的依據。緩存
所以,一個可靠、準確的監測服務很是重要。爲了更好地保障平臺和廣告主雙方的權益,以及爲提高馬蜂窩旅遊網的廣告服務效果提供支撐,咱們也在不斷地探索適合的解決方案,增強廣告監測服務的能力。服務器
初期咱們的廣告監測並無造成完整的服務對外開放,所以實現方式及提供的能力也比較簡單,主要分爲兩部分:一是基於客戶端打點,針對事件進行上報;另外一部分是針對曝光、點擊連接作轉碼存檔,當請求到來後解析跳轉。微信
可是很快,這種方式的弊端就暴露出來,主要體如今如下幾個方面:網絡
在這樣的背景下,咱們打造了馬蜂窩廣告數據監測平臺 ADMonitor,但願逐步將其實現成一個穩定、可靠、高可用的廣告監測服務。架構
爲了解決老系統中的各類問題,咱們引入了新的監測流程。主體流程設計爲:併發
經過以上方式,使監測服務徹底依賴 ADMonitor,極大地增長了監測部署的靈活性及總體服務的性能;同時爲了進一步驗證數據的準確性,咱們保留了打點的方式進行對比。異步
爲了使上述流程落地,廣告監測的流量入口必需要具有高可用、高併發的能力,儘可能減小非必要的網絡請求。考慮到內部多個系統都須要流量,爲了下降系統對接的人力成本,以及避免因爲系統迭代對線上服務形成干擾,咱們首先要作的就是把流量網關獨立出來。高併發
關於 C10K 編程相關的技術業內有不少解決方案,好比 OpenResty、JavaNetty、Golang、NodeJS 等。它們共同的特色是使用一個進程或線程能夠同時處理多個請求,基於線程池、基於多協程、基於事件驅動+回調、實現 I/O 非阻塞。
咱們最終選擇基於 OpenResty 構建廣告監測平臺,主要是對如下方面的考慮:
第一,OpenResty 工做在網絡的 7 層之上,依託於比 HAProxy 更爲強大和靈活的正則規則,能夠針對 HTTP 應用的域名、目錄結構作一些分流、轉發的策略,既能作負載又能作反向代理;
第二,OpenResty 具備 Lua協程+Nginx 事件驅動的「事件循環回調機制」,也就是 Openresty 的核心 Cosoket,對遠程後端諸如 MySQL、Memcached、Redis 等均可以實現同步寫代碼的方式實現非阻塞 I/O;
第三,依託於 LuaJit,即時編譯器會將頻繁執行的代碼編譯成機器碼緩存起來,當下次調用時將直接執行機器碼,相比原生逐條執行虛擬機指令效率更高,而對於那些只執行一次的代碼仍然能夠逐條執行。
總體方案依託於 OpenResty 的處理機制,在服務器內部進行定製開發,主要劃分爲數據收集、數據處理與數據歸檔三大部分,實現異步拆分請求與 I/O 通訊。總體結構示意圖以下:
咱們將多 Woker 日誌信息以雙端隊列的方式存入 Master 共享內存,開啓 Worker 的 Timer 毫秒級定時器,離線解析流量。
收集部分也是主體承受流量壓力最大的部分。咱們使用 Lua 來作總體檢參、過濾與推送。因爲在咱們的場景中,數據收集部分不須要考慮時序或對數據進行聚合處理,所以核心的推送介質選擇 Lua 共享內存便可,以 I/O 請求來代替訪問其餘中間件所須要的網絡服務,從而減小網絡請求,知足即時性的要求,以下所示:
下面結合 OpenResty 配置,介紹一些咱們對服務器節點進行的優化:
(1)開啓後會將 Lua 文件緩存到內存中,加速訪問,但修改 Lua 代碼須要 reload
(2)儘可能避免全局變量的產生
(3)關閉後會依賴 Woker 進程中生成本身新的 LVM
(1)增長公司的 DNS 服務節點與補償的公網節點
(2)使用 shared 來減小 Worker 查詢次數
(1)設置 I/O 模型、防止驚羣
(2)避免服務節點浪費資源作無用處理而影響總體流轉等
(1)包含連接時長與請求上限等
配置優化一方面是要符合當前請求場景,另外一方面要配合 Lua 發揮更好的性能。設置 Nginx 服務器參數基礎是根據不一樣操做系統環境進行調優,好比 Linux 中一切皆文件、調整文件打開數、設置 TCP Buckets、設置 TIME_WAIT 等。
這部分流程是將收集到的數據先經過 ETL,以後建立內部的日誌 location,結合 Lua 自定義 log_format,利用 Nginx 子請求特性離線完成數據落盤,同時保證數據延遲時長在毫秒級。
對被解析的數據處理要進行兩部分工做,一部分是 ETL,另外一部分是 Count。
(1)ETL
主要流程:
【例】Lua 利用 FFI 經過 IP 庫解析 "ip!"用 C 把 IP 庫拷貝到內存中,Lua 進行毫秒級查詢:
(2)Count
對於廣告數據來講,絕大部分業務需求都來自於數據統計,這裏直接使用 Redis+FluxDB 存儲數據,以有下幾個關鍵的技術點:
數據歸檔須要對全量數據入表,這個過程當中會涉及到對一些無效數據進行過濾處理。這裏總體接入了公司的大數據體系,流程上分爲在線處理和離線處理兩部分,可以對數據回溯。使用的解決方案是在線 Flink、離線 Hive,其中須要關注:
實時數據源:數據採集服務→ Filebeat → Kafka → Flink → ES
離線數據源:HDFS → Spark → Hive → ES
數據解析後的再利用:
解析後的數據已經擁有了重複利用的價值。咱們的主要應用場景有兩大塊。
一是 OLAP,針對業務場景與數據表現分析訪問廣告的人羣屬性標籤變化狀況,包含地域,設備,人羣分佈佔比與增加狀況等;同時,針對將來人羣庫存佔比進行預測,最後影響到實際投放上。
另外一部分是在 OLTP,主要場景爲:
OpenResty 在咱們的廣告數據監測服務全流程中均發揮着重要做用:
重點解讀如下兩個應用的實現方式。
NodeJS 服務向 OpenResty 網關上報當前服務器 CPU 和內存使用狀況;Lua 腳本調用 RedisCluster 獲取時間窗口內 NodeJS 集羣使用狀況後,計算出負載較高的 NodeJS 機器;OpenResty 對 NodeJS 集羣流量進行熔斷、降級、限流等邏輯處理;將監控數據同步 InfluxDB,進行時序監測。
使用第三方開源 lua_resty_waf 類庫實現,支持 IP 白名單和黑名單、URL 白名單、UA 過濾、CC 攻擊防禦功能。咱們在此基礎上增長了 WAF 對 InfluxDB 的支持,進行時序監控和服務預警。
總結來看,基於 OpenResty 實現的廣告監測服務 ADMonitor 具有如下特色:
完整的技術方案示意以下:
目前,ADMonitor 已經接入公司的廣告服務體系,整體運行狀況比較理想:
將來咱們將結合業務發展和服務場景不斷完善,期待和你們多多交流。
本文做者:江明輝,馬蜂窩旅遊網品牌廣告數據服務端組研發工程師。