解密Lego:客戶端日志系統(tǒng)的演進(jìn)
引言
埋點(diǎn)對于移動(dòng)應(yīng)用來說至關(guān)重要,無論是賦能業(yè)務(wù)增長,還是優(yōu)化技術(shù)實(shí)現(xiàn),埋點(diǎn)數(shù)據(jù)和技術(shù)日志都為決策和優(yōu)化提供了關(guān)鍵依據(jù)。轉(zhuǎn)轉(zhuǎn)App也有著一套自研的日志采集系統(tǒng)(Lego),從2015年轉(zhuǎn)轉(zhuǎn)App上線第一個(gè)版本到現(xiàn)在,Lego逐步從一個(gè)單一功能架構(gòu)演變?yōu)橹С肿詣?dòng)化采集、實(shí)時(shí)上報(bào)、業(yè)務(wù)與技術(shù)日志隔離的復(fù)合架構(gòu)。
Lego演進(jìn)歷程
總結(jié)起來,可以分為四個(gè)階段:
- 從零到一建設(shè)能力;
- 業(yè)務(wù)埋點(diǎn)與技術(shù)日志拆分;
- 提高核心埋點(diǎn)實(shí)時(shí)性;
- 架構(gòu)升級性能提升。
本文將為大家介紹客戶端在Lego升級的四個(gè)階段中的設(shè)計(jì)思路和解決方案。
Lego:從零到一
背景
- 移動(dòng)開發(fā)早期(2015 年)階段,移動(dòng)設(shè)備資源(CPU,內(nèi)存,電量)有限,網(wǎng)絡(luò)環(huán)境不穩(wěn)定(網(wǎng)速慢,連接質(zhì)量差);
- 業(yè)界技術(shù)實(shí)現(xiàn)普遍注重低功耗,低開銷實(shí)現(xiàn)數(shù)據(jù)的采集上報(bào);
- 埋點(diǎn)相對較少,業(yè)務(wù)規(guī)模相對較小;
架構(gòu)設(shè)計(jì)
在上面的背景下,首先面對不穩(wěn)定的網(wǎng)絡(luò)環(huán)境,采用合并多個(gè)埋點(diǎn)的數(shù)據(jù),將數(shù)據(jù)寫入本地文件的方式,盡量減少接口請求的頻次,防止網(wǎng)絡(luò)傳輸不穩(wěn)定導(dǎo)致數(shù)據(jù)丟失,較低的上報(bào)頻次,同時(shí)也減輕服務(wù)端的壓力;并且將埋點(diǎn)數(shù)據(jù)文件壓縮處理后再上報(bào)以節(jié)省網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)流量開銷。其次由于應(yīng)用主進(jìn)程運(yùn)行內(nèi)存有限,又涉及數(shù)據(jù)格式化,文件寫入,文件壓縮,網(wǎng)絡(luò)接口上報(bào)等操作,采用獨(dú)立子進(jìn)程的方式處理可以避免擠占主進(jìn)程的資源,同時(shí)隔離影響,由此有了下面的架構(gòu)設(shè)計(jì):
Lego初始架構(gòu)
圖中可見,應(yīng)用主進(jìn)程通過啟動(dòng)Service(后臺服務(wù))實(shí)現(xiàn)與子進(jìn)程數(shù)據(jù)通信,發(fā)送配置更新,寫日志和上傳日志的指令和數(shù)據(jù)到 Lego 子進(jìn)程。然后在子進(jìn)程中進(jìn)行初始化配置,將日志數(shù)據(jù)格式化寫入文件,在動(dòng)態(tài)配置的時(shí)間間隔(默認(rèn)兩分鐘)或者接收到主動(dòng)觸發(fā)的上傳指令時(shí),將日志文件壓縮后通過接口上傳,成功后則刪除壓縮文件,否則在下次發(fā)送時(shí)機(jī)觸發(fā)時(shí),再次嘗試上傳。
架構(gòu)特點(diǎn)
- 獨(dú)立內(nèi)存空間:采用子進(jìn)程做日志處理上報(bào),子進(jìn)程擁有獨(dú)立的內(nèi)存空間,避免擠占應(yīng)用主進(jìn)程的內(nèi)存等資源;
- 進(jìn)程隔離,穩(wěn)定性高:子進(jìn)程獨(dú)立與主進(jìn)程運(yùn)行,如果子進(jìn)程在執(zhí)行日志寫入或上傳時(shí)崩潰,不會(huì)影響App主進(jìn)程的正常運(yùn)行。這樣大大提高應(yīng)用的穩(wěn)定性與用戶體驗(yàn);
- 性能開銷低:子進(jìn)程中將日志數(shù)據(jù)寫入文件,每兩分鐘合并發(fā)送一次,可以減少頻繁的接口請求,減輕服務(wù)端壓力的同時(shí)減少應(yīng)用的性能開銷。
- 節(jié)省流量:客戶端經(jīng)過格式化數(shù)據(jù),寫入本地文件后,每兩分鐘將日志文件壓縮后上傳到數(shù)據(jù)服務(wù)端,服務(wù)端接收數(shù)據(jù)后再進(jìn)行文件解壓縮,落盤,清洗,落表。
Lego4APM:業(yè)務(wù)埋點(diǎn)與技術(shù)日志拆分
背景
- 用戶規(guī)模增長,精細(xì)化和自動(dòng)化決策運(yùn)營的內(nèi)在需求,迫切需要強(qiáng)實(shí)時(shí)性的數(shù)據(jù)采集,上報(bào),處理;
- 業(yè)務(wù)埋點(diǎn)與APM 日志混合上報(bào),未做區(qū)分,給大數(shù)據(jù)部門的數(shù)據(jù)處理造成時(shí)效性壓力;
- 客戶端本身也需要將性能相關(guān)的埋點(diǎn)統(tǒng)一化,規(guī)范化,需要有新的聚合維度;
實(shí)現(xiàn)方案
上報(bào)的實(shí)現(xiàn)還是采用 Lego 的原有架構(gòu),復(fù)制了新的組件 Lego4APM,將上報(bào)的數(shù)據(jù)服務(wù)接口換成技術(shù)埋點(diǎn)的專用接口,將技術(shù)日志與業(yè)務(wù)埋點(diǎn)分流。按照日志級別劃分,聚合原有的性能日志埋點(diǎn),再將原有的日志采集接口的底層上報(bào)邏輯直接遷移到新組件。
拆分后結(jié)構(gòu)圖
Lego業(yè)務(wù)與技術(shù)埋點(diǎn)拆分結(jié)構(gòu)圖
圖中ZPM為基于轉(zhuǎn)轉(zhuǎn)位置模型自研的自動(dòng)化埋點(diǎn)采集框架,采集完的數(shù)據(jù)通過 Lego 上報(bào),APM則是性能監(jiān)控框架采集技術(shù)日志,通過Lego4APM組件上報(bào),其中 Lego 與 Lego4APM 是相同實(shí)現(xiàn)的兩套獨(dú)立的組件。
LegoRealtime:提高實(shí)時(shí)性
背景
將用戶行為埋點(diǎn)與 APM 日志通過 Lego 和 Lego4Apm 分流后,做到數(shù)據(jù)隔離,但是Lego 原有設(shè)計(jì)是多埋點(diǎn)合并上報(bào),每2 分鐘壓縮文件后上報(bào)一次,為實(shí)現(xiàn)自動(dòng)化運(yùn)營的整體方案,客戶端要盡可能保證在 200ms 時(shí)延內(nèi)完成核心用戶行為的采集上報(bào),提高實(shí)時(shí)性。
方案設(shè)計(jì)
方案設(shè)計(jì)階段我們也調(diào)研前端的方案,是直接采用的接口上報(bào),但是作為移動(dòng)端,需要發(fā)揮移動(dòng)端的特性,下面是實(shí)時(shí)版本設(shè)計(jì)思路。
LegoRealtime 架構(gòu)圖
方案實(shí)現(xiàn)關(guān)鍵
- 數(shù)據(jù)備份容災(zāi):考慮移動(dòng)端的環(huán)境多樣問題,容易出現(xiàn)了異常,弱網(wǎng),斷網(wǎng)的情況,數(shù)據(jù)備份很必要,同時(shí)也要區(qū)分日志是實(shí)時(shí)的,還是異常備份數(shù)據(jù),涉及日志記錄的狀態(tài)修改,數(shù)據(jù)庫備份比文件備份更合適。
- 異常數(shù)據(jù)重傳機(jī)制:在網(wǎng)絡(luò)連接恢復(fù),應(yīng)用重新啟動(dòng),以及固定時(shí)間間隔,對異常數(shù)據(jù)進(jìn)行批量重傳;
- 簡單格式化,高效處理:實(shí)時(shí)上傳只利用了https本身支持的內(nèi)容壓縮,未做額外的壓縮等處理,直接以json格式上傳數(shù)據(jù),數(shù)據(jù)服務(wù)端在處理數(shù)據(jù)時(shí)相比壓縮格式上報(bào),不需要額外的解壓縮處理,更高效。
- 穩(wěn)定可控:方案設(shè)計(jì)之初就考慮上線后如何控制穩(wěn)定遷移以及數(shù)據(jù)驗(yàn)證的問題,增加了灰度控制開關(guān)和數(shù)據(jù)驗(yàn)證接口。
遷移方案
- 無侵入遷移:為了避免大量更改原有業(yè)務(wù)埋點(diǎn)的接入代碼,我們選擇通過攔截原有 Lego 上報(bào)的接口,通過白名單控制核心埋點(diǎn)走實(shí)時(shí)上報(bào),對原有接入業(yè)務(wù)無侵入,降低影響范圍。
- 上線穩(wěn)定控制:配置 ABTest灰度開關(guān),方案驗(yàn)證階段,先按照10%的灰度比例切換到實(shí)時(shí)上報(bào),觀察數(shù)據(jù)完整性,后端服務(wù)的穩(wěn)定性,驗(yàn)證通過后逐步增大比例到 50%,穩(wěn)定運(yùn)行一周后全量切換。
- 數(shù)據(jù)質(zhì)量驗(yàn)證:
- 時(shí)效性方面,通過 APM 后臺的監(jiān)控?cái)?shù)據(jù),確認(rèn)Lego 實(shí)時(shí)上報(bào)接口的往返時(shí)延是否達(dá)到低時(shí)延設(shè)計(jì)目標(biāo)。
- 完整性方面,采用了實(shí)時(shí)埋點(diǎn)通過實(shí)時(shí)方式和文件壓縮合并方式同時(shí)上報(bào)的方案來驗(yàn)證數(shù)據(jù)完整性,其中文件壓縮合并方式使用的是Lego4APM,因?yàn)榧夹g(shù)日志落盤數(shù)據(jù)與業(yè)務(wù)數(shù)據(jù)是隔離的,將這部分?jǐn)?shù)據(jù)上報(bào)到技術(shù)埋點(diǎn)不會(huì)污染業(yè)務(wù)數(shù)據(jù),用以驗(yàn)證完整性非常合適。
驗(yàn)證結(jié)論
- 性能平臺監(jiān)控到,實(shí)時(shí)上報(bào)接口的平均往返時(shí)延為 160ms,發(fā)送時(shí)延按一半估算為80ms,遠(yuǎn)遠(yuǎn)低于設(shè)計(jì)目標(biāo)的200ms,為大數(shù)據(jù)端數(shù)據(jù)處理預(yù)留了操作空間;
- 由于實(shí)現(xiàn)的機(jī)制不同,Lego實(shí)時(shí)上報(bào)的數(shù)據(jù)比 Lego4APM 上報(bào)的數(shù)據(jù)多 1%,在合理范圍內(nèi);
Lego 新架構(gòu):性能提升
背景
- 業(yè)務(wù)方面:
- 某些場景存在后臺啟動(dòng)服務(wù),存在隱私合規(guī)問題;
- 數(shù)據(jù)組反饋數(shù)據(jù)重復(fù)上報(bào)問題,以及埋點(diǎn)缺失問題;
- 技術(shù)方面:
- 應(yīng)用市場反饋 Lego 相關(guān)的卡頓問題(當(dāng)埋點(diǎn)量較多時(shí),頻繁從主進(jìn)程發(fā)送埋點(diǎn)數(shù)據(jù)和配置到子進(jìn)程,每次數(shù)據(jù)交互都是 IPC,這會(huì)擠占系統(tǒng)的 binder 通信的資源,Android系統(tǒng)的各種服務(wù)包括頁面的創(chuàng)建,點(diǎn)擊事件的交互等都是使用 binder 通信實(shí)現(xiàn),容易引發(fā)卡頓問題)
- 多進(jìn)程配置管理復(fù)雜,相同的配置主進(jìn)程配置后需要再同步至子進(jìn)程,這給組件的升級維護(hù)帶來了額外的成本。
- Lego 和 Lego4APM相同功能的多套代碼,修改出現(xiàn)分叉,維護(hù)成本增高;
- Lego 項(xiàng)目由來已久,實(shí)現(xiàn)方案不符合于移動(dòng)端內(nèi)存相對充足,性能過剩的現(xiàn)狀;
新方案架構(gòu)設(shè)計(jì)
基于業(yè)務(wù)和技術(shù)多方面因素考慮,我們對 Lego進(jìn)行了重新設(shè)計(jì),新架構(gòu)如下圖:
Lego 新架構(gòu)設(shè)計(jì)
圖中可以看到,新架構(gòu)采用的是子線程方案,在主進(jìn)程創(chuàng)建Lego 實(shí)例,通過實(shí)例進(jìn)行配置管理,寫日志和上傳觸發(fā), 同時(shí)實(shí)例通過創(chuàng)建HandlerThread 子線程,在子線程中進(jìn)行日志文件寫入和壓縮上傳。
新方案優(yōu)點(diǎn)
- 無需IPC,開銷低:老架構(gòu)的子進(jìn)程方案需要頻繁的 IPC,且更改配置時(shí),主進(jìn)程和子進(jìn)程都要維護(hù),而新架構(gòu)在同一進(jìn)程中,線程間內(nèi)存共享,無需要 IPC的額外性能消耗,卡頓問題自然解決,配置只需要保證線程安全即可。
- 無隱私合規(guī)問題:老架構(gòu)某些場景觸發(fā)后臺啟動(dòng)服務(wù)實(shí)現(xiàn)IPC,而上報(bào)數(shù)據(jù)包含位置信息,用戶設(shè)備 id等隱私數(shù)據(jù),引發(fā)隱私不合規(guī)問題,新架構(gòu)中無需IPC,也就不需要從后臺啟動(dòng)服務(wù)了。
- 支持多實(shí)例,易維護(hù):非核心用戶行為埋點(diǎn)和 APM 埋點(diǎn)的上報(bào)實(shí)現(xiàn)基本一致,老架構(gòu)需要多份復(fù)制,額外占用系統(tǒng)進(jìn)程,同時(shí)維護(hù)成本大,新架構(gòu)支持多個(gè)實(shí)例后,兩種上報(bào)只需要兩個(gè)實(shí)例,兩套配置即可,性能和維護(hù)成本上沒有額外的消耗。
- 上報(bào)穩(wěn)定:老架構(gòu)存在重復(fù)上報(bào),埋點(diǎn)缺失的問題,新架構(gòu)中通過 HandlerThread 的事件循環(huán)隊(duì)列實(shí)現(xiàn)寫日志與上傳日志串行執(zhí)行。防止邊上傳邊寫入容易造成重復(fù)上報(bào)和缺失的問題。
版本遷移方案
Lego、Lego4APM作為客戶端的基礎(chǔ)能力,承載著客戶端所有業(yè)務(wù)及技術(shù)埋點(diǎn),一旦出現(xiàn)問題,對于客戶端來說將是災(zāi)難。對如此重要的組件進(jìn)行重構(gòu),面臨巨大的風(fēng)險(xiǎn),需要制定一個(gè)穩(wěn)妥的、漸進(jìn)的、對上層業(yè)務(wù)無感知的遷移方案。計(jì)劃將版本遷移拆分為兩個(gè)階段:
- 階段一:對照驗(yàn)證,通過選定指定埋點(diǎn),對比新老版本埋點(diǎn)數(shù)量及參數(shù)是否在合理范圍內(nèi),驗(yàn)證時(shí)間全量后兩天,驗(yàn)證通過進(jìn)入第二階段,驗(yàn)證不通過則停止版本遷移,定位問題后下個(gè)版本繼續(xù)進(jìn)入階段一。
- 階段二:版本切換,按用戶比例逐步切換到新版Lego,用戶比分為三個(gè)階梯:10%、50%、100%,每個(gè)階梯灰度一周時(shí)間,期間觀察核心業(yè)務(wù)埋點(diǎn)指標(biāo)(如登錄PV/UV、詳情頁P(yáng)V/UV、訂單PV/UV)是否正常。
遷移后埋點(diǎn)數(shù)據(jù)對比結(jié)果
驗(yàn)證結(jié)論:新版本埋點(diǎn)數(shù)據(jù)的內(nèi)容完整沒有缺失,并且比舊版本的數(shù)據(jù)量多1%
總結(jié)與展望
Lego系統(tǒng)結(jié)構(gòu)
上圖是目前轉(zhuǎn)轉(zhuǎn)客戶端的Lego日志系統(tǒng)結(jié)構(gòu)圖,其中包含了數(shù)據(jù)采集和數(shù)據(jù)上報(bào)兩個(gè)部分。業(yè)務(wù)核心埋點(diǎn)數(shù)據(jù)由ZPM(轉(zhuǎn)轉(zhuǎn)位置模型自動(dòng)化采集框架)采集,通過LegoRealtime組件實(shí)時(shí)上報(bào);業(yè)務(wù)其他埋點(diǎn)則是手動(dòng)埋點(diǎn)采集,通過基于Lego新架構(gòu)的Lego4Buz實(shí)例上報(bào);技術(shù)日志用APM日志框架(性能監(jiān)控)采集,由基于Lego新架構(gòu)的Lego4APM實(shí)例上報(bào)。
通過這些優(yōu)化和升級,不僅增加數(shù)據(jù)上報(bào)的可靠性和實(shí)時(shí)性,還顯著提升了穩(wěn)定性,降低了維護(hù)成本。在這個(gè)過程中也收獲了寶貴的經(jīng)驗(yàn),在實(shí)現(xiàn)日志上報(bào)功能時(shí),我們不僅需要考慮如何減少不必要的性能開銷,發(fā)揮客戶端的優(yōu)勢,合并上報(bào)以減輕服務(wù)器的壓力,同時(shí)我們還需要確保新舊版本的平滑過渡和安全遷移,制定周全的遷移方案,以便在出現(xiàn)問題時(shí)能夠?qū)崟r(shí)回退,做到安全可控。
關(guān)于埋點(diǎn)上報(bào)的優(yōu)化,我們還有其他的演進(jìn)方向,如LegoRealtime實(shí)時(shí)上報(bào),頻繁的https接口請求,可以替換成其他低功耗傳輸方式;而Lego新架構(gòu)的異常處理方面,在服務(wù)異常時(shí)會(huì)頻繁重試,可能會(huì)讓系統(tǒng)異常問題雪上加霜。此外,大日志文件上傳的策略優(yōu)化等方面,還有演進(jìn)升級的空間,如采取拋棄策略,避免影響整體運(yùn)行,或者拆分成小文件縮短上報(bào)時(shí)間,提高成功率。
總之,升級之路是不斷優(yōu)化和改進(jìn)現(xiàn)有方案的過程,我們將繼續(xù)尋求更加高效、穩(wěn)定和安全的實(shí)現(xiàn)方式,推動(dòng)Lego系統(tǒng)的不斷演進(jìn)和升級。

















