主頁 > 軟體設計 > OpenResty 在馬蜂窩廣告監測中的應用

OpenResty 在馬蜂窩廣告監測中的應用

2020-09-13 17:13:49 軟體設計

馬蜂窩技術原創內容,更多干貨請訂閱公眾號:mfwtech

廣告是互聯網變現的重要手段之一,

以馬蜂窩旅游 App 為例,當用戶打開我們的應用時,有可能會在首屏或是資訊流、商品串列中看到推送的廣告,如果剛好對廣告內容感興趣,用戶就可能會點擊廣告了解更多資訊,進而完成這條廣告希望完成的后續操作,如下載廣告推薦的 App 等,

廣告監測平臺的任務就是持續、準確地收集用戶在瀏覽和點擊廣告這些事件中攜帶的資訊,包括來源、時間、設備、位置資訊等,并進行處理和分析,來為廣告主提供付費結算以及評估廣告投放效果的依據,

因此,一個可靠、準確的監測服務非常重要,為了更好地保障平臺和廣告主雙方的權益,以及為提升馬蜂窩旅游網的廣告服務效果提供支撐,我們也在不斷地探索適合的解決方案,加強廣告監測服務的能力,

 

Part.1 初期形態

初期我們的廣告監測并沒有形成完整的服務對外開放,因此實作方式及提供的能力也比較簡單,主要分為兩部分:一是基于客戶端打點,針對事件進行上報;另一部分是針對曝光、點擊鏈接做轉碼存檔,當請求到來后決議跳轉,

但是很快,這種方式的弊端就暴露出來,主要體現在以下幾個方面:

  • 收數的準確性:資料轉發需要訪問中間件才能完成,增加了多段丟包的機率,在和第三方監測服務進行對比驗證時,Gap 差異較大;

  • 資料的處理能力:收集的資料來自于各個業務系統,缺乏統一的資料標準,資料的多種屬性導致決議起來很復雜,增加了綜合資料二次利用的難度;

  • 突發流量:當流量瞬時升高,就會遇到 Redis 記憶體消耗高、服務掉線頻繁的問題;

  • 部署復雜:隨著不同設備、不同廣告位的變更,打點趨于復雜,甚至可能會覆寫不到;

  • 開發效率:初期的廣告監測功能單一,例如對實時性條件的計算查詢等都需要額外開發,非常影響效率,

 

Part.2 基于 OpenResty 的架構實作

在這樣的背景下,我們打造了馬蜂窩廣告資料監測平臺 ADMonitor,希望逐步將其實作成一個穩定、可靠、高可用的廣告監測服務,

2.1 設計思路

為了解決老系統中的各種問題,我們引入了新的監測流程,主體流程設計為:

  1. 在新的監測服務 (ADMonitor) 上生成關于每種廣告獨有的監測鏈接,同時附在原有的客戶鏈接上;

  2. 所有從服務端下發的曝光鏈接和點擊鏈接并行依賴 ADMonitor 提供的服務;

  3. 客戶端針對曝光行為進行并行請求,點擊行為會優先跳轉到 ADMonitor,由 ADMonitor 來做二段跳轉,

通過以上方式,使監測服務完全依賴 ADMonitor,極大地增加了監測部署的靈活性及整體服務的性能;同時為了進一步驗證資料的準確性,我們保留了打點的方式進行對比,

2.2 技術選型

為了使上述流程落地,廣告監測的流量入口必須要具備高可用、高并發的能力,盡量減少非必要的網路請求,考慮到內部多個系統都需要流量,為了降低系統對接的人力成本,以及避免由于系統迭代對線上服務造成干擾,我們首先要做的就是把流量網關獨立出來,

關于 C10K 編程相關的技術業內有很多解決方案,比如 OpenResty、JavaNetty、Golang、NodeJS 等,它們共同的特點是使用一個行程或執行緒可以同時處理多個請求,基于執行緒池、基于多協程、基于事件驅動+回呼、實作 I/O 非阻塞,

我們最終選擇基于 OpenResty 構建廣告監測平臺,主要是對以下方面的考慮:

第一,OpenResty 作業在網路的 7 層之上,依托于比 HAProxy 更為強大和靈活的正則規則,可以針對 HTTP 應用的域名、目錄結構做一些分流、轉發的策略,既能做負載又能做反向代理;

第二,OpenResty 具有 Lua協程+Nginx 事件驅動的「事件回圈回呼機制」,也就是 Openresty 的核心 Cosoket,對遠程后端諸如 MySQL、Memcached、Redis 等都可以實作同步寫代碼的方式實作非阻塞 I/O;

第三,依托于 LuaJit,即時編譯器會將頻繁執行的代碼編譯成機器碼快取起來,當下次呼叫時將直接執行機器碼,相比原生逐條執行虛擬機指令效率更高,而對于那些只執行一次的代碼仍然可以逐條執行,

2.3 架構實作

整體方案依托于 OpenResty 的處理機制,在服務器內部進行定制開發,主要劃分為資料收集、資料處理與資料歸檔三大部分,實作異步拆分請求與 I/O 通信,整體結構示意圖如下:

我們將多 Woker 日志資訊以雙端佇列的方式存入 Master 共享記憶體,開啟 Worker 的 Timer 毫秒級定時器,離線決議流量,

2.3.1 資料收集 

收集部分也是主體承受流量壓力最大的部分,我們使用 Lua 來做整體檢參、過濾與推送,由于在我們的場景中,資料收集部分不需要考慮時序或對資料進行聚合處理,因此核心的推送介質選擇 Lua 共享記憶體即可,以 I/O 請求來代替訪問其他中間件所需要的網路服務,從而減少網路請求,滿足即時性的要求,如下所示:

下面結合 OpenResty 配置,介紹一些我們對服務器節點進行的優化:

  1. 設定 lua 快取-lua_code_cache:

    (1)開啟后會將 Lua 檔案快取到記憶體中,加速訪問,但修改 Lua 代碼需要 reload

    (2)盡量避免全域變數的產生

    (3)關閉后會依賴 Woker 行程中生成自己新的 LVM

  2. 設定 Resolver 對于網路請求、好的 DNS 節點或者自建的 DNS 節點在網路請求很高的情況下會很有幫助:

    (1)增加公司的 DNS 服務節點與補償的公網節點

    (2)使用 shared 來減少 Worker 查詢次數

  3. 設定 epoll (multi_accept/accept_mutex/worker_connections):

    (1)設定 I/O 模型、防止驚群

    (2)避免服務節點浪費資源做無用處理而影響整體流轉等

  4. 設定 keepalive:

    (1)包含鏈接時長與請求上限等

配置優化一方面是要符合當前請求場景,另一方面要配合 Lua 發揮更好的性能,設定 Nginx 服務器引數基礎是根據不同作業系統環境進行調優,比如 Linux 中一切皆檔案、調整檔案打開數、設定 TCP Buckets、設定 TIME_WAIT  等,

2.3.2 資料處理

這部分流程是將收集到的資料先通過 ETL,之后創建內部的日志 location,結合 Lua 自定義 log_format,利用 Nginx 子請求特性離線完成資料落盤,同時保證資料延遲時長在毫秒級,

對被決議的資料處理要進行兩部分作業,一部分是 ETL,另一部分是 Count,

(1)ETL

主要流程:     

  1. 日志經過統一格式化之后,抽取包含實際意義引數部分進行資料決議

  2. 將抽取后的資料進行過濾,針對整體字符集、IP、設備、UA、相關標簽資訊等進行處理

  3. 將轉化后的資料進行重加載與日志重定向

【例】Lua 利用 FFI 通過 IP 庫決議 "ip!"用 C 把 IP 庫拷貝到記憶體中,Lua 進行毫秒級查詢:

(2)Count

對于廣告資料來說,絕大部分業務需求都來自于資料統計,這里直接使用 Redis+FluxDB 存盤資料,以有下幾個關鍵的技術點:

  • RDS 結合 Lua 設定鏈接時間,配置鏈接池來增加鏈接復用

  • RDS 集群服務實作去中心化,分散節點壓力,增加 AOF與延時入庫保證可靠

  • FluxDB 保證資料日志時序性可查,聚合統計與實時報表表現較優

2.3.3 資料歸檔

資料歸檔需要對全量資料入表,這個程序中會涉及到對一些無效資料進行過濾處理,這里整體接入了公司的大資料體系,流程上分為在線處理和離線處理兩部分,能夠對資料回溯,使用的解決方案是在線 Flink、離線 Hive,其中需要關注: 

  • ES 的索引與資料定期維護

  • Kafka 的消費情況

  • 對于發生故障的機器使用自動腳本重啟與報警等

實時資料源:資料采集服務→ Filebeat → Kafka → Flink → ES

離線資料源:HDFS → Spark → Hive → ES

資料決議后的再利用:

決議后的資料已經擁有了重復利用的價值,我們的主要應用場景有兩大塊,

一是 OLAP,針對業務場景與資料表現分析訪問廣告的人群屬性標簽變化情況,包含地域,設備,人群分布占比與增長情況等;同時,針對未來人群庫存占比進行預測,最后影響到實際投放上,

另一部分是在 OLTP,主要場景為:

  • 判定用戶是否屬于廣告受眾區域

  • 決議 UA 資訊,獲取終端資訊,判斷是否屬于為低級爬蟲流量

  • 設備號打標,從 Redis 獲取實時用戶畫像,進行實時標記等

2.4 OpenResty 其他應用場景

OpenResty 在我們的廣告資料監測服務全流程中均發揮著重要作用:

  • init_worker_by_lua階段:負責服務配置業務

  • access_by_lua階段:負責CC防護、權限準入、流量時序監控等業務

  • content_by_lua階段:負責實作限速器、分流器、WebAPI、流量采集等業務

  • log_by_lua階段:負責日志落盤等業務

重點解讀以下兩個應用的實作方式,

2.4.1  分流器業務

NodeJS 服務向 OpenResty 網關上報當前服務器 CPU 和記憶體使用情況;Lua 腳本呼叫 RedisCluster 獲取時間視窗內 NodeJS 集群使用情況后,計算出負載較高的 NodeJS 機器;OpenResty 對 NodeJS 集群流量進行熔斷、降級、限流等邏輯處理;將監控資料同步 InfluxDB,進行時序監測,

2.4.2 小型 WEB 防火墻

使用第三方開源 lua_resty_waf 類別庫實作,支持 IP 白名單和黑名單、URL 白名單、UA 過濾、CC 攻擊防護功能,我們在此基礎上增加了 WAF 對 InfluxDB 的支持,進行時序監控和服務預警,

2.5 小結

總結來看,基于 OpenResty 實作的廣告監測服務 ADMonitor 具備以下特點:

  • 高可用:依賴 OpenResty 做 Gateway, 多節點做 HA

  • 立即回傳:決議資料后利用 I/O 請求做資料異步處理,避免非必要的網路通信

  • 解耦功能模塊:對請求、資料處理和轉發實作解耦,縮減單請求串行處理耗時

  • 服務保障:  針對重要的資料結果利用第三方組件單獨存盤

完整的技術方案示意如下:

 

Part.3 總結

目前,ADMonitor 已經接入公司的廣告服務體系,總體運行情況比較理想:

1. 性能效果

  • 達到了高吞吐、低延遲的標準

  • 轉發成功率高,曝光計數成功率>99.9%,點擊成功率>99.8%

2. 業務效果

  • 與主流第三方監測機構進行資料對比:曝光資料 GAP < 1%,點擊資料GAP < 3%

  • 可提供實時檢索與聚合服務

未來我們將結合業務發展和服務場景不斷完善,期待和大家多多交流,

本文作者:江明輝,馬蜂窩旅游網品牌廣告資料服務端組研發工程師,

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/25988.html

標籤:架構設計

上一篇:云計算之Linux全堆疊目錄番外篇(教你如何破解別人root用戶密碼!!!)

下一篇:springboot 后臺框架平臺 mybatis 集成代碼生成器 shiro 權限 websocket

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more