本文來自 2020年4月25日,前端早早聊第五屆「前端搞監控」專場分享嘉賓 - 釘釘前端團隊監控負責人 燭象(slashhuang) 的分享實錄《釘釘前端-如何設計前端實時分析及報警系統》。前端
你們好,我是來自釘釘的燭象,我今天的題目是《釘釘前端團隊如何打造億級流量的監控系統》。web
首先來個個人我的介紹。我是 2013 年畢業,2017 年來到釘釘的,入職釘釘的時候是 P6,而後經過作前端監控、作一些模塊化代碼包、效率等工具,順利的獲得了一些晉升的機會。小程序
釘釘從 2014 年末創業至今,發展極其迅速,釘釘前端監控也在相應的演進。咱們有億級的用戶和千萬級的企業用戶,前端產品有安卓、iOS、桌面端、小程序、 H5等,前端應用的發佈也涵蓋全量發佈、灰度發佈的狀況。api
億級流量的挑戰瀏覽器
對於這樣一個億級平臺,除了作前端監控系統以外,我相信不少小夥伴也有體感,要保證總體釘釘前端的穩定性,還須要有一些技術運營的手段,包括人的一些狀況。咱們如今總體有 100 多個前端開發成員,而後咱們的技術模塊上面有 IM、通信錄、直播、教育、文檔、硬件等等很是具備 B 端屬性的業務。服務器
我先說一下咱們的成果: 100% 覆蓋了咱們今天全部的 h5 和小程序、支撐了 100 多個前端人員的監控需求。前端監控的日誌量達到百億,監控大盤個數超過 100 個,能作到線上問題一分鐘感知和一分鐘模糊問題定位。在人力投入上面,始終維持在兩個負責人員之內,大部分狀況下是我一我的爲主在負責總體的一個監控狀況,因此在人力投入上面,咱們的成本是相對比較低的。
上圖中的兩張趨勢圖是咱們監控的主要產品結構,一張是咱們的監控趨勢圖,另外一張是咱們的業務大盤文件夾用於承載各個業務,同時,咱們有一個生產環境的統一小程序、H5 監控大盤。微信
接下來我會講一下,關於釘釘前端監控,咱們是如何對系統進行演進,拿到一個不錯的結果。markdown
考慮到有不少小夥伴們不是搞前端監控的,因此這邊我會先講一些基礎知識來展開如何設計一個前端監控系統。架構
咱們來看一下上面這段代碼,const 建立一個對象,而後 foot.a.b = c。能夠看到這是段很是經典的 NPE 代碼,就是 null point exception,在前端代碼中很是容易出現。這邊會拋出一個錯誤:** Uncaught TypeError: Cannot set property 'b' of undefined**。模塊化
對於這樣一個錯誤,在用戶側發生以後,咱們的前端監控系統是怎樣去捕獲這個錯誤,而且在一分鐘以內發現?咱們來看一下一傳統的作法是怎麼作的:
我這邊演示的是用 image 標籤,建立一個 image 標籤,設置它的 src 指向對應的日誌服務器來發送對應的日誌。
咱們對錯誤的採集採用的是 window.onerror 來捕獲全局錯誤。而後將捕獲的錯誤經過建立 image 標籤形式發送到上圖右側的前端監控服務端。
如上的代碼只是一個僞代碼演示,我寫的比較簡單。
對於一個傳統的基於日誌分析的監控系統,你首先要知道這條日誌究竟是來自哪裏,因此咱們對每一條日誌在前端採集的時候,都有一個應用 id,姑且我這邊稱之爲 spmId ,經過 spmId 來標識日誌源,而後將這條日誌存儲到對應的監控服務端,這樣就完成了一個很是簡單的從前到後的一個鏈路。
從日誌發生、採集,而後再到存儲的一個閉環,很是簡單。其實見微知著,看到這麼一個簡單的實現,再把日志類型進行豐富,採集和存儲作的強大一點,基本上就能夠去搭建一個比較簡單的前端監控系統了。
通常而言,一個簡單的前端監控分析系統須要包含以下三個維度:
在監控平臺,咱們須要作一些日誌存儲,將監控日誌提供給可視化平臺服務器,經過提供一些 API 服務就能夠畫出上面這樣一個圖。好比第 1 個是接口成功率。
我以爲在技術選型上面,對於不少稍微有點 Node 或者服務端基礎的前端同窗來講,基本上能作出一個簡單的 Demo。然而,這樣一個看似功能很完備的系統,對於作前端監控來講,有沒有什麼問題?是否是可以知足釘釘這樣一個億級流量平臺的監控需求?
上圖左邊展現的是咱們的開發人員接入前端監控的過程,包括開發階段、測試階段、上線階段。 在前端監控推行的過程當中,咱們要求全部的開發人員在應用迭代上線後,要主動觀察監控大盤至少 30 分鐘,觀察三個指標:
對於目前咱們 100 多個前端同窗的團隊規模來講,人力成本是 100 乘以 30 分鐘,同時對於釘釘這個企業級產品而言,咱們對線上的穩定性要求是很是高的,對線上故障容忍度極低,所以還要求每日對線上應用進行巡檢,所以人力成本很是高。
從開發人員的體驗角度看,一個開發人員查看監控的時候:第 1 個他會去可視化分析平臺上去看有沒有錯誤日誌。這邊有一個很是重要的點,就是說咱們監控分析平臺看到的日誌,是否是"前端頁面"的日誌?
不必定是。爲何?由於對於用戶來講,它不只僅是打開了前端頁面,這個前端頁面背後還有容器的 webview、應用容器、運營商等。
舉個例子,咱們一個頁面能夠在微信的容器裏面打開、能夠在頭條的容器裏面打開、能夠在釘釘容器裏面打開。因此你採集的日誌源不只僅是一個前端頁面,還有容器的 webview,同時咱們還會面臨不少的運營商。好比說咱們常常看到前端頁面裏插了一段廣告,而後咱們還有一些手機的製造商,好比vivo、華爲等,也會在咱們的頁面裏面插入相關的腳本。因此監控分析平臺採集到的日誌不只僅是前端日誌,他採集到的範圍其實是前端頁面對應的用戶終端日誌。
通常咱們會碰到以下三種干擾日誌:
舉個例子,如上是咱們線上的一個應用,大概 js error 率是 0.08%, 對於釘釘這樣的體量來講,這個錯誤率影響用戶的數量已經很是大了。
咱們來看一下它對應的錯誤其實是什麼?Script error,WeixinJSBridge is not defined, toutiaoJSBridge is not defined, 20 vivoNewsDetailPage,這些東西從錯誤信息基本上能夠判斷跟業務錯誤基本沒啥關係。
因此咱們能夠獲得第 1 個結論,就是前端監控產生的一部分錯誤實際上跟業務無關,這個可能跟不少人的認知是相悖的。
咱們再來看一個問題,左圖是咱們桌面端的發佈曲線,釘釘是國內甚至是全球爲數很少的很是重桌面端的平臺。釘釘桌面端基本上是一個禮拜或者兩個禮拜一個迭代,因爲桌面端的前端代碼是採用離線包的形式,所以代碼的更新修復是比較困難的,對前端穩定性的要求很是的高。
對於咱們今天的桌面端而言,已經有 100 多個線上發佈版本了,這麼多的版本上報的日誌採用的是同一個應用id,咱們如何去作分層監控,線上流量的不均如何作好分層監控,避免小流量的發版監控被淹沒?
這些問題在釘釘的業務場景是常常碰到的,咱們的監控顆粒度須要和前端的發版相適應,而且監控的日誌須要支持更多的維度。好比說以應用和發佈版本,這兩個變量爲單位進行監控。
咱們再看一個案例,釘釘有幾百個前端應用,每一個應用報警 1 次就很是誇張了,基本上一天報警羣就有 500 多條日誌,刷屏現象很是嚴重,並且不少錯誤是線上的長尾錯誤。也就是它雖然有報警,可是不須要去修改等等。長尾錯誤出現的緣由是我雖然修復了問題,可是用戶那邊不必定徹底訪問的是最新的版本。
因此結論 3 就是咱們監控運營的人力成本很是高,對於前端監控的要求不只僅是要報警報出來,還須要你的報警是直觀的、實時的,同時要支持一些短時關閉和錯誤過濾等等手段。
看完上面這三個案例後,咱們來看一下究竟該如何設計一個可以服務 3 億體量的監控系統。
首先,咱們先界定監控設計的目標,釘釘企業級前端監控須要作到的事情是: 一分鐘感知、5 分鐘定位、10 分鐘恢復。姑且稱這個監控系統爲 2.0 系統。
咱們對於前端監控 2.0 在 1.0 的基礎上定義了以下的能力水位。
第 1 個是要貼近實際業務,下降人力運營成本、業務方可以低成本介入。同時對於報警體系,要求作到快報警、準報警,而且支持自定義報警。咱們內部定了一個基準線,就是前端監控精度必須達到 90% 以上,人力成本必須減小 20 分鐘每個人,而且報警和大盤須要可以支持自定義配置。
上圖是總體的監控的組件編排方案。左邊是一個圖例,藍色部分表明的是 1.0 的監控組件,墨綠色的部分表明 2.0新增的監控組件。
自定義採集
第 1 個在日誌採集端,除了採集常規的業務數據和監控數據以外,支持自定義採集。
分析智能化
分析智能化這一塊增長了分析可自定義的能力。
報警實時化
在報警實時化這一塊,增長了線上1分鐘報警和5分鐘定位的要求。
最關鍵的技術實現
一樣,藍色部分是原有的 1.0 的一個體系,墨綠色部分是咱們新增的體系。咱們會發如今日誌採集在和日誌消費端,咱們增長了一個模塊叫作日誌雙寫。
一份日誌被兩個系統所消費,一份系統用於實時去報警,一份系統用於去作分析:
不少同窗會以爲日誌雙寫實際上是一個很是大的系統的浪費,一份日誌被兩個系統所消費了。實際上釘釘前端監控藉助了阿里很是成熟的日誌消費系統和基礎設施。經過日誌分發兩路被快速消費,讓分鐘計算系統在整個監控體系裏面的編排是前置的,達到 1 分鐘報警的要求,這是咱們在這一塊裏面最核心的一個技術思路。
在上圖的紫色虛線下方,是咱們的用戶視角。用戶側觸碰到的是兩塊,第 1 塊是前端監控 SDK,咱們有 H5 和小程序的 SDK,第二塊是平臺,包括分析平臺和報警平臺。
真實案例
咱們來看一個真實的案例。用戶碰到了兩個 js error 。這兩個 js error 都是前端經典的 NPE 錯誤。
第 1 個是發生在 iPad + 百度瀏覽器。第 2 個是發生在安卓 + 頭條 webview ,結果咱們會發現,咱們客戶端上報過來的錯誤有兩種:
可能不少同窗沒有觀察過。咱們是仔細去排查過的。百度瀏覽器會注入 MyAppHrefLink is not defined。頭條的也會去注入一些頭條 jsBridge 。
日誌到達服務端後,咱們先對日誌進行清洗,把全部宿主的干擾日誌都過濾掉,確保咱們的報警系統是消費的真正的業務發生的日誌錯誤。這是黃色區域的第一個模塊: 日誌清洗
接下來咱們進行日誌分組,將應用 A spmId=A 和應用 B 的日誌進行分組,經過應用標識 A 和 B 進行分組。將過濾過來的日誌進行實時計算。
通過這一步後,再將日誌流轉到報警指標項進行實時計算,這個報警規則引擎下發相關的指令到 Map Reduce 對應的機器上去作一些處理。
好比 JS Error 失敗率= JS Error 日誌條數除以 PV 條數。當對日誌進行計算的結果大於 6%,則進行釘釘羣報警 ,當失敗率大於 15% 則進行短信報警。
監控日誌
經過將一樣的流程應用到各個不一樣的指標項,好比 api 成功率、js error 失敗率、pv 數據等咱們就能夠在分鐘計算系統搭建出一套知足 1 分鐘感知的監控系統。
報警系統架構
關於報警系統,上圖咱們阿里研發事業部那邊的一個很是經典的監控系統,有興趣的同窗能夠在 infoQ 上搜索 sunfire 看到更詳細的架構介紹,這裏不作過多展開。
總體日誌架構總結
基本上這就是我今天想要分享的,釘釘前端監控在從 1.0 演進到 2.0 的過程當中,咱們是如何思考和如何落地的。這邊的話我給你們稍微簡單總結一下:
好,這就是我今天想要分享的,釘釘前端監控是如何賦能釘釘這樣一個億級體量、100 多個前端、600 多個前端頁面的線上穩定性的。
下面是釘釘前端的技術專欄,有知乎專欄、有掘金專欄,咱們一直在廣納賢才,歡迎聯繫我。