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