本文首發於 infoQ 及「前端之巔」微信公衆號(微信羣直播記錄),感謝 infoQ 前端之巔尾尾同窗對文章的整理和校對、微信羣直播的組織策劃前端
一般在一個大型的 Web 項目中有不少監控,好比後端的服務 API 監控,接口存活、調用、延遲等監控,這些通常都用來監控後臺接口數據層面的信息。並且對於大型網站系統來講,從後端服務到前臺展現會有不少層:內網 VIP、CDN 等。可是這些監控並不能準確地反應用戶看到的前端頁面狀態,好比:頁面第三方系統數據調用失敗,模塊加載異常,數據不正確,空白開天窗等。這時候就須要從前端 DOM 展現的角度去分析和收集用戶真正看到的東西,從而檢測出頁面是否出現異常問題node
頁面一般出現如下問題時須要使用郵件、短信通知相關人員修復問題nginx
狀態碼返回錯誤(50x, 40x)沒法打開git
模塊加載失敗github
頁面亂碼web
數據正確性編程
觸發報警時要有現場快照,以便復現問題後端
監控的意義和迴歸測試的在本質上是一致的,都是對已上線功能進行迴歸測試,但不一樣的是監控須要作長期的可持續可循環的迴歸測試,而測試僅僅須要在上線以後作一次迴歸瀏覽器
既然監控和測試的本質一致,那咱們徹底能夠採用測試的方式來作監控系統。在自動化測試技術遍地開花的時代,不乏不少好用的自動化工具,咱們只須要把這些自動化工具進行整合爲咱們所用便可緩存
NodeJS - 特別適用於網絡密集型任務
PhantomJS - 模擬無界面的瀏覽器,提供豐富的內核交互 API
NodeJS 是一個 JavaScript 運行環境,非阻塞 I/O 和異步、事件驅動,這幾點對於咱們構建基於 DOM 元素的監控是很是重要的
PhantomJS 是一個基於 webkit 的瀏覽器引擎,可使用 JavaScript API 來模擬瀏覽器的操做。它使用 QtWebKit 做爲它的瀏覽器核心,使用 webkit 來編譯解釋執行 JavaScript 代碼。也就是說任何你能夠在 webkit 瀏覽器裏作的事情,它都能作到
它不只是個隱形的瀏覽器,提供了諸如 CSS 選擇器、支持 Web 標準、DOM 操做、JSON、HTML五、Canvas、SVG 等,同時也提供了處理文件 I/O 的操做等。PhantomJS 的用處可謂很是普遍,諸如網絡監測、網頁截屏、無瀏覽器的 Web 測試、頁面訪問自動化等
爲何不是 Selenium
作自動化測試的同窗確定都知道 Selenium。可使用 Selenium 將測試用例在瀏覽器中執行,並且 Selenium 對各類平臺和常見瀏覽器支持比較好,可是 Selenium 上手難度係數略高,並且使用Selenium 須要在服務器端安裝瀏覽器
考慮到監控主要任務在監控不在測試。系統並不須要太多考慮兼容性,並且監控功能相對單一,主要對頁面進行功能上的迴歸測試,因此選擇了 PhantomJS
對於 DOM 監控服務,在應用層面上進行了垂直劃分:
規則管理系統
規則隊列生成器
長時持續處理器
PhantomJS 服務
服務化 API
在應用層面上進行的垂直劃分能夠對應用作分佈式部署,提升處理能力。後期也方便作性能優化、系統改造擴展等
這是一個獨立的 Web 系統,系統主要用來收集用戶錄入的頁面信息、頁面對應的規則、展現錯誤信息。經過調用後端頁面抓取服務來完成頁面檢測的任務,系統能夠建立三種類型的檢測頁面:常規監控、高級監控、可用性監控
錄入一個頁面地址,和若干檢測規則。注意這裏的檢測規則,咱們把經常使用的一些檢測點抽象成了一條相似測試用例的語句。每條規則用來匹配頁面上的一個 DOM 元素,用 DOM 元素的屬性來和預期作匹配,若是匹配失敗系統就會產生一條錯誤信息,後續交由報警系統處理
匹配類型 通常有這麼幾種:長度、文本、HTML、屬性
處理器 相似編程語言中的操做符:大於、大於等於、小於、小於等於、等於、正則
這樣作的處就是,錄入規則的人只要瞭解一點 DOM 選擇器的知識就能夠上手操做了,在咱們內部一般是交由測試工程師統一完成規則的錄入
主要用來提供高級頁面測試的功能,通常由有經驗的工程師來撰寫測試用例。這個測試用例寫起來會有一些學習成本,可是能夠模擬 Web 頁面操做,如:點擊、鼠標移動等事件從而作到精確捕捉頁面信息
可用性監控側重於對頁面的可訪問性、內容正確性等比較 嚴重的問題 作即時監控。一般這類頁面咱們只須要在程序裏面啓一個 Worker 不斷的去獲取頁面 HTML 就能夠對結果進行檢測匹配了,因此咱們選擇了 NodeJS 來作異步的頁面抓取隊列,高效快速的完成這種網絡密集型任務
頁面引入一段監控腳原本收集頁面產成 error 事件返回的錯誤信息,自動上報給後端服務,在系統裏面能夠彙總全部報錯信息,以及對應的客戶端瀏覽器版本、操做系統、IP 地址等
這個功能須要對應的前端工程師在代碼中調用錯誤上報 API,來主動提交錯誤信息。主要使用的場景有,頁面異步服務延時無響應、模塊降級兜底主動通知等。監控腳本提供幾個簡單的 API 來完成這項任務
// error 方法調用後當即上報錯誤信息併發出郵件、短信通知 errorTracker.error('錯誤描述') // info 方法調用後當即上報信息,並在單位時間內僅產生一條郵件、短信通知 errorTracker.info('信息描述') // log 方法調用後由報錯檢測是否達到設置閥值,最終確認是否報錯 errorTracker.log('日誌信息')
因爲京東不少頁面內容是異步加載的,像首頁、單品等系統有許多第三方異步接口調用,使用後端程序抓取到的頁面數據是同步的,並不能取到動態的 JavaScript 渲染的內容,因此就必須使用像 PhantomJS 這種能模擬瀏覽器的工具
常規監控咱們使用 PhantomJS 模擬瀏覽器打開頁面進行抓取,而後將監控規則解析成 JavaScript 代碼片斷執行並收集結果
高級監控咱們使用 PhantomJS 打開頁面後向頁面注入像 jasmine, mocha 等相似的前端 JavaScript 測試框架,而後在頁面執行對應的錄入測試用例並返回結果
規則隊列生成器會將採集的規則轉化類成消息隊列,而後交由長時持續處理器一次處理
爲何採用類消息隊列的處理方式?
這和 PhantomJS 的性能是密不可分的,由屢次實踐發現,PhantomJS 並不能很好地進行併發處理,當併發過多,會致使 CPU 過載,從而致使機器宕機
在本機環境下的虛擬機中進行併發測試,數據並不理想,極限基本在 ab -n 100 -c 50 左右。 因此爲了防止併發致使的問題,就選擇了使用類消息隊列來避免由於併發太高致使的服務不可用
咱們這裏經過調用內部的分佈式緩存系統生成類消息隊列,隊列的生成其實能夠參考數據結構--隊列。最基本的模型就是在緩存中建立一個 KEY ,而後根據隊列數據結構的模式進行數據的插入和讀取
固然,類消息隊列的中間介質可根據你實際的條件來選擇,你也可使用本機內存實現。這可能會致使應用和類消息隊列競爭內存
長時持續處理器是要功能就是消費規則隊列生成器生成的類消息隊列
在長時持續處理器的具體實現中,咱們利用了 JavaScript 的 setInterval 方法來持續獲取累消息隊列的內容下發給規則轉化器,而後轉發給負載均衡調度器。以後再對返回的結果進行統一處理,好比郵件或者短信報警
PhantomJS 服務能夠作爲公共 API 提供給客戶端進行測試需求的處理, API 經過 HTTP 方式調用。在 API 的處理上須要提供 HTTP 數據到規則和 PhantomJS 的轉換。從而又演化出了 HTTP 數據到規則轉換器
PhantomJS 服務是指將 PhantomJS 結合 HTTP 服務和子進程進行服務化的處理
首先、啓動 HTTP 服務,而後將長時處理器下發的規則進行進一步轉化,轉化後啓動子進程,HTTP 服務會監聽子進程的處理結果,並在處理完畢以後返回
報警系統咱們目前使用的是京東內部本身的統一監控平臺 UMP,經過調用平臺提供的一些 API 來實現報警郵件與短信通知
用戶經過監控管理系統錄入規則後,監控系統會根據 UMP 規則針對用戶錄入的頁面生成 UMP 使用的 key。當長時持續處理器發現 PhantomJS 服務返回的結果標示爲異常後,就會使用 key 來進行日誌記錄
報警主要分爲了短信和郵件報警。郵件報警是在每條異常以後就會發給指定系統用戶。短信則是根據異常次數來進行處理的,當異常次數過大,就會下發短信通知
對於系統部署能夠分爲兩大塊進行。由於機器資源數量有限,沒有將全部部分都單獨部署
規則管理系統以及規則隊列生成器和持續處理器整合部署在一臺機器上,PhantomJS 服務部署在了其餘的機器上。進程管理使用了著名的 NPM 模塊 —— PM2
PM2 是一個帶有負載均衡功能的 NodeJS 應用的進程管理器。可充分利用 CPU,並保證進程穩定存活
PM2 特性:
內建負載均衡(使用 Node cluster 集羣模塊)
無縫重啓相似 nginx reload
具備 Ubuntu 和 CentOS 的開機啓動腳本
控制檯檢測
不過在目前部署任務中,並無使用內建負載均衡的特性,沒用經過集羣的方式部署代理。僅使用了後臺運行和無縫重啓的特性
其實咱們如今開發的這套監控系統並不複雜,只是合理的運用了一些現有的技術框架。抽象出來咱們本身須要的一些功能。但卻有效的達到了咱們的預期功能,而且節省了不少以前須要人肉測試的時間成本。系統自己還有不少問題在待解決狀態,好比報警系統的規則處理與閥值設定,JavaScript 報錯的準確過濾機制等,這些問題咱們都會逐個解決,而且將來的前端監控系統會成爲一個平臺,核心服務在後端爬取頁面服務,應用端能夠有多種形式,好比監控、測試工具等
一些能夠持續優化點:
監控系統雖然在應用層面進行了垂直劃分,可是因爲機器資源等限制,並無進行單獨功能的部署。這點可能會在後期的使用中進行優化
PhantomJS 服務還須要進一步優化,以承載大併發,大處理量。提供穩定的服務
報警因爲依賴於公司內部的 UMP 系統,因此並非特別靈活,後期能夠考慮本身實現一套報警機制