目錄
- 前言
- 需求背景
- 解決什么問題
- 行業通用方案
- 定制化
- 系統架構與融合
- 基本構成
- 系統關聯融合
- 高效運維
- 小結
- 數據收集與分析
- 數據收集
- 數據錄入
- 數據分析
- 問題發現與解決
- 自動化集成測試
- 數據聚合
- 數據庫
- 結語
前言
在上一篇文章《前端監控SDK開發分享》中,對客戶端SDK
的實現做了分享。這篇文章將會分成四節(需求背景
、系統架構與融合
、數據收集與分析
、問題發現與解決
)分享介紹我們是如何打造前端監控系統的。
一、需求背景
1.1 解決什么問題
客戶端常常會遇到如下一些問題:
- 白屏
- 無響應
- 卡頓
- 服務異常
- bug無法復現
- 等等
面對這些運行在用戶端的問題,前端常常表示很無奈,解決這些問題之前,我們需要先知道客戶端發生了什么,於是我們可以想到:
- 收集錯誤,解決報錯、兼容性等問題
- 收集性能,解決慢查詢、慢加載等問題
- 收集接口,發現接口錯誤、打通服務端監控
- 收集多方面輔助信息,綜合多方面分析
為了實現收集功能,我們需要提供一個前端監控平台,它能夠收集數據、處理數據、存儲數據、查詢數據。其實就有很多現成的平台或者開源項目我們可以直接使用。
1.2 行業通用方案
前端技術發展至今,相信大家已經對前端監控的這件事情非常熟悉,或多或少都會在我們的項目中用上它。比如搭建使用開源項目sentry
、付費平台阿里的ARMS
、甚至小程序配套的前端監控服務。
(1). sentry
sentry
主要提供的功能是收集錯誤。支持大多流行語言的客戶端和服務端,不支持小程序,但是目前有大公司根據sentry
的上報數據結構,自己實現了小程序SDK
並開源,目前關注度和流行度都偏低。除開錯誤,它的其它類型的前端監控能力相對來說很弱。
(2). 阿里ARMS
ARMS
提供的功能與支持的客戶端比較齊全,小程序也支持。只是需要付費。總體來說提供的功能還是比較全面、符合國內的環境。
(3). 小程序自帶監控
微信小程序不斷的在完善內部的監控,各方面的功能也慢慢豐富了起來,但是只能支持小程序本身。
在使用這些開源或者平台前端監控服務的時候,始終有一些不足。比如:
- 系統分散
- 很難滿足增加一些自定義數據和查詢需求
- 特性一直不更新、
BUG
解決周期長 - 二次開發難度大
1.3 定制化
早期我們使用sentry
,隨着公司多方面的發展,已經發現到sentry
不能滿足好幾個方面的需求了。
如果完全從0到1來打造一套前端監控系統,成本也是很高的。甚至在早期,都可能沒人願意用,系統是否能立項或者持續發展下去也是一個問題。於是從一些開源項目中去尋找,去找一個方便改造也有一定功能模塊的項目。在2019年底,我們找到了zanePerfor,因為它功能比較豐富,使用node+mongo
符合我們前端的技術棧,也配套支持了微信小程序。
之后,我們開始基於它的代碼,進行長期的改造和迭代。慢慢的改造成為一個更適合公司內部環境的一個前端監控系統。下一節,聊聊目前的系統基本構成、企業內部系統之間的關聯融合、以及運維服務如何保駕護航。
二、系統架構與融合
2.1 基本構成
- 客戶端SDK
- web
- 小程序
- ios
- andriod
- 服務端 node+EggJs
- 數據庫 Redis Mongo+mongooseJs(orm)
- 管理台 Vue+ElementUI
為了實現前端監控,第一要素是要收集客戶端數據,為了方便客戶端集成監控系統、我們需要首先開發封裝一個統一的SDK、去幫助我們收集數據。在早期,客戶端方面我們優先支持的是web
和微信小程序,隨着系統的迭代現在也支持了native
。
SDK
收集了數據,我們還需要通過服務端接口來接收,在服務端,使用node+EggJs
,node
適合i/o
密集型場景,符合前端技術棧。eggjs
簡單易用、文檔友好,大部分使用node
的前端程序員都應該能很快上手。
服務端收集到數據並進行一些處理之后,我們需要存儲到我們的數據庫之中。在數據庫方面,使用mongo
做持久化存儲,mongo
文檔模型數據庫,數據擴展方便,類json
結構方便和node
配合使用,天生適合日志系統。使用redis
做數據緩存,redis
簡單易用的高性能key-value
數據庫,市場上占據主流,被大部分人都熟知。
最后,還需要一個管理台,做數據查詢與管理。管理台使用Vue+ElementUI
,簡單快速。
下圖是目前系統技術關系圖:
客戶端SDK
收集數據上報,node
服務端獲取到數據后,先存在redis
中,node
服務會根據消費能力去拉取redis
數據處理分析后存儲到mongo
之中,最后我們通過管理后台展示處理好的應用數據。
當初步的實現了我們的前端監控以后,我們還接入了公司內部現有的優質系統,豐富功能、提高了易用性、減少了工作量。
2.2 系統融合與關聯
- SSO系統
- 加入內部導航黃頁
- 本地日志系統 finder elasticsearch
- APM系統 skywalking
- 告警平台
- 操作日志平台
- SPA平台
(1) 接入內部SSO系統
企業內部我們有一套SSO
單點登錄系統,系統會為每個員工注冊一個賬戶,可以通過賬戶密碼、企業微信掃碼或者微信掃碼等方式登錄。統一登錄,不僅僅是解決了登錄不同系統之間的賬戶密碼和登錄方式問題,還更方便系統之間的相互跳轉和接口請求。
(2) 加入內部導航黃頁
在內部的導航頁加入我們的項目,大家使用方便進入。
(3) 本地日志系統
前端監控系統的node
后端服務,也會產生服務的本地日志。通過存儲日志到約定目錄,運維服務將會幫我們收集,並且提供了兩個查詢系統:finder
和elasticsearch
。finder
按照時間和文件夾結構划分,它的查看視角就像直接通過服務器看本地的日志一樣,大部分時候我們更習慣用它。 elasticsearch
主要適合搜索的方式查詢。
(4) APM系統 skywalking
前端監控系統的node
后端服務,除了系統本地產生的運行日志,它同樣應該被后端的監控系統所監控。APM
應用性能管理,目的是通過各種探針采集數據,收集關鍵指標,同時搭配數據呈現以實現對應用程序性能管理和故障管理的系統化解決方案。我們企業內部統一使用skywalking
,我們的大部分服務主要是java
。skywalking
提供了node
探針,使我們的項目也能夠接入。接入之后,我們便可以通過skywalking
管理台查詢到后端node
服務的性能以及調用情況了。
traceId
,APM
工具會在服務端生成traceId
,它標示一次調用的上下文id
,通過此id
可以查詢所做事情的足跡鏈。后端服務可以通過前端http
請求把這次調用的traceId
通過響應頭返回給客戶端。前端監控的前端SDK
探針便可以收集traceId
,通過收集到它,前端監控就可以打通后端監控。在前端監控管理后台,我們不僅可以看到前端的監控網絡日志,還可以通過traceId
查詢到后端鏈路信息。
(5) 告警平台
前端監控系統需要實時或定時的推送一些告警郵件等,內部告警平台提供了告警策略配置、並會拉取前端監控數據。接入告警平台可以減輕前端監控系統本身的剛需工作量。
(6) 操作日志平台
在網關層,操作日志平台可以攔截我們的管理台操作請求,以此來記錄用戶的系統操作。幫助我們做敏感操作追溯以及報警等。
(7) SPA平台
SPA
平台是公司內部自研的靜態資源發布平台,可以通過它半自動化管理業務項目,配置注入、靜態資源管理等。前端監控在收集到壓縮代碼的報錯時,需要通過sourceMap
文件解析轉換為源代碼。大部分前端監控方案,需要手動上傳sourceMap
文件到監控系統,使用SPA
平台后,資源被統一管理,我們可以通過內部配置直接把sourceMap
文件存放在約定的位置,免去業務方手動上傳,提高了易用性。
當我們的系統的功能都已經實現,關聯系統也成功融合以后,程序要穩定友好的運行在線上,還需要我們的運維服務來保駕護航。
2.3 高效運維
- 日志抓取
- 自動化構建
- 容器化
- 負載均衡
- 健康檢測、安全關閉
- 等等
健康檢測、安全關閉
前端監控隨時都會收到業務方上報的數據,這個系統在重啟的時候,必須保障服務不間斷,也要保障在關閉的時候,是安全的不會丟失數據。當我們更新了代碼,重新構建的時候,首先會預先啟動新的容器,當新的容器啟動完成后,逐步關閉替換舊的服務,舊服務也會在關閉前收到通知,停止接收新處理任務,當所有正在執行的任務處理完后再被關閉。
一個完整的線上系統,離不開運維服務,它做的很多事情、甚至是我們平時不知道的,我們開發人員應當關注並了解它。
2.4 小結
內部的獨立系統,各自負責某塊任務,系統之間互相關聯,運維服務保駕護航,構建了企業內部的生態環境,減少了很多重復的工作,也同樣可以讓某一個領域的系統做的更加深入和完善。
目前我們已經介紹了前端監控系統的需求背景和系統的構成情況,下一節我們將會稍微詳細的說明一下我們最核心的數據收集與分析。
三、數據收集與分析
3.1 數據收集
(1)性能
收集Native
熱冷啟動、Web
頁面加載、靜態資源、ajax
接口等性能信息,指標有加載時間、http
協議版本、響應體大小等,這是為業務整體質量提升提供數據支撐,解決慢查詢問題等。
(2)錯誤
收集Native
和js
報錯、靜態資源加載錯誤、ajax
接口加載錯誤,這些常規錯誤收集都很好理解。下面主要說明一下"業務接口錯誤(bussiness)":
客戶端發送ajax
請求后端業務接口,接口都會返回json
數據結構,而其中一般都會有errorcode
和message
兩個字段,errorcode
為業務接口內部定義的狀態碼。正常的業務響應內部都會約定比如errorcode==0
等,那如果不為0
可能是一些異常問題或者可預見的異常問題,這種錯誤數據就是需要收集的。
由於不同團隊或者接口可能約定都不一樣,所以我們只會提供一個預設方法,預設方法會在ajax
請求響應后調用,業務方自己根據約定和響應的json
數據,在預設的方法中編寫判斷邏輯控制是否上報。像是下面這樣:
errcodeReport(res) {
if (Object.prototype.toString.call(res) === '[object Object]' && res.hasOwnProperty('errcode') && res.errcode !== 0) {
return { isReport: true, errMsg: res.errmsg,code: res.errcode };
}
return { isReport: false };
}
(3)輔助信息
除了上面兩類硬指標數據,我們還需要很多其它的信息,比如:用戶的訪問軌跡、用戶點擊行為、用戶ID、設備版本、設備型號、UV/UA標識、traceId
等等。很多時候我們要解決的問題並不是那么簡單直接就能排查出來,甚至我們需要前端監控和其它系統在某些情況下能夠關聯上,所以這些軟指標信息同樣很重要。
數據收集之后,並不能直接錄入到數據庫之中,而是要經過一定的處理。下面聊聊數據錄入的兩個過程。
3.2 數據錄入
(1)SDK過濾
一些三方的業務接口和資源等,有一定請求量,甚至它們自己也會會常常報錯。或者總有一些我們內部的接口我們並不想要做收集,這些數據收集起來會污染我們的數據視角,影響我們查看管理台數據。客戶端SDK
提供過濾配置,業務方可以根據具體業務過濾一些不需要收集的接口等。或者內置一些企業約定過濾的接口路徑。
(2)服務端處理
SDK
上報的數據,服務端也是需要經過二次處理再保存,例如為了查詢方便對原始數據做拆分等。
3.3 數據分析
當我們的數據已經錄入到數據庫以后,我們就可以對我們的數據應該分析和查詢了。除了管理台基礎的數據查詢功能,我們也會提供圖表和日報,來幫助我們滿足不同的場景。
3.3.1 日報
日報可以從已有的數據中,篩選出重點信息和分析后的內容,雖然平台就在那里,但是可能大家有時候真的不怎么關注。日報的匯報目標對象目前主要是開發和測試人員。
3.3.2 圖表
圖表只是一種數據的展示形式,比如頁面性能加載實時圖表,實時錯誤圖表。在大部分情況下,可能我們都不會一直關注着,但是比如上線新版本的時候,我們可以一直打開關注它的變化。圖表是數據視角的一種補充。
經過前面3節,對前端監控系統的功能都大致介紹完了。第四節,我們主要分享一下在打造前端監控系統的過程中,我們遇到過哪些問題,我們是如何解決的。
四、問題發現與解決
4.1 自動化集成測試
JS-SDK
屬於一個需要長期維護和更新的獨立庫,它被使用在很多業務項目中。隨着代碼量和特性的增加、人工測試成本變得越來越高,開發過程伴隨強烈的不安全感,測試覆蓋率低的可怕。於是從無到有,我們開始完善自動化集成測試。
我們的JS-SDK
主要是加入探針監聽業務項目的運行狀態而收集信息,集成測試是我們關注的重點。我們的Web SDK
運行環境依賴Web
瀏覽器環境,而不能單純的在node
之中運行。目前我們有兩種測試方式並存。
通過終端測試,可以幫助我們支持持續集成環境(代碼提交倉庫以后托管平台提供的環境中進行托管測試)。
通過瀏覽器測試,可以讓代碼運行在最真實的環境中,也可以做瀏覽器的兼容測試。
4.2 數據聚合
在管理台視角,我們是需要將數據進行聚合歸類的,這是為了讓我們更清晰的查看我們的監控數據。但是一些原因會對數據造成聚合影響。
(1) 動態路由
有部分接口使用動態路由設置參數,如xxx.com/api/getuid/15501/detail
。此類接口會導致根據url
無法聚合同一個接口,因此SDK
默認會把此類接口的動態參數部分替換為*
。替換后上面的鏈接變成xxx.com/api/getuid/*/detail
。
這樣我們就能在服務端把他們歸類為一個接口。目前是正則匹配的全數字,剛好內部有此類接口的服務參數部分都是純數字。如果動態參數部分會存在非純數字的參數就會無法判別。只有SDK
提供配置列表,業務方去一一配置相關鏈接,讓SDK
自動替換。但是這樣對業務方使用不友好,也不好維護。所以一旦有此類情況發生,最好的建議就是用?
或者消息體的方式帶參數吧!
(2) 接口錯誤信息不固定
前端監控收集到ajax
業務錯誤響應信息以后,會按照接口路徑+錯誤信息
的方式聚合同一個錯誤。有發現過一個接口響應的錯誤信息帶了隨機值,隨機值可能是當前請求的配置的唯一id
。大致如下:
{
errMsg: '發生了異常(d1nbj1az5)',//括號內的為隨機值
errcode: 1
}
解決方法就是,和服務端約定好,如果需要返回額外設置一個字段,而不是放在錯誤信息中。
4.3 數據庫
4.3.1 表設計
在迭代native
版本時,對於表結構設計有多種方案的考慮。對於日志系統,最終決定還是使用反規范化設計,通過犧牲空間來提高吞吐。
4.3.2 查詢優化
(1)索引
當數據量變得越來越大,查詢越來越慢時。我們對索引做了調整,以時間字段建立索引,同時客戶端查詢條件默認定義合理的時間范圍,以此來優化查詢速度。並適當的使用復合索引。
(2)慢查詢
在早期,一些慢查詢、比如分鍾級定時任務使用的mapReduce
語句,拉低了數據庫性能,通過一定的優化、低效語句替換,我們解決了這些慢查詢。線上優化前數據庫24小時平均cpu
使用率78%,優化后為27%。下圖便是測試環境優化后的效果截圖,峰值發生了明顯下降。
4.3.3 獨享數據庫
最初前端監控系統和其他業務系統共享使用雲數據庫。由於前端監控在某段時期存在數據庫慢查詢的問題,而這個慢查詢剛好也是分鍾級別的定時任務。導致共享數據庫有很多慢查詢記錄,CPU
消耗也一直維持在較高位置。前端監控本身也會保持一定的監控數據並發量在做存儲。前端監控拖累了整個數據庫,並且由於慢查詢日志很多,導致其它業務在排查數據庫慢日志的時候,很難找到他們自己的日志。后來,運維同事就給單獨配置了一個獨享數據庫給前端監控。
遷移前配置12核32g三節點(一主兩從),遷移后為2核4g三節點。雖然配置變小了,但是前端監控獨享數據庫后平均響應速度反而變快了。前端監控的數據是屬於日志數據,量更大,導致數據庫性能下降,影響到業務數據服務。日志系統的數據庫和業務分離也是正確合理的。
當然系統的迭代過程中還有很多問題和細節,這里就不一一列舉了。
結語
目前前端監控系統已經運行1年多,服務公司幾十個應用,它仍然有很多不足,它也一直保持規划和迭代。記錄於此,繼續努力。
End