序言
埋點數(shù)據(jù)作為推薦、搜索、產(chǎn)品優(yōu)化的基石,其數(shù)據(jù)質(zhì)量的重要性不言而喻,而要保障埋點數(shù)據(jù)的質(zhì)量,埋點驗證則首當(dāng)其沖。工欲善其事必先利其器,要做好埋點驗證會面臨很多技術(shù)挑戰(zhàn):易用性、準(zhǔn)確性、實時性、穩(wěn)定性、擴展性,如何攻克這些挑戰(zhàn)呢,其實還是技術(shù),這也是本文的主旨所在。
目前埋點驗證已在字節(jié)內(nèi)部得到廣泛使用,通過一鍵掃碼開啟驗證、實時上報驗證、自動生成驗證報告,解決了埋點數(shù)據(jù)驗證難、埋點質(zhì)量保障難的問題。
埋點驗證流程
埋點生命周期:4+6
- 4 個角色:PM、DA、RD、QA
- 6 個節(jié)點:提出需求、設(shè)計埋點、開發(fā)埋點、測試埋點、上報埋點、分析埋點
- 埋點驗證流程:3+3+3
- 3 個角色:DA、RD、QA
- 3 個節(jié)點:設(shè)計埋點、測試埋點、驗收埋點
- 3 個物料:埋點驗證方案、埋點驗證工具、埋點驗證報告
技術(shù)架構(gòu)
產(chǎn)品流程
先簡單介紹一下產(chǎn)品,以便大家能對平臺有整體認(rèn)識,方便大家更加輕松地理解技術(shù),平臺主要包括三部分:埋點驗證方案、埋點驗證工具、埋點驗證報告,三者相輔相成,極大的降低了用戶的埋點驗證成本。
- 附埋點驗證工具圖
技術(shù)架構(gòu)圖
埋點驗證的鏈路很長,可以簡單概括為三個環(huán)節(jié):埋點上報、埋點接收、埋點驗證,每個環(huán)節(jié)都有一定的復(fù)雜性,此處先介紹整體流程,讓大家可以快速對全流程有所認(rèn)識。其次將主要聚焦于“埋點驗證”環(huán)節(jié),此環(huán)節(jié)的重中之重是埋點驗證引擎,它包括 4 個部分:規(guī)則生成器、規(guī)則選擇器、埋點驗證器和埋點推送器,通過對埋點驗證引擎的詳解讓大家對“埋點如何驗證”有更深的理解。
- 埋點上報環(huán)節(jié)重點是豐富的 SDK(客戶端、服務(wù)端、JS、Chrome 插件),要做到簡單易用并且保證埋點實時上報。
- 埋點接收環(huán)節(jié)重點是數(shù)據(jù)接收服務(wù)(客戶端-applog、Web 端-mcs、服務(wù)端-databus)、數(shù)據(jù)保存服務(wù)(消息隊列),要保證服務(wù)穩(wěn)定并且保證埋點不丟失。
- 埋點驗證環(huán)節(jié)重點是埋點驗證引擎,要確保服務(wù)高性能并且保證埋點驗證結(jié)果的準(zhǔn)確性。
規(guī)則生成器
規(guī)則生成器將“埋點驗證方案”轉(zhuǎn)換為“驗證規(guī)則”。埋點驗證方案是驗證規(guī)則的邏輯視圖,方便用戶操作,降低驗證規(guī)則的編寫和維護成本。通過邏輯視圖和物理視圖兩層邏輯,確保了埋點驗證引擎底層不受業(yè)務(wù)變化的影響。
埋點方案
埋點驗證方案支持 2 種:
- 按需求驗證:即新建需求計劃,針對某次需求驗證、
- 按元數(shù)據(jù)驗證:即按元數(shù)據(jù)驗證,元數(shù)據(jù)是指所有需求的并集
按元數(shù)據(jù)驗證:
- 埋點名稱:video_play
- 參數(shù)信息
- (名稱、類型、是否必填、值校驗、是否是場景條件)
- enter_from,string,必傳,固定值(login),是
- duration,integer,必傳,值無限制,否
- type,integer,必傳,枚舉(1,2,3),否
埋點數(shù)據(jù):
{
"app_id":100,
"event":"click",
"params":{
"enter_from":"login",
"duration":1,
"type":3
}
}
埋點規(guī)則
{
"app_id":100,
"event_name":"video_play",
"logical_filter":{
"enter_from":"login"
},
"meta":{
"required_field":[
"duration",
"enter_from",
"type"
],
"scene":{
"condition":"enter_from=login",
"name":"登錄頁"
},
"validate_field":[
"duration",
"enter_from",
"type"
]
},
"physical_validation":"{\"$schema\":\"https://json-schema.org/draft/2019-09/schema\",\"type\":\"object\",\"properties\":{\"params\":{\"type\":\"object\",\"properties\":{\"duration\":{\"type\":\"integer\"},\"enter_from\":{\"type\":\"string\",\"enum\":[\"login\"]},\"type\":{\"type\":\"integer\",\"enum\":[1,2,3]}},\"required\":[\"duration\",\"enter_from\",\"type\"]}},\"required\":[\"params\"]}",
"source":"schema_scene"
}
埋點規(guī)則字段說明
- app_id:應(yīng)用 id
- event_name:埋點名稱
- logical_filter:用于“規(guī)則選擇器”
- physical_validation:用于“埋點驗證器”
- source:區(qū)分規(guī)則來源:按需求驗證、按元數(shù)據(jù)驗證
規(guī)則選擇器
規(guī)則選擇器將依據(jù)“埋點”中的關(guān)鍵信息,從“驗證規(guī)則池”中選擇出對應(yīng)的“埋點驗證規(guī)則”。
- 選擇邏輯:具體數(shù)據(jù)參考“規(guī)則生成器”
- 根據(jù)“埋點數(shù)據(jù)”中 app_id 和 event 從“驗證規(guī)則池”中篩選出“匹配的規(guī)則”
- 將“埋點數(shù)據(jù)”的 parms 字段和“匹配的規(guī)則”的 login_filter 規(guī)字段進(jìn)行匹配,選擇出最終的“埋點驗證規(guī)則”
埋點驗證器
埋點驗證器將依據(jù)“基礎(chǔ)驗證規(guī)則”以及“規(guī)則選擇器”產(chǎn)出的“埋點驗證規(guī)則”,對“埋點數(shù)據(jù)”進(jìn)行驗證并產(chǎn)出“驗證結(jié)果”。
- 基礎(chǔ)驗證規(guī)則:埋點是否登記;埋點是否禁用;是否是 debug 埋點;
- 埋點驗證規(guī)則:參數(shù)是否丟失;參數(shù)類型是否正確;參數(shù)取值是否符合預(yù)期:枚舉、范圍、正則;
- 埋點驗證結(jié)果:驗證結(jié)果提供雙語格式,用戶可自行選擇中文或者英文;
埋點推送器
埋點推送器將“埋點驗證結(jié)果”推送到前端,推送的過程存在數(shù)據(jù)交互頻繁、數(shù)據(jù)體積大、數(shù)據(jù)傳輸穩(wěn)定性的要求,這里我們自建 Push 服務(wù)進(jìn)行數(shù)據(jù)傳輸,保證數(shù)據(jù)實時可達(dá)。
技術(shù)挑戰(zhàn)
- 易用性:快速接入埋點驗證,快速開始埋點驗證
- 準(zhǔn)確性:埋點驗證結(jié)果準(zhǔn)確、用戶可信
- 實時性:埋點數(shù)據(jù)實時可見
- 穩(wěn)定性:埋點數(shù)據(jù)可靠不丟失
- 擴展性:快速接入新的埋點數(shù)據(jù)格式
易用性
快速接入埋點驗證,快速開始埋點驗證
SDK
- 快速接入埋點驗證
- SDK 提供“埋點驗證開關(guān)”,客戶端集成 SDK 的時候,可根據(jù)不同環(huán)境來配置是否開啟“埋點驗證開關(guān)”
- SDK 層判斷如果開啟“埋點驗證開關(guān)”,埋點數(shù)據(jù)會雙發(fā),此過程對業(yè)務(wù)是透明的
- 雙發(fā)的原因或者為什么不從“線上埋點通道”取數(shù)?這里主要考慮兩個原因:
- “線上埋點通道”數(shù)據(jù)量太大
- SDK 層線上上報邏輯是采用微批的形式,默認(rèn) 1 分鐘從客戶端上報一次,而埋點驗證要求實時性,所以采用單獨的通道
端 | SDK | 如何開啟埋點驗證開關(guān) |
客戶端 | Android SDK IOS SDK | Android、IOS 提供 API,開關(guān)默認(rèn)是關(guān)閉的,業(yè)務(wù)側(cè)集成的時候可選擇在“域內(nèi)測試包”打開此開關(guān) |
服務(wù)端 | Go SDK Java SDK Python SDK | 服務(wù)端會自行判斷是否是非線上環(huán)境,如果是非線上環(huán)境,會默認(rèn)開啟“埋點驗證開關(guān)” |
web 端 | JS SDK 瀏覽器插件 | 1. JS SDK 采用和客戶端 SDK 一樣的邏輯 2. 為了使用方便,我們也提供了瀏覽器插件,用戶只需打開此插件即可,無需關(guān)注“埋點驗證開關(guān)” |
掃碼連接
- 快速開始埋點驗證
- 連接流程
- 建立 WS 連接:服務(wù)端和驗證平臺建立長連接,用于通信
- ws_id:驗證平臺根據(jù) ws_id 生成二維碼
- 掃碼:客戶端掃描二維碼
- 獲取并打開驗證開關(guān):客戶端獲取設(shè)備信息并且打開埋點驗證開關(guān)
- 上報 device_id:客戶端將長連接信息和設(shè)備信息上報至服務(wù)端
- 下發(fā) device_id:服務(wù)端將設(shè)備信息推送到驗證平臺
- 開始驗證:埋點驗證平臺進(jìn)入驗證階段
- 上報埋點:客戶端開始上報埋點
- 推送埋點:服務(wù)端將埋點推送到驗證平臺
- 下發(fā)原理
- 客戶端上報的埋點數(shù)據(jù)中含有設(shè)備信息
- 用戶通過掃碼在驗證平臺回填設(shè)備信息
- 服務(wù)端接收到埋點數(shù)據(jù)后,將埋點數(shù)據(jù)中的設(shè)備信息和驗證平臺的設(shè)備信息進(jìn)行匹配,如果匹配則將埋點數(shù)據(jù)進(jìn)行下發(fā)
準(zhǔn)確性
埋點驗證結(jié)果準(zhǔn)確、用戶可信
埋點驗證引擎必須保證埋點驗證結(jié)果的準(zhǔn)確性,才能降低驗證成本。針對埋點數(shù)據(jù)本身的格式驗證,我們采用了 JsonSchema 作為驗證手段,以支持完善的驗證規(guī)則、可信的驗證結(jié)果。上文中的“規(guī)則生成器”、“規(guī)則選擇器”、“埋點驗證器”也都在一定程度上保證了埋點驗證結(jié)果的準(zhǔn)確性。
埋點方案
event:video_play
- 埋點名稱:video_play
- 參數(shù)信息
- (名稱、類型、是否必填、值校驗、是否是場景條件)
- enter_from,string,必傳,固定值(login),是
- duration,integer,必傳,值無限制,否
- type,integer,必傳,枚舉(1,2,3),否
埋點規(guī)則
jsonSchema
{
"$schema":"https://json-schema.org/draft/2019-09/schema",
"type":"object",
"properties":{
"params":{
"type":"object",
"properties":{
"duration":{
"type":"integer"
},
"enter_from":{
"type":"string",
"enum":[
"login"
]
},
"type":{
"type":"integer",
"enum":[
1,
2,
3
]
}
},
"required":[
"duration",
"enter_from",
"type"
]
}
},
"required":[
"params"
]
}
埋點數(shù)據(jù)
event:video_play
{
"app_id":100,
"event":"click",
"params":{
"enter_from":"login",
"duration":1,
"type":3
}
}
驗證結(jié)果
event:video_play
- 測試地址:https://www.jsonschemavalidator.net/
實時性
埋點數(shù)據(jù)實時可見
埋點驗證場景下,服務(wù)端和驗證平臺需要頻繁地進(jìn)行數(shù)據(jù)交互,所以我們自建了 Push 服務(wù)(基于 WebSocket 的封裝),能夠保證數(shù)據(jù)的實時暢通性
Push 服務(wù)目標(biāo)
- 基于 WebSocket 實現(xiàn)一套通用長連接通訊協(xié)議,能實現(xiàn)同一個客戶端上的不同業(yè)務(wù)共享同一個長連接通道,并實現(xiàn)可靠的心跳機制。
- 客戶端和服務(wù)端基于通用長連接通訊協(xié)議實現(xiàn)一個穩(wěn)定可靠的全雙工通道。
- 客戶端實現(xiàn)一個通用的 SDK,服務(wù)端實現(xiàn)一個通用接入層。
- 客戶端 SDK,服務(wù)端接入層,都要很方便后續(xù) service 接入。
- Push 服務(wù)定期做打點監(jiān)控,同時開放 http 的 Admin 接口,方便系統(tǒng)的監(jiān)控和查看服務(wù)狀態(tài)
Push 服務(wù)優(yōu)勢
- 連接穩(wěn)定性:Push 服務(wù)分為兩個組件 Push 和 Backone,實現(xiàn)了業(yè)務(wù)和推送解耦。push 面向客戶端連接,設(shè)計盡可能簡單,需保持大量客戶端活躍連接,避免了業(yè)務(wù)服務(wù)更新時不影響客戶端連接
- 服務(wù)隔離性:不同的業(yè)務(wù)服務(wù)接入 push 服務(wù),會根據(jù)接入信息做集群隔離,避免業(yè)務(wù)之間互相影響
- 橫向擴展性:當(dāng)業(yè)務(wù)服務(wù)不斷增多時,只需對 push 服務(wù)做橫向擴容即可支持
Push 服務(wù)流程
穩(wěn)定性
埋點數(shù)據(jù)可靠不丟失
SLA
- 定義:服務(wù)級別協(xié)議 (service-level agreement,即 SLA) 是服務(wù)提供方與客戶之間的正式承諾,用來量化服務(wù)水平(質(zhì)量、可用性、責(zé)任)
- 埋點驗證服務(wù):服務(wù)的特征是實時,所以衡量埋點驗證不可用的手段是“數(shù)據(jù)延遲”,即埋點從“上報”->“驗證平臺”的 p99 超過 3s 即視為不可用,日常 p99 在 1s
可用性 | 雙月故障時間 | 年故障時間 |
99.9% | 86.4m | 8.64 h |
措施
- 為了保證“SLA”,我們做了一系列的保護措施
- 日志轉(zhuǎn)換器:客戶端、服務(wù)端、web 端上報的是原始日志格式,需要轉(zhuǎn)換為埋點驗證日志格式后進(jìn)行驗證
措施 | 說明 |
監(jiān)控 | 為了保證線上服務(wù)的穩(wěn)定性,對線上流量進(jìn)行監(jiān)控,支持按 app 粒度進(jìn)行查看 app 粒度的 QPS,以便發(fā)生報警的時候,可以快速定位到具體是哪個 app 的流量異常 |
報警 | 對線上流量進(jìn)行報警,報警策略的設(shè)置如下:- 當(dāng)前 QPS 達(dá)到最大 qps 的 50%的時候,報警級別為 warning,提示需要注意- 當(dāng)前 QPS 達(dá)到最大 qps 的 70%的時候,報警級別為 critical,提示必須處理 |
限流 | 當(dāng)發(fā)生報警的時候,通過監(jiān)控定位出具體 app,做如下處理:1. 針對此 app 數(shù)據(jù)進(jìn)行限流,確保其他 app 不會受到影響 2. 聯(lián)系 app 業(yè)務(wù)方,確認(rèn)此 app 流量是否為異常流量 3. 如果是異常流量,對異常流量進(jìn)行處理,處理后撤銷限流 4. 如果是正常流量,那么埋點驗證服務(wù)進(jìn)行處理 |
降級 | 實時驗證流程是當(dāng)前的主要業(yè)務(wù),當(dāng)發(fā)現(xiàn)流量突增,限流無法解決的情況下,對自動化驗證流程進(jìn)行降級,確保主要業(yè)務(wù)的穩(wěn)定性 |
擴展性
快速接入新的埋點數(shù)據(jù)格式
- 提供可插拔的“日志轉(zhuǎn)換器插件”,服務(wù)高內(nèi)聚,可支持各種日志格式快速接入、驗證
展望
埋點驗證是保障埋點質(zhì)量的有效方式,此方式屬于事前驗證,適用于埋點頻繁變化的業(yè)務(wù)場景,需要一定程度的人工介入,能夠解決基本的埋點質(zhì)量問題。但是對于核心埋點場景來說,這種方式的驗證成本較高,需要重復(fù)的人力投入,為了解決核心埋點驗證成本高的問題,我們正在探索落地其他方式:
- 回歸驗證(自動化驗證):伴隨每次發(fā)版,核心埋點都需要進(jìn)行回歸驗證,目前我們通過內(nèi)部其他團隊的合作實現(xiàn)了自動化驗證功能來支撐回歸驗證,當(dāng)前已有一部分業(yè)務(wù)正在使用,極大地降低了驗證核心埋點的成本
- 事后驗證:經(jīng)過事前驗證、回歸驗證,埋點質(zhì)量基本能得到很好的保障。但為了更好的保障我們也在探索事后驗證的場景和落地:
- 質(zhì)量大盤:通過“規(guī)則引擎”,結(jié)合“質(zhì)量模型”對埋點數(shù)據(jù)進(jìn)行質(zhì)量評估,得出各個維度的“質(zhì)量評分”,然后針對質(zhì)量問題進(jìn)行專項修復(fù),進(jìn)一步提高埋點質(zhì)量。
- 質(zhì)量工具:提供監(jiān)控計劃,業(yè)務(wù)可以針對自己關(guān)注的埋點配置監(jiān)控報警,當(dāng)線上出現(xiàn)質(zhì)量問題,會發(fā)送質(zhì)量報告給業(yè)務(wù),及時止損。
- 全鏈路埋點質(zhì)量保障:事前驗證、回歸驗證、事后驗證貫穿埋點的生命周期,打通這三個流程,從而形成埋點質(zhì)量保障全鏈路,徹底解決埋點質(zhì)量問題。