網站用戶訪問速度監(jiān)測分析項目
剛來新公司不久做運維開發(fā),本為以為要繼續(xù)做我的開源軟件開發(fā),結果領導給分了個以前基本從來沒考慮的任務,監(jiān)測用戶訪問我們網站的速度,沒錯,是監(jiān)測所有的用戶訪問我們網站的速度。就跟基調一樣。因為基調不能實現我們一些特殊的定制需求,所以公司準備我們自己開發(fā)一個。雖然以前沒做過,但是有挑戰(zhàn)才有意思嘛,開始走起。
首先,確定頁面速度如何監(jiān)控?監(jiān)控什么指標?如何分析?領導的基本需求如下:
- 實現全國各地用戶訪問速度的按區(qū)域分析
- 實現用戶從瀏覽器開始請求到頁面加載完畢的每一步驟的指標統(tǒng)計
- 實現對定點區(qū)域的任務下發(fā)
到底咋做?剛開始想的是,能否通過分析網站日志來實現呢?尼馬,當然不可能這么簡單,因為日志里最多只能記錄服務器收到請求到開始響應的時間,用戶何時完全加載完你的頁面,是找不到的。那咋辦?先學習基調的監(jiān)測方法發(fā)現,他們是在全國各個機房里埋了數萬個客戶端,讓這些客戶端定時自動訪問你的網站,然后再對每個客戶端的加載速度做匯總后分析。很顯然我們不可能在全國各個機房放一臺機器當客戶端,那樣的花費非得把公司賣了不行。本著花小錢辦大事的思想,靈光一現,為什么不讓用戶直接幫我們測?我們網站每天數億PV,這么好的資源不用就白浪費了。咋讓用戶幫我們測?呵呵,很簡單,在頁面埋碼,在用戶訪問我們頁面的時候,瀏覽器會自動運行一段JS腳本,會紀錄從瀏覽器開始請求到整個頁面加載完畢的過程。然后我的腳本把這些紀錄的值做成一個字典,統(tǒng)一用GET的方式發(fā)送到后臺分析接口,后臺分接程序接到數據進來后就按相應的分析維度做分析,然后,然后問題就解決了嘛。
GOOD,既然以為邏輯能走通,那就開始測試下吧,廢話少說上干貨,以下為實現過程:
-
前端埋碼
首先確定收集以下指標
- onLoad頁面加載時間
- 頁面下載時間
- JS加載時間
- 從request開始到服務器響應時間
- DomReady時間
- 第一次渲染時間(白屏時間)
- DNS lookup時間
- 從服務器下載第一個byte時間
- 導航類型
- 請求的url
- 瀏覽器類型
- 瀏覽器版本
- 分辨率
以上指標只是第一期功能,以后可能還會加很多新的指標,完全靠自己寫JS來實現挺麻煩的,尼馬我是運維開發(fā)呀,不是搞前端的呀,這么多東西怎么弄,果斷尋找開源解決方案,找來找去找到了yahoo開源的一個頁面速度指標收集的小插件boomerang, 下載下來用了下發(fā)現很強大,支持自行開發(fā)plugin, 于是就在他的基礎上做了些更改,自己加入了一些自定義指標的收集。
為了幫助看客了解,先跟大家說一下,以上指標如何收集?一個HTML頁面從開始服務器請求,到整個頁面展現在用戶面前,其實是經過好多個步驟的,擦,干說好累,還是上圖吧。
如上圖,頁面整個加載過程一般為:
- 輸入網址回車 navigationStart
- DNS解析,獲取網站IP地址 domainLookupStart
- 向服務器IP發(fā)起請求,TCP/IP 3次握手,建立連接 ConnectStart
- 服務器開始處理用戶請求頁面的URL ResponseStart
- 向用戶發(fā)送第一個字節(jié) FristByte
- DOM加載完畢 domComplete
- Onload事件開始 LoadEventtart
- 頁面加載完畢 LoadEventEnd
親,知道么,現在基本上所有的主流瀏覽器都會在頁面加載的時候把這些指標記錄下來,你可以直接在JS腳本里調用。調用方法等詳細指標解釋請看 https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html
因為不支持IE9以下的瀏覽器,所以,去他媽的IE,果斷放棄老版本IE,直接設置為在IE9以下不執(zhí)行,簡單粗暴。
瀏覽器版本檢測代碼
- <script type="text/javascript">
- function get_browser() {
- var N = navigator.appName, ua =navigator.userAgent, tem;
- var M =ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
- if (M && (TEM = ua.match(/version\/([\.\d]+)/i)) != null) M[2] =tem[1];
- M = M ? [M[1], M[2]] : [N, navigator.appVersion, '-?'];
- return M[0];
- }
- function get_browser_version() {
- var N = navigator.appName, ua = navigator.userAgent, tem;
- var M = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
- if (M && (tem = ua.match(/version\/([\.\d]+)/i)) != null) M[2] =tem[1];
- M = M ? [M[1], M[2]] : [N, navigator.appVersion, '-?'];
- return M[1];
- }
- var browser = get_browser();
- var browser_version = get_browser_version();
- var br_detect = 0; //default to run
- if (browser == 'MSIE') {
- if (parseInt(browser_version) < 9) {
- var br_detect = 1; //not runthe status js
- }
- } //end if browser
- //setJS controller variable for speed monitor plugin
- varBoomRunMark = 0; //0 = enable , 1=disable
- varBoomKickStartMark = 5; // run the collect plugin when random num < 5
- varRandomNumber = Math.floor((Math.random() * 10) + 1);
- if(br_detect == 0) {
- imgLoadBeginTime= new Date();
- }
- //console.log('randomnumber :'+ RandomNumber);
- if (br_detect == 0) {
- if (BoomRunMark == 0){
- if(RandomNumber < BoomKickStartMark ){
- BOOMR.init({
- beacon_url:"http://perf.che168.com/pv_perf.php",
- BW:{ enabled: false },
- RT:{
- cookie:'CHE168-RT'
- }
- });
- }//endRandomNumber check
- }// end BoomRunMark check
- }//end if br_detect
- </script>
做完后,上線測試,打開網站,就看到我的腳本在華麗麗的跑了。
由于每天收集量在大約上千萬,然后又需要用戶訪問速度進行實時分析,所以才用了storm實時日志流分析,對數據做基本處理后,把各個地區(qū)的訪問統(tǒng)計一下,寫入redis,因為量大,實時數據只存1天左右,過了一天,就把這些數據按小時進行平均優(yōu)化等。
#p#
分析方法
由于數據量大,如果直接簡單的對數據做平均的話,肯定會出現很多極值,導致平均值不能代表整組數據的實際平均值,例如,兩組數,[1,999], [499,501] 兩組數平均后都等于500,直接取平均值就太坑了,這時候高中數學終于用上了,直接取標準差,中位數,然后又TP90,TP99了一下,一番下來,數據基本準了,當然其中很多細節(jié)實現,有興趣的同學可以專門找我探討。
直接看最后實現吧:
以下為實時監(jiān)控部分:
好吧,差就多就這些吧,回頭搞一下,爭取開源下。 打完收工。