CI上的Web前端性能測試
來自: http://icodeit.org/2016/02/performance-testing-in-ci/
Web站點的響應速度
雅虎在2006年就發布了一份提升Web站點響應速度的 最佳實踐指南 。該指南包含了35條規則,分為7個類別。這些規則已經被廣泛使用,并指導人們在新的站點設計時更有針對性的考慮問題。這份指南已經成了Web前端性能度量的一個事實標準了。
YSlow 是一個基于這份指南的測試工具,它可以測試一個站點是否“慢”,以及為什么“慢”?你可以通過很多方式來使用 YSlow ,比如Firefox,Chrome的插件,命令行工具,甚至PhantomJS這樣的無頭(Headless)瀏覽器。YSlow會檢測你的站點中的資源是否沒有壓縮,是否缺失了超時設置,更進一步,它還會檢測你的JS/CSS是否已經壓縮/精簡化,圖片的尺寸,是否使用了CDN等等很多的維度。它還可以生成很多格式的報告,比如打分信息,TAP協議的輸出,以及junit測試報告的格式。
我們這里討論如何在持續集成服務器上設置一個 YSlow 任務,這個任務會在每次構建之后,測試你應用的性能指標,以幫助你更快的發現和定位問題。當然,我推薦你在 staging 環境,很多開發者在測試環境,本地開發環境都會啟動很多對 Debug 友好的設置,比如未壓縮的JS/CSS,沒有超時設置的響應等,這會導致該構建任務的 打分 不夠準確。
搭建CI環境
按照傳統方式,如果要搭建一個這樣的CI任務,我們需要至少做這樣一些事情:
- 安裝JDK
- 安裝Jenkins
- 安裝 PhantomJS
- 安裝 YSlow.js腳本
然后設置環境變量,在Jenkins上創建任務,并運行YSlow.js腳本。這個任務很簡單,只需要設置好參數,然后將結果輸出為Jenkins上的報告即可。比如:
$ phantomjs /var/share/yslow.js -i grade -threshold "B" -f junit \ http://bookmarks-frontend.s3-website-us-west-2.amazonaws.com/ > yslow.xml
</div>
- -i grade 展示打分(grade)信息(還可以是basic/stats/all)等
- -threshold "B" 指定失敗的閾值為B
- -f junit 輸出為 junit 識別的XML格式
這里的閾值可以是數字(0-100分),字母(A-F級別)或者一個JSON字符串(混合使用)
-threshold '{"overall": "B", "ycdn": "F", "yexpires": 85}'
</div>
上面的命令會測試站點 http://bookmarks-frontend.s3-website-us-west-2.amazonaws.com/ 的各項指標,并應用雅虎的那35條規則,并最終生成一個 junit 測試報告格式的文件: yslow.xml 。
但是維護CI環境是一個比較麻煩的事情,而且既然每個項目都可能會用到這樣的 基礎設施 ,一種好的做法就是將其做成一個 鏡像 保存起來,以方便其他項目的復用!這里我們使用 docker 來安裝和配置我們的CI環境,配置完成之后,我們可以將 docker 的鏡像分享給其他團隊,也可以供我們在下一個項目中使用。
基于docker/docker-compose的環境搭建
在 docker 出現之前,我們要搭建一個 測試 或者 staging 環境,往往需要很多個不同角色的機器:有專門的數據庫服務器,文件服務器,緩存服務器,Web服務器,反向代理等等。這樣在成本上顯然是個不小的開銷,如果將所有不同的組件部署在同一臺機器上,則又可能互相干擾,只需要一個小小的失誤,整個系統就需要重新配置。更可怕的是,這個環境和生產系統不一致,那么很可能真實的錯誤要等到系統上線之后才會被發現。
比如在2012年,我所在的一個項目中,客戶的系統采用傳統的J2EE架構。本地開發中,我們使用了Jetty作為容器,而 測試 和 Staging 環境使用了Tomcat。由于Tomcat對空格的處理和Jetty有所不同,我們在本地測試通過,并且運行良好的代碼,在 Staging 變得完全不能工作。這個問題花費了團隊很多時間來排查錯誤。
在 docker 出現之后,我們可以在一臺物理機器上運行多個互不干涉的容器,每個容器可以是一個組件(比如運行數據庫的容器,Web服務器容器等等)。這樣不但縮減了成本,而且可以讓我們的環境盡可能和生產環境一致(有的項目甚至直接將CI出來的鏡像應用到生產中)。不過對多個容器的管理是一個很麻煩的事情,好在 docker 提供了 docker-compose 工具來解決這個問題。使用 docker-compose 可以定義一組互相獨立,但是又可以協作在一起的容器,這樣我們可以很容易的搭建一個 仿生產 環境。
比如我們可以定義個 docker-compse.yml
app: build: . links: - db:postgres ports: - 8000:8000 volumes: - .:/app working_dir: /app entrypoint: /app/start.sh environment: JDBC_DATABASE_URL: jdbc:postgresql://postgres:5432/bookmarks DATABASE_USER: bookmarks-user DATABASE_PASS: bookmarks-password db: image: postgres:9.3 ports: - 5432:5432 environment: POSTGRES_DB: bookmarks POSTGRES_USER: bookmarks-user POSTGRES_PASSWORD: bookmarks-password
</div>
這個 docker-compose 定義了兩個組件, app 和 db 。 db 使用了 postgres:9.3 鏡像,并設置了自己的環境變量。 app 則從當前目錄 . 構建一個新的鏡像, app 與 db 通過 links 屬性連接起來。
如果在當前目錄執行 docker-compose build 命令, docker-compose 會找到本地的 Dockerfile ,然后構建出一個 docker 的鏡像,并啟動該容器,同時,它還會啟動 postgres:9.3 容器作為數據庫組件。這樣我們的環境就被完整的搭建好了。
搭建CI環境
app: build: . ports: - 8080:8080 - 50000:50000 volumes: - ./data:/var/jenkins_home
</div>
這個配置,表明我們會根據當前目錄的 Dockerfile 來構建一個鏡像。
通過命令 volumns ,我們將本地目錄 ./data 映射為 jenkins_home ,這樣我們定義的job信息,以及插件的安裝都會放到本地的目錄中,方便管理。配置完成之后,構建并啟動該容器:
FROM jenkins:latest # Env ENV PHANTOMJS_VERSION 1.9.6 ENV PHANTOMJS_YSLOW_VERSION 3.1.8 ENV SHARE_BIN /var/share # Install stuff by using root USER root RUN apt-get update RUN apt-get upgrade -y RUN apt-get install -y git wget libfreetype6 libfontconfig bzip2 RUN mkdir -p $SHARE_BIN RUN wget -q --no-check-certificate -O /tmp/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 \ https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 RUN tar -xjf /tmp/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 -C /tmp RUN rm -f /tmp/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 RUN mv /tmp/phantomjs-$PHANTOMJS_VERSION-linux-x86_64/ $SHARE_BIN/phantomjs RUN ln -s $SHARE_BIN/phantomjs/bin/phantomjs /usr/bin/phantomjs RUN wget -q --no-check-certificate -O /tmp/yslow-phantomjs-$PHANTOMJS_YSLOW_VERSION.zip \ http://yslow.org/yslow-phantomjs-$PHANTOMJS_YSLOW_VERSION.zip RUN unzip /tmp/yslow-phantomjs-$PHANTOMJS_YSLOW_VERSION.zip -d $SHARE_BIN/ USER jenkins
</div>
執行下面的命令來設置并啟動CI服務器:
docker-compose up
</div>
創建新任務,并指定該任務執行的命令為:
$ phantomjs /var/share/yslow.js -i grade -threshold "B" -f junit \ http://bookmarks-frontend.s3-website-us-west-2.amazonaws.com/ > yslow.xml
</div>
由于此時 phantomjs 已經被安裝到了容器中,我們可以直接在jenkins中使用。運行結束之后,這個命令會生成一個報告:
- 沒有壓縮內容
- 沒有添加過期的頭信息
在產品環境,我們需要使用反向代理來添加這些頭信息,以保證最終用戶在使用Web站點時的體驗。
總結
我們只需要很少的配置就可以設置好一個工作良好的CI任務,這樣在程序員某天引入了未經壓縮的JS/CSS或者UX不小心提供了巨大而未經處理的圖片時,你可以盡快的得到通知,并在正是上線之前發現這些問題。
代碼配置 在這里。
</div>