決策源於數據,而數據源於採集,採集源於規則梳理,讓這一切發生源於工程師的創造力和執行力,本文 5000 字,偏科普向,技術深度通常,閱讀約 10 分鐘,能夠先 Mark 後看,本文最新版會在小冊中進行維護 - 《前端核心能力進階指南》。前端
背景:小菜從 2014 年第一款 APP 上線,到現在將近 5 年,5 年風雨 5 年征程,雖然技術部有 80 人,前端有 20 人,咱們依然對本身所研發的 8 款 APP、4 款小程序、6 款 H5 商城系統、10+ 個 PC CRM/IM/ERP/TMS 中臺運營系統的用戶使用狀況、線上異常狀況、設備分佈狀況、營銷活動的 PV/UV 轉化狀況通通一無所知,由於看不見就不清楚現場,這種作法顯然很不互聯網,也很不符合小菜前端 「工具爲王效率至上」 的技術價值觀。面試
歷史問題和痛點:redis
- toB 產品的多端數據未蒐集,toC 的產品亦然
- 如同一個業務的 RN APP/PC Web(React 單頁/多頁應用)/H5/小程序跨端產品
- 數據埋點散落未作定義及歸類
- 如阿里有位置跟蹤 SPM、資源位跟蹤 SCM、曝光和交互的黃金令牌,咱們通通沒有
- 用戶的線上訪問異常(B 端用戶,可用性穩定性是剛需)無從跟蹤
- 如整個質量體系監控沒有抓手,前端報錯後端報錯,全靠經驗、人肉日誌和用戶主動反饋
- 用戶的訪問行爲/設備特徵/應用性能信息徹底無感知
- 如活躍時間點(避開作發佈),軟硬件系統和設備比例(作兼容),慢頁面優化等無從作起
- 業務數據的效果無從跟蹤
- 如營銷活動轉化效果、支付鏈路的耗時等都很難服務業務決策
其實痛點還太多太多,爲了避免讓本身變成瞎子,咱們決定不管是藉助社區方案,仍是付費,仍是自研,必定要作出一套前端產品埋點監控的工具產品出來,這幾年,咱們也作過一點嘗試,總共走過了 3 段歷程:數據庫
直到今年,咱們最終選擇社區開源方案 + 徹底自研,也就是階段三,幾乎再也不用任何付費產品,投入了 1 個前端全力攻堅,整個項目從立項到落地,差很少用了 60 人日(對,小菜前端就是這麼硬核)。小程序
另外,本文所介紹的整個監控系統屬於小菜前端質量評估與跟蹤體系中的一環,至於端質量體系策劃了兩篇,還沒動筆寫:後端
本文咱們不作質量體系的探討,只聚焦在監控跟蹤實現。瀏覽器
爲了讓你們更直觀的感覺到底咱們作了什麼,作了多少,也便於你們理解後面更技術性的一些選型判斷,先放咱們的數據流向圖、產品功能圖和系統架構圖出來,造成第一觀感及疑問。服務器
數據從用戶訪問頁面那一刻開始,到基於這些數據作出必要的決策結束,整個數據流進來一步步處理掉,能夠分爲 採集、轉發、解密、持久化和處理這幾個核心流程:微信
而整個監控跟蹤,從採集到跟蹤,從產品的視角,能夠拆分出來以下幾個功能模塊:網絡
從實現層面,數據一層層進來,每一層的任務都有對應系統接管處理,整個監控跟蹤的技術架構圖以下:
從核心系統/模塊組成上,能夠簡單分以下幾個:
限於篇幅,咱們只針對每一個系統的設計作介紹,不涉及技術細節,你們想要了解更詳細的信息,或者要更詳細的高清架構圖,能夠加我微信索取: codingdream。
圖上用到了不少名詞,你們能夠搜索下作些越熱,我先嚐試用大白話簡述下它們關係,而後咱們就開始進入系統介紹,內部的關係是:
數據源於採集,而採集源於需求梳理和規則梳理,也就是爲了達到某某某的目的,而必須採集到端上什麼樣的數據,以 PC/H5 爲例,但願採集的數據有以下幾大類:
對這些數據需求作整理,映射到瀏覽器宿主環境下,就須要實現以下一些功能:
技術沒什麼難點,主要是對瀏覽器的特定事件( onerror 、onunhandledrejection、onpopstate 等)進行監聽以及以 AOP 的方式進行包裝一些全局對象的某些特定函數(如 XHR 的 send
),在不影響開發者的狀況下采集必要的數據。
這個過程當中咱們應該注意的是,在對函數或對象進行 wrap 的時候,必定要避免重複包裝,真正花時間的是兼容性的調試,特別是在移動端會遇到一些難點,好比 iOS 設備頻繁發生的 script error
、指紋丟失、iOS 的 sendBeacon
上報到達率低一些問題。
由於要集中管理多個端的 SDK,咱們在搭建這個 SDK 工程時,使用了 monorepo 的方式,TypeScript 實現代碼,部分 SDK 使用 rollup + tsc 打包。
數據從客戶端採集到後,按照必定的策略上報到服務器,先經由 Nginx 拿到 IP 等信息後,直接交由 Transfer,而後將數據發送給 Kafka,讓 Kafka 把數據同步給 ELK。下圖是 DataTransfer 在整個架構中與其餘組件的關係:
這裏的數據轉發器,就是一個 Node 服務,它扮演數據搬運工的角色,將數據轉發給 Kafka 集羣,同時它也作了一些額外的事情,好比數據的解密和驗證,添加額外的必要字段等。
針對 Kafka 咱們作了降級方案,當轉發到 Kafka 失敗的時候,就將數據寫到本地的日誌,而後用 Filebeat 發送給 Logstash,爲何作降級呢,由於咱們自建的 ES 和 Kakfa 正在經歷阿里雲 VPS 從經典到私有網絡的切換,過渡期的幾個月不穩定,咱們這裏就用了兩條腿,優先發送給 Kafka,當 Kafka 不穩定的時候,就由 Filebeat 接管,再推送給 Logstash,每一臺 transfer 上都對應一個 Filebeat 備胎,屬因而過渡性方案。
其實這裏的 Nginx + Transfer 用 Openresty 會更合適,性能也不錯,咱們之因此沒采用,是由於整套設施是前端自行搭建和維護的,用 Eggjs 搭建的 Transfer 服務,不想引入額外的語言棧加大後期的維護成本,就用了 Nginx + Node Transfer(Filebeat)。
至於工程的實現,咱們依然使用了 TS,服務框架用的是 Eggjs,針對 Eggjs 寫了一個 egg-kafka 插件用於 kafka 的消息收發,該插件也算是這次項目的收穫之一。
數據若是沒有介入到團隊的決策,那就失去了蒐集的價值,既然是決策,無非就是信息的聚合展現以及各類任務的增刪改查,而這個角色就有監控後臺 Dashboard 承擔。
Dashboard 在總體架構中與其餘模塊的關係如圖所示:
ELK 三大件中最好用的莫過因而 Kibana,爲何咱們不用呢,其實咱們也不是不用,而是給到部分小場景去靈活使用,之因此沒有徹底使用,是由於咱們但願跟前端團隊有更強的關聯性,好比用戶身份、issue 的推動、任務的跟蹤、將來代碼倉庫分支的異常關聯、質量報告的評估等等,這些業務屬性太強,而 Kibana 顯然不便於咱們作很靈活的擴展,因此就沒有以它做爲 Dashboard。
Dashboard 的數據來源主要有兩個,ES 和 阿里雲的 RDS(MySQL)。
ES 扮演的就是日誌數據庫的角色,他提供查詢的能力,而 Dashboard 就是無腦的從 ES 獲取實時數據,好比剛剛 15 分鐘的異常數量,或者今天到目前爲止某個應用的 PU/V ,訪問的設備類型分佈等等,以下圖,某個應用大盤的數據:
或者該應用異常發生狀況:
每個特定的異常,咱們能夠點擊詳情查看相應的異常詳情,跟蹤到用戶的 ID、設備及廠商、瀏覽器版本、頁面、發生時間、IP、地理位置甚至角色身份等更細節的數據信息,再結合異常的回溯重放和 Sourcemap,便於咱們第一時間跟進了解和修復。
甚至 API 請求出錯的狀況也能查看:
MySQL 中存儲的數據是咱們經過下節會講到的 Controller 對存儲在 ES 中的錯誤原始數據進行分類和抽象而獲得 issue 信息、以及開發者爲了監控某個特殊 issue 而制定的規則和相應的任務信息,
針對每一個 issue ,不管是前端仍是後端,到底哪些被跟進修復了,修復狀況如何,均可以跟蹤到:
同時,針對用戶的某一次的一系列動做咱們會有一個 session 的概念,上報數據時會生成一個 sessionId 而後透出到 issue 詳情中,便於開發者在解決錯誤時查看用戶具體操做了什麼,而後能更好地解決問題:
目前這個頁面還作得比較粗糙,畢竟沒有專門設計師
issue 的大體生命週期以下,其中大多數狀態變動的操做是開發者在 dashboard 上實現的:
前端和後端結合起來聯動查看,能夠更快速的解決問題,再配合上異常的識別和斷定機制,能夠更主動的把異常推到前端和後端的釘釘羣裏,甚至復發的問題會 @ 當事人,關於 issue 的斷定咱們放到後面再來說:
當開發者須要對某個 issue 特別 "關照" 時,能夠針對該 issue 設置相應的報警規則,下文提到的 controller 會根據報警規則生成報警任務,下圖就是一個簡單的報警任務:
咱們還能看到該任務的執行狀況:
後臺還有不少其餘實用的功能,好比 issue 查看分配指派與分類、更新流水、報警任務查看編輯、錯誤信息回溯、各類質量週報的生成推送等,更多截圖在文後。
技術實現上,後端咱們使用的是基於 Eggjs 封裝的 Cross 搭建的工程,集成了 Kafka 和釘釘等,其中 kafka 用於和其餘模塊交流;前端則使用了 AntDesign Pro(umijs/dva/bizcharts),此次考慮到是功能多變且業務性強,就沒有使用 TS。
前面提到的 Dashboard 最大的做用是消費、修改以及管理 issue 數據,而從原始數據中抽象出 issue 數據給 dashboard 消費的則是 controller,固然,controller 的做用不止於此,咱們會在下面展開來講,這裏先貼出其在整個架構中的與其餘模塊的關係圖,讓你們對其在整個架構中的角色有一個大體的認識:
Controller 在整個架構中的做用相當重要,主要體如今如下幾個方面:
任務控制器是一個純後端項目,它依然經過 kafka 與其餘模塊進行交流,由於其功能比較明確因此咱們採用 TypeScript 編寫,後端框架依然是咱們團隊基於 Eggjs 自研的 Cross。而報警任務隊列是經過 redis 實現的。
做爲任務控制器的小弟,任務執行器 Instpector 作的事情就很純粹,就是解析從 controller 發送過來的任務,而後對原始進行查詢最後返回結果,可是考慮到任務可能會比較多,咱們在設計時是將其設計爲多點的,利用 kafka 的消息單播的特色,儘量讓任務儘快地執行。
實現執行器也是用 TS 開發,框架爲 Eggjs, 比較簡單。
這個系統的建設並非一蹴而就的,咱們在過去兩年使用過很多社區現有的產品,也自研過不完善的方案,從中積累了很多經驗,沒有這些沉澱,咱們也沒辦法作出如今的這個系統。
整個系統麻煩在於設計而不是實現,你們動手以前,能夠先考慮清楚本身的應用場景,指望解決的問題是什麼,也就是弄清楚 What 和 Why,以後再考慮是否投入人力進行設計和實現,畢竟整個系統建設下來,仍是須要必定的技術實力和很多人力的。
截至目前,這個系統並不是達到最理想的狀態:
但即使如此,上線這 3 個月以來,咱們能看到端產品上的行爲數據和異常狀況了,對產品體驗的提高或者降低更有感知,對問題的跟蹤修復也更有效率了,用戶對於產品的負面反饋也在一每天的減小,我想,這也算是一個不錯的開始吧。
再補兩張 DashBoard 截圖:
Scott 近兩年不管是面試仍是線下線上的技術分享,遇到許許多多前端同窗,因爲團隊緣由,我的緣由,職業成長,技術方向,甚至家庭等等緣由,在理想國與現實之間,在放棄與堅守之間,搖擺不停,心酸硬扛,你們能夠找我聊聊南聊聊北,對工程師的宿命有更多的瞭解,有更多的看見與聽見,Scott 微信: codingdream