伴魚事件分析平臺設計
背景
在伴魚,服務器每天收集的用戶行爲日誌達到上億條,我們希望能夠充分利用這些日誌,瞭解用戶行爲模式,回答以下問題:
-
最近三個月,來自哪個渠道的用戶註冊量最高?
-
最近一週,北京地區的,發生過繪本瀏覽行爲的用戶,按照年齡段分佈的情況如何?
-
最近一週,註冊過伴魚繪本的用戶,7 日留存率如何?有什麼變化趨勢?
-
最近一週,用戶下單的轉化路徑上,各環節的轉化率如何?
爲了回答這些問題,事件分析平臺應運而生。本文將首先介紹平臺的功能,隨後討論平臺在架構上的一些思考。
功能
總的來說,爲了回答各種商業分析問題,事件分析平臺支持基於事件的指標統計、屬性分組、條件篩選等功能的查詢。其中,事件指用戶行爲,例如登錄、瀏覽伴魚繪本、購買付費繪本等。更具體一些,事件分析平臺支持三類分析:「事件分析」,「漏斗分析」,和「留存分析」。
事件分析
事件分析是指,用戶指定一系列條件,查詢目的指標,用於回答一個具體的分析問題。這些條件包括:
-
事件類型:指用戶行爲,採集自埋點數據;例如登錄伴魚繪本,購買付費繪本
-
指標:指標分爲兩類,基礎指標和自定義指標基礎指標:總次數(pv),總用戶數(uv),人均次數(pv/uv)自定義指標:事件屬性 + 計算類型,例如 「用戶下單金額」的「總和 / 均值 / 最大值」
-
過濾條件:用於篩選查詢所關心的用戶羣體
-
維度分組:基於分組,可以進行分組之間的對比
-
時間範圍:指定事件發生的時間範圍
讓我們舉個具體的例子。我們希望回答「最近一週,在北京地區,不同年齡段的用戶在下單一對一課程時,下單金額的平均數對比」這個問題。這個問題可以很直觀地拆解爲下圖所示的事件分析,其中:
-
事件類型 = 下單一對一課程
-
指標 = 下單金額的平均數
-
過濾條件 = 北京地區
-
維度分組 = 按照年齡段分組
-
時間範圍 = 最近一週
圖注:事件分析創建流程
圖注:事件分析界面
漏斗分析
漏斗分析用於分析多步驟過程中,每一步的轉化與流失情況。
例如,伴魚繪本用戶的完整購買流程可能包含以下步驟:登錄 app -> 瀏覽繪本 -> 購買付費繪本。我們可以將這個流程設置爲一個漏斗,分析整體以及每一步轉化情況。
此外,漏斗分析還需要定義「窗口期」,整個流程必須發生在窗口期內,纔算一次成功轉化。和事件分析類似,漏斗分析也支持選擇維度分組和時間範圍。
圖注:漏斗分析創建流程
圖注:漏斗分析界面
留存分析
在留存分析中,用戶定義初始事件和後續事件,並計算在發生初始事件後的第 N 天,發生後續事件的比率。這個比率能很好地衡量伴魚用戶的粘性高低。
在下圖的例子中,我們希望瞭解伴魚繪本 app 是否足夠吸引用戶,因此我們設置初始事件爲登錄 app,後續事件爲瀏覽繪本,留存週期爲 7 天,進行留存分析。
圖注:留存分析創建流程
圖注:留存分析界面
架構
在架構上,事件分析平臺分爲兩個模塊,如下圖所示:
-
數據寫入:埋點日誌從客戶端或者服務端被上報後,經過 Kafka 消息隊列,由 Flink 完成 ETL,然後寫入 ClickHouse。
-
分析查詢:用戶通過前端頁面,進行事件、條件、維度的勾選,後端將它們拼接爲 SQL 語句,從 ClickHouse 中查詢數據,展示給前端頁面。
圖注:總架構圖
不難看出,ClickHouse 是構成事件分析平臺的核心組件。我們爲了確保平臺的性能,圍繞 ClickHouse 的使用進行了細緻的調研,回答了以下三個問題:
-
如何使用 ClickHouse 存儲事件數據?
-
如何高效寫入 ClickHouse?
-
如何高效查詢 ClickHouse?
如何使用 ClickHouse 存儲事件數據?
事件分析平臺的數據來源有兩大類:來源於埋點日誌的用戶行爲數據,和來源於「用戶畫像平臺」的用戶屬性數據。本文只介紹埋點日誌數據的存儲,對「用戶畫像平臺」感興趣的同學,可以期待一下我們後續的技術文章。
在進行埋點日誌的存儲選型前,我們首先明確了幾個核心需求:
-
支持海量數據的存儲。當前,伴魚每天產生的埋點日誌在億級別。
-
支持實時聚合查詢。由於產品和運營同學會使用事件分析平臺來探索多種用戶行爲模式,分析引擎必須能靈活且高效地完成各種聚合。
ClickHouse 在海量數據存儲場景被廣泛使用,高效支持各類聚合查詢,配套有成熟和活躍的社區,促使我們最終選擇 ClickHouse 作爲存儲引擎。
根據我們對真實埋點數據的測試,億級數據的簡單查詢,例如 PV 和 UV,都能在 1 秒內返回結果;對於留存分析、漏斗分析這類的複雜查詢,可以在 10 秒內返回結果。
「存在哪」的問題解決後,接下來回答「怎麼存」的問題。ClickHouse 的列式存儲結構非常適合存儲大寬表,以支持高效查詢。但是,在事件分析平臺這個場景下,我們還需要支持「自定義屬性」的存儲,這時「大寬表」的存儲方式就不盡理想。
所謂「自定義屬性」,即埋點日誌中一些事件所獨有的屬性,例如:「下單一對一課程」這一事件在上報時,會帶上「訂單金額」這個很多其它事件所沒有的屬性。如果爲了支持「下單一對一課程」這個事件的存儲,就需要改變 ClickHouse 的表結構,新增一列,這將使得表結構的維護成本極高,因爲每個新事件都可能附帶多個「自定義屬性」。
爲了解決這個問題,我們將頻繁變動的自定義屬性統一存儲在一個 Map 中,將基本不變的公共屬性存爲列,使之兼具大寬表方案的高效性,和 Map 方案的靈活性。
如何高效寫入 ClickHouse?
在設計 ClickHouse 的部署方案時,我們採用了業界常用的讀寫分離模式:寫本地表,讀分佈式表。在寫入側,分爲 3 個分片,每個分片都有雙重備份。
由於事件分析的絕大多數查詢,都是以用戶爲單位,爲了提高查詢效率,我們在寫入時,將數據按照 user_id 均勻分片,寫入到不同的本地表中。如下圖所示:
圖注:將埋點數據寫入到 ClickHouse
之所以不寫分佈式表,是因爲我們使用大量數據對分佈式表進行寫入測試時,遇到過幾個問題:
-
Too many parts error:分佈式表所在節點接收到數據後,需要按照 sharding_key 將數據拆分爲多個 parts,再轉發到其它節點,導致短期內 parts 過多,並且增加了 merge 的壓力;
-
寫放大:分佈式表所在節點,如果在短時間內被寫入大量數據,會產生大量臨時數據,導致寫放大。
如何高效查詢 ClickHouse?
我們可以使用 ClickHouse 的內置函數,輕鬆實現事件分析平臺所需要提供的事件分析、漏斗分析和留存分析三個功能。
事件分析可以用最樸素的 SQL 語句實現。例如,最近一週,北京地區的,發生過繪本瀏覽行爲的用戶,按照年齡段的分佈,可以表述爲:
SELECT
count(1) as cnt,
toDate(toStartOfDay(toDateTime(event_ms))) as date,
age
FROM event_analytics
WHERE
event = "view_picture_book_home_page" AND
city = "beijing" AND
event_ms >= 1613923200000 AND event_ms <= 1614528000000
GROUP BY (date, age);
留存分析使用 ClickHouse 提供的 retention 函數。例如,註冊伴魚繪本後,計算瀏覽繪本的次日留存、7 日留存可以表述爲:
SELECT
sum(ret[1]) AS original,
sum(ret[2]) AS next_day_ret,
sum(ret[3]) AS seven_day_ret
FROM
(SELECT
user_id,
retention(
event = "register_picture_book" AND toDate(event_ms) = toDate('2021-03-01'),
event = "view_picture_book" AND toDate(event_ms) = toDate('2021-03-02'),
event = "view_picture_book" AND toDate(event_ms) = toDate('2021-03-08')
) as ret
FROM event_analytics
WHERE
event_ms >= 1614528000000 AND event_ms <= 1615132800000
GROUP BY user_id);
漏斗分析使用 ClickHouse 提供的 windowFunnel 函數。例如,在 瀏覽繪本 -> 購買繪本,窗口期爲 2 天的這個轉化路徑上,轉化率的計算可以被表達爲:
SELECT
array( sumIf(count, level >= 1), sumIf(count, level >= 2) ) AS funnel_uv,
FROM (
SELECT
level,
count() AS count
FROM (
SELECT
uid,
windowFunnel(172800000)(
event_ms, event = "view_picture_book" AND event_ms >= 1613923200000 AND event_ms <= 1614009600000, event = "buy_picture_book") AS level
FROM
event_analytics
WHERE
event_ms >= 1613923200000 AND event_ms <= 1614182400000
GROUP BY uid
)
GROUP BY level
)
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/eKm6ub3hrNnB9v6xg2196w