1、背景html
奕星 (EAS) 是騰訊內部專一於遊戲營銷活動分析的系統,在營銷活動效果分析中,奕星遇到一個最大的問題就是對活動參與人數的去重,並給出對應的活動號碼包。單個營銷活動的週期是固定的,但活動與活動之間時間不多會有徹底相同的狀況。
好比A活動時間是1-10號,B活動是5-15號,那麼若是想分別獲得 A 和 B 的去重參與人數,則必須分別開啓任務對 A 和 B 在他們所屬的時間區間內進行計算去重。在海量日誌中天天對數千個營銷活動進行相似計算,對資源消耗是一個不小的挑戰。
而實際狀況下,須要計算的任務量還遠遠不止於此,奕星同時還提供遊戲官網非活動連接的去重數據,甚至每一個連接在每一個推廣渠道的去重數據,這個任務量級目前高達天天 50W+ 以上。
總結來看,面臨的主要問題就是如何在海量數據的狀況下,處理數量巨大的並且週期各不相同的去重計算任務。node
2、原有解決方案算法
對於這個問題,奕星以前嘗試了很多方案,這裏簡單介紹一下。
1. 基於TDW臨時表的方案
TDW 是騰訊內部通用的一站式大數據平臺,服務穩定,功能強大。對於這些任務的計算,奕星最先是想借助於 TDW 的計算能力來完成。
思路很簡單,就是在 pysql 中循環對每一個活動執行對應的 hiveSQL 來完成 T+1 時效的計算。
但這個方案最大的缺點就是:任務基本都是順序執行,重複掃描大量日誌,致使效率很是低下,並且從HDFS中拉取最終的去重文件也很是耗時。
雖而後面採用多種思路優化,好比將原始日誌先天天統一批量去重一次入到臨時表裏,全部計算基於臨時表來完成等,但最終仍是效率沒法進一步提升而放棄。
2. 基於實時計算+文件增量去重的方案
在奕星的數據統計中,基於 Storm 的實時計算任務,主要是提供各個活動的實時 PV 和參與次數等計數類數據。
因爲內存資源有限,業界也有基於近似去重算法(如 hyperloglog )直接在 Storm 中算出近似去重結果的,但沒法給出精確的結果和最終的號碼包文件,因此不符合選型要求。
而內存資源有限,更不可能容納下這麼大量的號碼包數據,因此經過內存徹底得出最終精確去重結果的方案基本不現實。
但內存雖然不能容納整個活動期間的號碼數據或者一天以內的號碼數據,可是否能夠容納 1 分鐘,5 分鐘的號碼數據?
經過測試計算髮現,在內存中緩存 5 分鐘內的去重號碼數據是徹底可行的,而且最高能夠將原始日誌下降 90% 以上的量級。緩存 1 分鐘的話,最高也能夠將原始日誌下降 70% 以上的量級。
主要的緣由是玩家參與活動的時候是即時參與行爲,好比一個玩家來到一個活動頁面後,通常是連續將活動中能參與的功能都參與下,不會參與完一個等好久再參與下一個,因此致使同一個玩家的日誌時間連續性較高,單位時間窗口內去重後量級會下降不少。
基於此,目前奕星主要是基於 Storm 在單位時間窗口內進行初次去重,以達到下降原始數據量級的目的。
最初的基於 TDW 的去重方案,除了重複掃描等問題外,還有一個問題就是:同一個活動不一樣日期之間的計算沒法先後銜接,好比 A 活動在活動期間(1-10號),天天的計算邏輯基本一致,都是要全量掃描 1-10 號之間的日誌(或中間結果)來完成計算。
因此團隊將目光投向如何在活動前期去重的基礎上來增量去重的問題上來。最終選定的方案是基於文件的計算方案,以下圖所示,活動天天都滾動生成最新的去重號碼包文件,而第二天同一個活動的日號碼包再與這個總包交叉後獲得更新的號碼包文件,如此重複,直到活動結束獲得最終的活動號碼包文件。
3. 基於實時計算+LevelDB增量去重方案
文件增量去重的方案,運行了一段時間後,就出現了一個很大的問題:就是每日新增的文件量巨大,日均幾十萬。
雖然沒有達到把單臺機器 inode 佔滿的狀況,但在增量去重時,大量的小文件 IO 操做,致使增量去重效率很是低,最後被迫只支持高優先級業務的活動和單個活動參與量大於必定閥值的大活動。
通過團隊小夥伴的調研,最終將目光鎖定在 Google 的 LevelDB 上,LevelDB 是 Google 開源的持久化 KV 單機數據庫,具備很高的隨機寫,順序讀/寫性能,可是隨機讀的性能很通常。
也就是說,LevelDB 很適合應用在查詢較少,而寫入不少的場景,這正好符合咱們號碼包去重服務的應用場景。
另外號碼包的存儲自己也是一個K-V的存儲,文件名爲 key,文件內容爲 value,正好跟 LevelDB 支持的 K-V 結構相似。
使用 LevelDB 後,能夠毫秒級獲得某個活動的準確去重人數,而且能夠在 10 秒內導出千萬量級的號碼包文件,相比傳統的文件操做,大大提升了號碼包去重服務的總體效率。
3、基於CLickHouse的解決方案sql
雖然基於 LevelDB 的去重服務能夠很好的知足大部分營銷活動的人數去重需求。但擴展性較差,數據回溯困難等問題比較突出,
類
似於基於預計算模式的 O
LAP
系統。
好比系統只支持活動整個期間內的去重人數計算,若是想知道活動期間內某一段時間內的去重就沒法實現。
另外若是某個活動引入了髒數據後,只能將整個活動的
K
-V
結構刪除後重跑,很是耗時。
團隊通過調研後,將目光鎖定到基於
M
PP
的
O
LAP
方案上。
基於 MPP 的 OLAP 系統,在數據庫非共享集羣中,每一個節點都有獨立的磁盤存儲系統和內存系統,業務數據根據數據庫模型和應用特色劃分到各個節點上,每臺數據節點經過專用網絡或者商業通用網絡互相鏈接,彼此協同計算,做爲總體提供數據庫服務。
相對於基於預計算模式的 OLAP 系統來講,它最大的優勢就是靈活,擴展性強,而最大的缺點是響應時間不及時,甚至須要較長的時間等待。
而在營銷活動效果分析中,每每靈活性比效率要更加劇要,或者說效率是能夠稍微妥協的一面,因此咱們選擇基於 MPP 的 OLAP 系統。
目前市面上有不少優秀的 OLAP 系統,但要麼是收費的(Vertica),要麼是基於 hadoop 生態的(presto,Impala),總體架構比較重。
而做爲戰鬥民族開源神器的 ClickHouse 不但擁有本身的文件系統和極高的壓縮比,在集羣部署上甚至能夠不用 zk 來獨立部署,甚至在性能上「吊打」商業的 OLAP 系統(詳見
官方測評數據:https://clickhouse.tech/benchmark/dbms/
)。
綜合以上考慮,最終選擇了 ClickHouse,去重服務就變成了 SQL 查詢,例以下面這條 SQL 就是查詢 LOL 官網某個頁面在 9 月 6 日這 1 天的 UV:
select uniqExact(uvid) from tbUv where date='2020-09-06' and url='http://lol.qq.com/main.shtml';
在 24 核 96G 內存的機器上,實際測試下來在 1 億條記錄中,精確去重一個參與量爲100W 的活動,僅需 0.1 s 不到,而導出這個號碼包文件只須要 0.2 s 不到。
雖然查詢效率上比 LevelDB 有一點差距,但靈活性卻大大提升,能夠任意指定時間區間和條件來作去重查詢,符合當前業務場景關注靈活度的需求場景,並且性能上從毫秒到秒級的延遲基本也能夠接受。
4、結語數據庫
去重服務的的問題伴隨奕星系統整個開發和運營週期,期間經歷過不少嘗試,部分臨時的嘗試方案還沒有在本文列出,但一直的出發點就是業務需求自己,而且結合當時的運維環境來選取對應的技術方案。
不追求絕對的高性能(意味成本也高),而關注最合適,易於擴容,搬遷,故障替換等有利於服務長期穩定運營的特性。固然,隨着更多利器的出現,也會去不斷的嘗試使用,畢竟科學技術纔是第一輩子產力。
目前 ClickHouse 在奕星等多個數據系統和諸多個性化營銷分析的場景中落地使用,數據總規模超過 5 千億,還在不斷增加中。