京東前端:PhantomJS 和 NodeJS 在京東網站前端監控平臺的最佳實踐
1. 為什么需要一個前端監控系統
通常在一個大型的 Web 項目中有很多監控系統,比如后端的服務 API 監控,接口存活、調用、延遲等監控,這些一般都用來監控后臺接口數據層面的信息。而且對于大型網站系統來說,從后端服務到前臺展示會有很多層:內網 VIP、CDN 等。
但是這些監控并不能準確地反應用戶看到的前端頁面狀態,比如:頁面第三方系統數據調用失敗,模塊加載異常,數據不正確,空白開天窗等。
這時候就需要從前端 DOM 展示的角度去分析和收集用戶真正看到的東西,從而檢測出頁面是否出現異常問題。
2. 需要監控系統解決的問題
頁面通常出現以下問題時需要及時郵件、短信上報通知相關人員修復問題。
返回錯誤(50x, 40x)無法打開
模塊加載失敗
頁面亂碼
數據正確性
現場快照,復現問題
3. 技術選型
監控的意義和測試的意義在本質上是一致的,都是對已上線功能進行回歸測試,但不同的是監控需要做長期的可持續可循環的回歸測試,而測試僅僅需要在上線之后做一次回歸測試。
既然監控和測試的本質一致,那我們是完全可以采用測試的方式來做監控系統的。在自動化測試技術遍地開花的時代,不乏很多好用的自動化工具,我們僅僅需要把這些自動化工具進行整合為我們所用即可。
? NodeJS - 特別適用于網絡密集型任務 ? PhantomJS - 模擬無界面的瀏覽器,提供豐富的內核交互 API
NodeJS
NodeJS 是一個 JavaScript 運行環境,非阻塞 I/O 和異步、事件驅動,這幾點對于我們構建基于 DOM 元素的監控是非常重要的。并且 NodeJS 支持非組塞 I/O 和異步、事件驅動,這點對于我們構建基于 DOM 元素的監控是比較重要的。
PhantomJS
PhantomJS 是一個基于 webkit 的 JavaScript API。它使用 QtWebKit 作為它的核心瀏覽器,使用 webkit 來編譯解釋執行 JavaScript 代碼。任何你可以在基于 webkit 瀏覽器做的事情,它都能做到。
它不僅是個隱形的瀏覽器,提供了諸如 CSS 選擇器、支持Web標準、DOM操作、JSON、HTML5、Canvas、SVG 等,同時也提供了處理文件 I/O 的操作,從而使你可以向操作系統讀寫文件等。PhantomJS 的用處可謂非常廣泛,諸如網絡監測、網頁截屏、無需瀏覽器的 Web 測試、頁面訪問自動化等。
為什么不是Selenium
做自動化測試的同學肯定都知道 Selenium。可以使用 Selenium 將測試用例在瀏覽器中執行,而且 Selenium 對各種平臺和常見瀏覽器支持比較好,但是 Selenium 上手難度系數略高,而且使用Selenium 需要在服務器端安裝瀏覽器。
考慮到監控主要任務在監控不在測試。系統并不需要太多考慮兼容性,而且監控功能相對單一,主要對頁面進行功能上的回歸測試,所以選擇了 PhantomJS。
4. 架構設計
架構概覽
架構如下圖所示。
架構簡述
對于 DOM 監控服務,在應用層面上進行了垂直劃分:
? 規則管理系統。 ? 規則隊列生成器。 ? 長時持續處理器。 ? PhantomJS 服務。 ? 服務化 API。
在應用層面上進行的垂直劃分可以對應用做分布式部署,提高處理能力。后期再性能優化、系統改造擴展等方面也能提高簡易性。
5. 解決方案
(1)前臺規則錄入
這是一個獨立的 Web 系統,系統主要用來收集用戶錄入的頁面信息、頁面對應的規則、展示錯誤信息。通過調用后端頁面抓取服務來完成頁面檢測的任務,通過系統可以創建三種類型的檢測頁面:常規監控、高級監控、可用性監控。
常規監控
錄入一個頁面地址,和若干檢測規則。注意這里的檢測規則,我們把常用的一些檢測點抽象成了一條類似測試用例的語句。每條規則用來匹配頁面上的一個 DOM 元素,用 DOM 元素的屬性來和預期做匹配,如果匹配失敗系統就會產生一條錯誤信息,后續交由報警系統處理
匹配類型一般有這幾種:長度、文本、HTML、屬性 處理器 類似編程語言中的操作符:大于、大于等于、小于、小于等于、等于、正則。
這樣做的好處就是,錄入規則的人只要了解一點 DOM 選擇器的知識就可以上手操作了,在我們內部通常是交由測試工程師統一完成規則的錄入。
高級監控
主要用來提供高級頁面測試的功能,一般由有經驗的工程師來撰寫測試用例。這個測試用例寫起來會有一些學習成本,但是可以模擬 Web 頁面操作,如:點擊、鼠標移動等事件。從而做到精確捕捉頁面信息。
可用性監控
可用性監控側重于對頁面的可訪問性、內容正確性等比 嚴重的問題 的即時監控。通常這類頁面我們只需要在程序里面啟一個 Worker 不斷的去獲取頁面 HTML 就可以對結果進行檢測匹配了,所以我們選擇了 NodeJS 來做異步的頁面抓取隊列,高效快速的完成這種網絡密集型任務。
(2)主動錯誤上報
頁面腳本執行錯誤監控
頁面引入一段監控腳本來收集頁面產成 error 事件的信息,自動上報給后端服務,在系統里面可以匯總所有報錯信息,以及對應的客戶端瀏覽器版本、操作系統、IP 地址等。
頁面主動上報
這個功能需要對應的前端工程師在代碼中調用錯誤上報 API,來主動提交錯誤信息。主要使用的場景有,頁面異步服務延時無響應、模塊降級兜底主動通知等。監控腳本提供幾個簡單的 API 來完成這項任務。
// error 方法調用后立即上報錯誤信息并發出郵件、短信通知 errorTracker.error('錯誤描述') // info 方法調用后立即上報信息,并在單位時間內僅僅產生一條郵件、短信通知 errorTracker.info('信息描述') // log 方法調用后由報錯檢測是否達到設置閥值,最終確認是否報錯 errorTracker.log('日志信息')
(3)后端頁面抓取服務
由于京東很多頁面內容是異步加載的,像首頁、單品等系統有許多第三方異步接口調用,使用后端程序抓取到的頁面數據是同步的,并不能取到動態的 JavaScript 渲染的數據,所以就必須使用像 PhantomJS 這種能模擬瀏覽器的工具。
常規監控我們使用 PhantomJS 模擬瀏覽器打開頁面進行抓取,然后將監控規則解析成 JavaScript 代碼片段執行收集結果。
高級監控我們使用 PhantomJS 打開頁面后向頁面注入像 jasmine, Mocha 等類似的前端 JavaScript 測試框架,然后在頁面執行對應的錄入測試用例并返回結果。
規則隊列生成器
規則隊列生成器會將規則系統采集的規則轉化類成消息隊列,然后交由長時持續處理器依次處理。
為什么采用類消息隊列的處理方式?
這和 PhantomJS 的性能是密不可分的,由多次實踐發現,PhantomJS 并不能很好地進行并發處理,當并發過多,會導致 CPU 過載,從而導致機器宕機 在本機環境下的虛擬機中進行并發測試,數據并不理想,極限基本在 ab -n 100 -c 50 左右。 所以為了防止并發導致的問題,就選擇了使用類消息隊列來避免因為并發過高導致的服務不可用。
類消息隊列的實現
我們這里通過調用內部的分布式緩存系統生成類消息隊列,隊列的生成其實可以參考數據接口–隊列。最基本的模型就是在緩存中創建一個 KEY ,然后根據隊列數據結構的模式進行數據的插入和提取。
當然,類消息隊列的中間介質可根據你實際的條件來選擇,當然你也可以使用本機內存實現。這可能會導致應用和類消息隊列競爭內存。
長時持續處理器
長時持續處理器是要功能就是消費規則隊列生成器生成的類消息隊列。
長時持續處理實現
在長時持續處理器的具體實現中,我們充分利用了 JavaScript 的 setInterval 方法來持續獲取累消息隊列的內容下發給規則轉化器,然后轉發給負載均衡調度器。之后再對返回的結果進行統一處理,比如郵件或者短信報警。
API
PhantomJS 服務可以做為公共 API 提供給客戶端進行測試需求的處理, API 通過 HTTP 方式調用。在 API 的處理上需要提供 HTTP 數據到規則和 PhantomJS 的轉換。從而又演化出了 HTTP 數據到規則轉換器。
PhantomJS 服務
PhantomJS 服務是指將 PhantomJS 結合 HTTP 服務和子進程進行服務化的處理 首先、啟動 HTTP 服務,然后將長時處理器下發的規則進行進一步轉化,轉化后啟動子進程,HTTP 服務會監聽子進程的處理結果,并在處理完畢之后返回。
(4)報警系統
報警系統我們目前使用的是京東內部自的統一監控平臺 UMP,通過調用平臺提供的一些 API 來實現報警郵件與短信通知。
如何根據報警到具體頁面?
在用戶通過監控管理系統錄入規則后,監控系統會根據 UMP 規則針對用戶錄入的頁面生成 UMP 使用的 key。當長時持續處理器發現 PhantomJS 服務返回的結果標示為異常后,就會使用 key 來進行日志記錄。
何時出發報警?
報警主要分為了短信和郵件報警。郵件報警是在每條異常之后就會發給指定系統用戶。短信則是根據異常次數來進行處理的,當異常次數過大,就會下發短信通知。
(5)部署
對于此系統部署是分為兩大塊進行的。因為機器資源數量有限,沒有將所有部分都單獨部署。
規則管理系統以及規則隊列生成器和持續處理器整合部署在一臺機器上,PhantomJS服務部署在了其他的機器上。進程管理使用了著名的PM2。這樣就可以避免自己在開發類似的部署功能。PM2 是一個帶有負載均衡功能的NodeJS應用的進程管理器。可充分利用CPU,并保證進程永遠都存活。
PM2 特性:
? 內建負載均衡(使用 Node cluster 集群模塊)。 ? 無縫重啟類似 nginx reload。 ? 具有 Ubuntu 和 CentOS 的開機啟動腳本。 ? 控制臺檢測。
不過在此次部署中,并沒有使用內建負載均衡的特性,沒用通過集群的方式部署代理。僅僅使用了后臺運行和 0 秒停機重載的特性
6. 總結與展望
其實我們現在開發的這套監控系統并不復雜,只是合理的運用了一些現有的技術框架。抽象出來我們自己需要的一些功能。但卻有效的達到了我們的預期功能,并且節省了很多之前需要人肉測試的時間成本。系統本身還有很多問題在待解決狀態,比如報警系統的規則處理與閥值設定,JavaScript報錯的準確過濾機制等,這些問題我們都會一一解決,并且未來的前端監控系統會成為一個平臺,核心服務在后端爬取頁面服務,應用端可以有多種形式,比如監控、測試工具等。
一些可以持續優化點:
-
監控系統雖然在應用層面進行了垂直劃分,但是由于機器資源等限制,并沒有進行單獨功能的部署。這點可能會在后期的使用中進行優化。因為現在僅僅提供給本部門使用。
-
PhantomJS服務還需要進一步優化,以承載大并發,大處理量。提供成穩定的服務。協同開發業務線和測試業務線制定統一的規范,以達到優化的監控。
-
報警由于依賴于公司內部的UMP系統,所以并不是特別靈活,每次系統接入都需要用戶去UMP系統接入。
QA環節
淀粉Q1:目前PhantomJS是后臺運行,對于不同地區、不同網絡環境、不同客戶端環境的模擬是如何處理的?很多時候前端問題是在一些特定場景下出問題。
周琪力:我們主要用來做監控,所以一般不考慮瀏覽器環境什么的。
淀粉Q2:對于前臺dom的監控有在京東有比較成功的案例嗎?
周琪力:我們現在這套系統已經在線上了,像首頁,單品,頻道,全部分類這些都在用。一般來說。按頁面接入三方系統數據的維度去添加監測規則即可
淀粉Q3:PhantomJS和Node之間的通信是通過buffer還是通過get post實現的
王備: 用http的話就是比較方便,如果任務時間過長可能就要考慮其它接口實現了。 由于現在是將PhantomJS做為服務來部署,現在采用的post方式實現。
淀粉Q4:請問測試人員在后臺配置規則的時候一個稍復雜帶交互頁面,需要配置多少規則才可實現合理監控。
周琪力:這個規則主要看你頁面里面的三方系統。一般三方系統多的規則相對多些。比如在單品頁,像價格、促銷、庫存、推薦這些重要的數據源都會加一些規則。至少每個三方系統都有一個規則。
淀粉Q5:通過模擬瀏覽器像頁面注入測試框架判定,請問注入動作是后端注入嗎?假如是前端注入,前端腳本本身異常無法完成注入,如何判定?
王備:測試框架是通過PhantomJS進行注入的,PhantomJS本身是可以檢測是否成功注入所需要的腳本。也可通過監聽控制臺的error來進行一些其他的處理。
淀粉Q6:請問測試人員在后臺配置規則的時候一個稍復雜帶交互頁面,需要配置多少規則才可實現合理監控。
周琪力:這個規則主要看你頁面里面的三方系統。一般三方系統多的規則相對多些。比如在單品頁,像價格、促銷、庫存、推薦這些重要的數據源都會加一些規則。至少每個三方系統都有一個規則。
淀粉Q7:在運行過程中監控平臺有幫助到業務發現問題嗎?主要是集中在那一塊的問題?
王備:有,像一些頻道頁上面開天窗,圖片廣告位空白。還有像一些頁面狀態碼異常503之類的都有發現過問題
C淀粉Q8:請問可以簡單描述一下一個數據源規則嗎?檢測數據是否正確是渲染在dom上之后的規則,還是對數據接口返回值直接做檢測呢?這塊實在沒明白
王備:規則就是類似jQuery的選擇器,然后通過注入的測試框架來處理,之后直接返回處理完畢的結果。
淀粉Q9:有關開源問題,請問這套系統未來會開源么?
周琪力:后臺暫不會開源,因為一些功能還不是很完善。前臺的規則錄入系統可以考慮開源出來。
淀粉Q6:在實際使用中解決過哪些問題,能否舉例說明?
王備:在實踐中,我們針對異常需要保存現場,也就是網頁快照,由于部門頁面采用了滾動加載數據來展示頁面,導致截圖每次都不能截斷完整的網頁。經過實踐我們修改了viewport的大小。來保證可以完整的獲取頁面。
淀粉Q7:現場快照是以什么方式保存的,如何通過現場快照定位bug?
王備:現場快照使用了PhantomJS的截圖功能,保存了頁面加載后的jpg圖片。以便于通過報警郵件直接查看。快照屬于定位bug的一種輔助。
淀粉Q7:感謝主講人的精彩分享,那我想問一個問題,就是Node.js本身就是一個傾向于服務端的框架,那對純前端的技術選型,能否講解下純前端的架構,比如說dojo,Angular, Angular2, ext等, 在頁面展示端與Node這種傾向于服務端的區別?
周琪力:我們在這個系統里面并沒有用到純純前端架構,這個并沒有什么經驗
B淀粉Q7:有沒有監控首屏時間、白屏時間。以及如何定義首屏時間的?我了解的有通過截屏來對比截屏大小,首屏渲染程度來判斷首屏渲染是否完成。我們這套監控系統是如何監控這些指標的。
周琪力:這些指標有點類似性能監控了,基本上我們只關心頁面是否按期望加載完成。并沒有細化到性能打開速度這個層面。
淀粉Q7:現場快照其實是在服務端來截圖的,但是大部分時候用戶的問題可能只是在用戶的客戶端會出現,監控系統能否解決這類很難復現的問題?
周琪力:快照是在 PhantomJS 里面做的,只有規則不匹配的時候才會生成頁面截圖,一般都是問題發生的那個時間點產生的。 PhantomJS 實際上也是一個實實在在的客戶端。
來自:http://mp.weixin.qq.com/s?__biz=MzIwNjQwMzUwMQ==&mid=2247484138&idx=1&sn=431702ee926dd3a92403bb58417d88d4&scene=1&srcid=0831UU5TBd1yrnF8uRzlCOr7#rd