無頭瀏覽器效能對比與Puppeteer的優化
工作中我們經常使用指令碼繪圖,比如通過指令碼繪製餅圖、折線圖、樹狀圖等。每種程式語言都有對應的圖形庫,像Python的Matplotlib,PHP的GD2。但在實際使用過程中,這些圖形庫使用起來並不方便。一是編碼量大,二是圖形渲染效果不理想,三是除錯不方便。

image
如上圖是由PHP呼叫GD2擴充套件繪製而成,繪製這樣一幅圖需要寫好幾千行程式碼,最後的產出(效果)也並不理想。雖然能看,但離 “美感“ 還有很大差距。仔細看會發現曲線、弧形、圓角都有鋸齒感。
一. 遇到的問題
平時工作中肯定需要產出報表或者郵件,郵件中少不了各種視覺化的圖形。簡單的有餅圖、折線圖,複雜的有南丁格爾玫瑰、箱型圖、雷達圖等。使用PHP和Python來做的話投入和產出不成正比。最好的報表效果類似滴滴公司每月釋出的 交通報告 ,截取了某一頁效果如下

image
這種報告非常友好,通過視覺化的圖形直觀的表達了主題,圖片種類多且清晰美觀。通過觀察,我發現滴滴這種報告並非人工截圖貼上而成,大部分內容不需要人工參與直接程式生成(每座城市的月報都是一個模版)。高德提供的交通報告也類似 https://report.amap.com/download_city.do 。所以我希望找到一種能減少編碼工作量,繪製高清、美觀圖片的方法,為生成高大上的報表打好地基。
二. 探索Headless
做前端開發和Web測試的同學對 Headless(無頭瀏覽器)都不會陌生,無頭瀏覽器是沒有使用者圖形介面的瀏覽器,可以直接執行在服務端,向客戶端提供服務介面。無頭瀏覽器提供了對於網頁的自動控制,這種控制所依賴的環境和現代 web 瀏覽器類似,然而卻是通過命令列介面或者網路通訊實施。它們是良好的網頁測試工具,提供了和普通 web 瀏覽器同樣的功能,包括渲染 HTML、頁面佈局、顏色以及字型,同時也提供了 JavaScript 和 AJAX 的載入和執行,這是其它測試工具通常做不到的。Google 在 2009 年的時候聲稱,使用無頭瀏覽器可以幫助他們的搜尋引擎在網站中定位那些使用 AJAX 技術載入的內容。
官方解釋很抽象,效果圖如下:

demo1
[圖片上傳失敗...(image-a1ccea-1548083220639)]
仔細看URL能看到URL中有option等引數,option就是常見的json格式,比較通用。還能線上除錯 Demo線上除錯
URL中的引數就是線上除錯工具中的程式碼,在開發過程中我們可以先線上除錯,除錯到滿足需求後再呼叫介面渲染, 渲染時間在 500ms 左右。在實際使用中無論多複雜的圖形都可以在1秒內返回結果,通過ab壓測,平均QPS在23,在生成報告這種應用場景下完全夠用。
三. 服務對比
很多服務提供Headless支援,常見的有Puppeteer、Phantomjs、Nightmare、Firefox headless,哪個工具更好用也是各大社群爭論的話題,不好評價。在實際專案中我分別使用了Phantomjs和Puppeteer,從搭建環境、封裝服務、服務穩定性三方面來說Puppeteer都優於Phantomjs。每種服務在使用過程中都會遇到各種問題,但總能通過摸索慢慢解決,由於操作方式不同,踩的坑也會不一樣,就會導致主觀上大家對同一個服務評價有差異,這裡我推薦在CentOS上使用Puppeteer(出於個人主觀的評價)。
同類服務中渲染速度最快的是 Google Charts
https://chart.googleapis.com/chart?cht=rs&chs=400x400&chd=s:voJATd9v,MW9BA9&chco=FF0000,FF9900&chls=2.0,4.0,0.0|2.0,4.0,0.0&chxt=x&chxl=0:|0|45|90|135|180|225|270|315&chxr=0,0.0,360.0&chg=25.0,25.0,4.0,4.0&chm=B,FF000080,0,1.0,5.0|B,FF990080,1,1.0,5.0|h,0000FF,0,1.0,4.0|V,00FF00,0,4.0,5.0 end(結束標記,方便複製)

Google Chart
Google Charts渲染速度快,但缺點較多。
- 需要使用特定DSL呼叫,學習成本比較高。
- 網路因素,不翻牆無法訪問。
- 支援的圖形種類比較少。
- 官方已經不推薦使用。
雖然不推薦使用Google Charts,但這種渲染圖形的方式值得學習,Google Charts的渲染速度能達到100ms,也是我追求的。正是看到此服務,我才想到利用Headless繪圖,並不斷的優化速度,最終達到500ms左右。下面是實際使用效果:
-
中文和漸變色渲染效果
image
image
伺服器端使用的中文字型為思源黑體,是 Adobe 與 Google 所領導開發的開源字型 ,在CentOS上可以直接通過yum安裝,渲染效果也不錯。如果想使用其他字型,可以根據自己的喜好定義。
-
除了支援Echarts 還支援D3、HighCharts、D2等圖形庫,下面是HighCharts的渲染效果
image
同樣可以通過修改URL中的引數,實現想要的效果,線上除錯地址 https://jshare.com.cn/demos/hhhhDW 。
綜上對比,使用Puppeteer搭建服務端繪圖服務,在穩定性,擴充套件性,渲染速度方面都有很好的效果。
四. API封裝與優化
選定Puppeteer之後,我就一直在優化繪圖服務的速度。經過不斷努力,截圖服務的速度基本優化到極限了500ms左右。最後開始編寫穩定的API介面,對外提供服務。
- 服務端架構介紹

服務端架構
伺服器端架構使用的都是常用配置,通過PM2生成多個Node例項,Chrome Headless本身支援多例項(理論 上在資源足夠多的情況下我們可以開啟無數個Chrome瀏覽器)。Chrome Headless的執行是同步的,Node服務本身是非同步的,所以多個例項並不能支援更大的併發,只是可以利用多核CPU。這裡PM2生成4個例項和生成一個例項的差異並不大。介面的瓶頸在於 Chrome Headless 的執行速度與記憶體、CPU等資源的消耗情況。
-
Chrome Headless版本選擇
在tlinux上chromium有多個版本可以選擇,經過我的測試,最優的版本是:
$ yum install chromium-headless $ /usr/lib64/chromium-browser/headless_shell (呼叫路徑)
-
主要優化點
- 瀏覽器每次呼叫後一定要關閉。否則一個page頁面發生錯誤,整個服務都會卡死。
- 瀏覽器開啟時會預設有一個page頁面,直接利用該頁面能減少1/3左右的記憶體消耗。
五. 其他嘗試
- 爬取SPA應用,並生成預渲染內容(即“SSR” 服務端渲染)
- 自動化表單提交、UI測試、鍵盤輸入等
- 自動化測試Web頁面,捕獲站點的時間線等資訊,幫助分析網站效能問題
- 服務穩定後申請一個域名(用的人多的話)。
七. 寫在最後
有很多Web測試工具都是基於Headless完成,Puppeteer的效能算是最好的,應用前景非常廣,值得深入學習。詳細優化教程請看 Puppeteer效能優化與執行速度提升