首頁  >  文章  >  h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

PHPz
PHPz原創
2017-04-06 10:48:422520瀏覽

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進? 原文標題:70%以上業務由H5開發,手機QQ Hybrid 的架構如何優化演進?

隨著前端開發的興起,QQ也逐漸演變為Web與原生終端混合的開發模式。在得到Web動態營運能力的同時,QQ也在互動回應速度、後台服務壓力、大量使用者集的頻寬衝擊等方面,受到了更多的挑戰。在快速的Web營運節奏下,必須保證嵌入QQ的第三方業務也始終處於一個高品質的服務狀態。針對這些問題,QQ團隊除了採用動態CDN、後台渲染等全端手段優化體驗,也建構了圍繞速度、成功率、頁面異常等維度的監控系統來保障服務品質。

寫在前面

先自我介紹,我叫塗強。我於2005年加入騰訊,那時候還不流行行動端、hybrid等開發。我當時主要開發PC版本的QQ,後來負責PC版QQ UI引擎的時候做過一些嘗試,即在PC客戶端上集成瀏覽器內核,那個時候做了一些H5和native混合開發的框架性工作。之後我加入了騰訊QQ會員團隊,負責QQ會員在行動終端上的技術,同時也有很艱鉅的任務:維護手機QQ中的所有H5 hybrid開發的框架,即WebView組件的技術工作。

言歸正傳,現在主流的hybrid還是H5 + native,H5開發對現在移動終端的重要性不必多提,但H5在native中很明顯的問題大家都看得到,比如打開應用的時候要等很久的頁面loading,loading時用戶看到轉菊花的介面很可能就會流失掉,這也是產品經理不想看到的狀況。還有一點是每次開啟H5都牽涉到網路互動、檔下載,這些操作會消耗使用者的流量,如果流量消耗大用戶也會不高興。

今天要跟大家分享的內容主要是介紹QQ會員團隊如何在頁面開啟時間以及使用者流量方面所做的最佳化,分別對應sonic和reshape的兩個自主技術框架。

傳統頁面的動靜分離

所有的技術選型與框架都是要結合商業形態來選擇,大家對QQ會員的業務形態可能有簡單的了解。手機QQ中可以說有大概70%以上的業務由H5開發,像會員的主要商城:遊戲分發中心、會員特權中心和我現在負責的個人化業務的商城等等。這些商城特點很明顯,它們不是UGC產生的頁面,是產品經理在後台配置的內容,例如在頁面上可以看到的表情和主題等等。

這些頁面相對傳統,在最初的時候,一個傳統的H5頁面為了提升速度和體驗會做一些動靜分離的優化,比如頁面頂部的banner以及下面我們稱作為item的物品區域,這些區域的數據可以由產品經理自由編輯隨時更換,我們會透過頁面loading之後發起CGI請求,從dataServer取得數據,然後再拼接起來。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

這裡的流程大概如下,使用者從click開始,到launch WebView,WebView去載入CDN上的HTML文件,頁面loading起來後才會去取得 JSON,為了加速這個過程可能會用到localStroage做快取,這整個過程是非常傳統的靜態頁面載入過程,相對比較簡單。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

但上述方案有一些問題,例如我們在launch WebView的時候網路處於空等狀態,這會浪費時間。我們團隊內部統計了Android機器launch WebView大概需要1秒以內(因為手機QQ是多進程的架構,WebView生存在另一個進程內部,launch一次WebView除了進程loading還有瀏覽器內核的載入)。

其次,發佈在CDN上的靜態頁面內部不包含item數據,所以用戶第一眼看到從CDN下載的頁面,裡面的banner區域和item區域處於一片空白,這對用戶體驗也是很大的傷害。

還有一個問題,頁面loading起來要refresh目前的DOM,也就是拉取JSON之後拼接DOM結構再refresh,我們發現在一些QQ用戶所使用的低端Android機器裡,這個執行也會非常消耗時間。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

靜態直出+離線預推

面對這些問題我們大膽採取了一些技術手段,我們稱之為靜態直出+離線預推的模式。首先我們把WebView的加載和網絡請求做了並行,我們所有的網絡請求並不是從WebView內核發起request,而是loading WebView的過程中,我們透過native的管道建立自己的HTTP鏈接,然後從CDN和我們稱為offlineServer的地方取得頁面,這個offlineServer也就是大家聽過的離線包快取策略。

我們在native會有offlineCache,發起HTTP請求的時候先檢查offlineCache裡有沒有目前HTML緩存,這個快取和WebView的快取是隔離的,不會受到WebView的快取策略影響,完全由我們自控。

如果offlineCache沒有快取才會去offlineServer去同步文件,同時也會去從CDN去下載更新。我們在CDN上儲存的HTML已經把banner和item等所有的資料打在靜態頁面裡,這時候WebView只要拿到HTML就不需要再做refresh和執行任何JS,整個頁面可以直接展示出來,使用者也可以進行互動。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

這個方案首先會節省WebView launch的時間,這段時間可以直接網絡傳輸,另外如果本地有offlineCache甚至也不需要網絡傳輸請求,相當於完全加載一個本地頁面。但很多時候我們為了保險起見,還是加了頁面loading,然後做refresh的操作來防止資料的不一致。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

這套機制上線後效果不錯,但真的去實作這個H5載入模式會遇到一些坑,例如產品經理配置的banner圖片和item資料可能會存在多份資料版本不一致的情況。

產品經理肯定是在dataServer上配置最新數據信息,但CDN上的頁面內置的數據有可能仍處於上一版本,更差的情況是離線包服務器和offlineServer生成的HTML又是另外一個版本。當用戶本地的快取和server同步不及時即常見的快取刷新問題,很有可能儲存的資料又是另外一份。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

所以這套系統剛開始灰階試用的時候,產品經理很快就找我們吐槽:打開頁面時看到的是一份數據,過了一秒頁面刷新後看到的內容又不一樣,而且每次進入頁面都會發生這種情況。

如何統一資料

如何快速把四個版本的資料全部統一?我們針對靜態直出這個模式做了小型的自動建置系統,產品經理在管理端設定資料要同步dataServer時,我們會立刻啟動我們內部稱為vnues的建置系統。

這套系統是基於Node.js搭建的,會把開發所寫的程式碼檔案和UI素材圖片等等資料即時產生最新版本的HTML ,然後發佈到CDN以及同步到offlineServer上,這可以解決CDN的文件與最新數據不一致的問題。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

但離線包快取是放在用戶手機上的,我們如何快速地把用戶手機上的離線快取也更新起來?大家可能會這麼做:QQ客戶端每次登入上來把offlineServer最新文件下載回來就好了,但這個方案會遇到巨大的流量挑戰。

QQ現在每天的活躍用戶好幾億,登入高峰差不多十幾萬每秒,即使一個100KB離線包的更新,發布一次動輒就需要幾百GB的頻寬,無論從成本還是技術層面都不是我們能接受的事。

我們offlineServer內部分為流控和offline計算兩部分。當一個頁面的所有資源需要離線包計算打包的時候,offline計算這部分除了把所有的資源打包,內部也會儲存之前所有的歷史版本,同時根據歷史版本和最新版本生成所有的dif f,即每個離線套件的差樣部分。

這個方案也是根據我們業務形態而定的,因為每次產品經理更新的頁面資料並不會太多,基本上是幾KB到10+KB的範圍,所以我們沒有必要每次離線包的更新都讓用戶去下載全量的包。

當QQ使用者登入後,每次都會詢問offline串流server看有沒有最新的套件可以下載,如果目前串流server統計的頻寬在可接受的成本(目前暫定為10GB到20GB的空間),當CDN的頻寬撐得住的時候就會把最新的diff下發給客戶端,這樣就做到離線包一有更新時客戶端能以最小的流量代價得到刷新。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

數據以及效果

透過這套系統,我們只花了十幾GB的頻寬,就把整個BG所有H5業務的離線包覆蓋率維持在大約80%到90%。從這份工作中我們也發現一個非常反常規的事情,即大家以為離線包預推會非常消耗頻寬,但其實只是偶爾預推才消耗大量頻寬;如果長年累月不停地推送,實際上對頻寬的消耗非常小,因為時時刻刻都保持在差量下發的狀態。

做了這個工作後我們採集了現網數據,靜態直出和傳統頁面這兩種模式對比非常明顯。下圖頁面耗時部分,由於靜態直出頁面不需要任何JS執行,只需要WebView渲染,所以頁面耗時靜態直出相比傳統頁面降低了大概500毫秒到1秒左右。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

這裡有趣的現像是離線包的性價比問題,可以看到傳統頁面使用離線包可以在網路耗時部分節省700多毫秒,但靜態直出這種模式使用離線套件只能節省300毫秒左右,這是因為使用靜態直出在網路過程中所依賴的外部CSS和JS都已經直出到HTML內部了,不需要額外的網絡請求,所以其本身網路耗時減少,這時使用離線包的收益開始逐漸下降。

這裡可能有疑問,為什麼靜態直出在離線包的情況下網路耗時還需要800多毫秒,本地有快取不應該是零耗時嗎?

我們統計的網路耗時是從WebView load URL開始到頁面首行這段時間,實際上包括一部分頁面加載,WebView核心的啟動,網路元件和渲染組件的加載,所以耗時比較高。

這裡肯定也有優化空間,但當我們的客戶端團隊正要優化網路耗時這部分的時候,我們的業務形態改變了。之前是產品經理配置什麼頁面就顯示什麼,所有使用者看到的內容都是一樣的,現在產品經理說每個使用者進入到商城首頁看到的內容要完全不一樣。

以下圖為例,像左邊首頁的內容是隨機推薦的,右邊實際上是透過機器學習根據使用者過去表情發送的行為習慣和我們後台的物品做計算匹配,根據使用者的喜好行為而推薦的內容。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

每個使用者進來看到的內容都是不一樣,那麼靜態直出這種模式行不通了,因為我們不可能把所有使用者的頁面都在後台生成然後發到CDN上,然而這種模式也有很簡單的辦法來解決。

動態直出

我們不是在CDN上儲存HTML,而是在後台Node.js伺服器上動態拼接出整個HTML文件,資料來源是從dataServer去拉取。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

這種模式解決了產品的需求,但引入了新的問題。 WebView取得html要請求Node.js,Node.js要進行後台頁面拼裝,中間的網路耗時和後台運算耗時比我們想像中還要大。在這個過程中,整個頁面是無法渲染的,使用者進入我們商城首頁則看到一片空白,產品經理同樣無法接受,使用者也不買單。

另外這種模式下幾乎無法利用WebView本身的緩存,因為後台直出同樣在CSS/JS已經全部都在後端執行,WebView很難將一個純粹的靜態HTML全部緩存下來。為了解決上述問題,我們引入了動態快取的機制。

動態快取

同樣我們不讓WebView直接存取我們的Node.js伺服器,我們在這中間加上之前提到地類似offlineCache的中間層sonicBridge ,這個中間層首先會從Node.js伺服器下載完整的HTML給WebView,同時會把下載回來的內容在本地完整地做快取。

我們之前是全網所有使用者快取同一份HTML,現在修正為全網使用者快取的內容都是從真實server里拉回來的頁面。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

當用戶第二次進入頁面時,sonicBridge會優先把本地快取的頁面提交給WebView,用戶進入頁面不需要等待網路請求就可以看到內容,這對用戶側在速度上的體驗提升比較大,但它又引入了另一個問題。

實際上使用者每次打開WebView看到的內容都不一樣,Node.js每次回傳的資料都是最新的,因此拉回來的資料我們必須讓WebView進行reload,這給使用者的體驗是:明明已經開啟了本機快取好的HTML並且看到內容,但一操作頁面卻整個reload了。在一些低階機型上WebView reload非常耗時,使用者能很明顯感覺到整個WebView H5頁面白屏一下,然後才刷新出新的內容。

結合前面提到的靜態直出局部refresh部分DOM的經驗,我們可以減少網路傳輸量和減少提交頁面的資料量。我們首先做的事情是減少網路傳輸量,避免refresh的時間太靠後。

減少傳輸資料

我們改變了Node.js群組HTML的協議,當sonicBridge在第二次請求資料的時候,Node.js伺服器並不會返回整個HTML給sonicBridge,而是傳回給我們稱為data資料的部分。

拿到data資料之後,我們和H5頁面做了約定,由native側呼叫頁面的固定刷新函數,並傳遞資料給頁面。頁面會去局部刷新自己的DOM節點,這樣即使頁面需要刷新也不會reload整個頁面。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

具體從資料內容的流程來看,首次sonicBridge載入頁面傳回的仍是完整的HTML,同時會傳回我們稱為template-tag的id,這個template -tag會標記這個頁面中靜態不變的那部分hash值,這措施是為了控制快取。在回傳的HTML中我們會也有一些標記,像是sonicdiff-banner,這個banner決定了它的刷新id是什麼。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

當第二次載入傳回的資料就沒有前面看到的整個HTML,只會回傳大概37KB的數據,這個data其實就是一個JSON,但它定義了前面對應例如sonicdiff-banner的DOM結構。為了節省H5中執行的程式碼,我們直接在JSON中把DOM節點程式碼拼好,這樣頁面只需要做id的符合和刷新。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

這裡37KB的傳輸資料很難避免,我們觀察到不同業務的刷新資料量還不一樣。能否再減少一些提交給頁面去刷新的資料量呢,畢竟產品經理每次修改的資料也不會很多。

減少提交頁面資料

我們在sonicCache這一層除了前面提到的我們會快取完整的HTML、template,還會把資料提取出來做dataCache 。

template是在首次訪問的時候,根據sonicdiff裡的id信息,把所有可變的數據剔除掉剩下的頁面框架。使用者二次開啟時只要根據傳回的數據,在客戶端本地和template做merge拼接就可以得到完整的HTML。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

我們把每次的dataCache快取下來後,對數據也做了差量,例如這次請求回傳的是37KB的數據,上次cache的也是37KB的數據,我們會判斷內部真正變化的到底有多少,然後只把差量的部分交給HTML刷新,這樣在大部分場景下我們的頁面只需要處理大概9KB的數據就能刷新整個頁面。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

有了cache後使用者在本地開啟的速度非常快,差量資料的傳輸也使得使用者刷新等待的時間減少了,最後加上這種資料提交時的diff使頁面刷新範圍也大幅的減少。

整個sonic模式流程如下,看起來比較複雜,但基本原理就是透過Bridge橋接把請求回的HTML分模版和資料來快取。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

這裡可能有疑問,前面靜態直出花力氣做的offlineServer和離線預推策略,這裡還有沒有用?事實上動態頁面和之前提到的靜態頁面離線快取機制我們仍在使用,因為我們商業頁面還有大量公用JS,例如QQ提供的JS API封裝,還有一些共用的CSS也是透過離線套件策略做的預推,這也是大家每次登入的時候都會進行的下載。

資料以及效果

完成這種模式之後資料效果相對明顯,首次載入和普通的HTTP載入效能是差不多的,但使用者第二次開啟頁面時,通常只需要1秒的時間就能看到頁面,這1秒鐘還包含客戶端launch進程和WebView的開銷,同時我們載入速度不再受用戶網路環境的影響,不管是2G還是4G載入速度都接近一樣。

而且還帶來一個好處,如果用戶的網路比較差,例如經常抖動連線不上,因為我們本地有緩存,因此就算用戶目前處於斷網狀態我們的頁面也能打開。

這裡沒有提到模板更新的場景,模板更新是指我們抽取的template在我們server是有可能動態變化的,這個時候的載入流程和我們前面提到的就不太一樣了,當template有變化時,還是依照原來走HTML reload頁面的流程,這裡的耗時相對偏高,但我們統計發現大部分使用者還是落在資料刷新也就是二次開啟的狀態。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

是否使用持久連線

在做H5的提速最佳化時,大家很容易想到我們是否要利用持久連線去避免存取伺服器的connect、DNS、握手之類的耗時,像QQ這種客戶端它跟後台server是有持久化的連線的。假如用這個連線來向後台伺服器請求HTML檔案並交給WebView,會不會比臨時建立一個connect請求更快呢?我們只需要搭一個反向代理服務就可以從QQ訊息後台存取我們Node.js伺服器,這個流程是可以打通,但是我們評估認為這種模式未必適合所有的場景。

確實是有一些App利用持久連接這種通道去加載頁面,但在手機QQ比較難行得通,因為手機QQ客戶端與sever的持久連接通道是一個非常傳統的CS架構,它發送的是socket package,每次需要發送一個請求包,收到回應之後才會繼續下一個請求。

這個回應機制決定了它每次都需要一個等待的過程,而且socket package的約束造成了每次傳輸的資料包的大小受到限制,就像我們30+ KB的資料很有可能要拆成五、六個資料包,雖然是利用了持久連線節省了connect耗時,但和server多次來回通訊反而把整個耗時加大了。

另外,從Node.js伺服器傳回的資料是HTTP流式的,WebView不需要等待整個HTML載入完成後才能進行渲染和顯示,只要拿到傳輸中的first byte就可以開始進行document的解析以及DOM的建構。

如果要使用持久連接,我們很有可能要經過客戶端的加密解密以及群組包等步驟,並且要等到整個HTML下載完成之後才能進行顯示,我們認為這個時間反而拖慢了效能。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

QQHybrid架構

經過上述的介紹後,大家對QQHybrid可能有了大概直覺的印象:1. 我們在WebScope的前端開發同學做了一部分工作;2. 我們的native層終端開發同學做了bridge橋接,3.我們後台的同學做了很多的自動集成和offlineServer推送等工作。該部分架構如下:

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

接下來我將介紹架構圖右邊關於頁面流量的部分。我們統計過各業務中關於流量的分佈,如下圖,我們可以明顯看到大部分的流量都消耗在圖片資源上,但我們做這個分析時也曾經有懷疑,是不是業務特性決定了我們圖片消耗是最多的?手機QQ其他H5業務是不是也這樣?

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

春節紅包的流量分析

剛好我們有了一次機會,在2016年春節時手機QQ做了一次幾乎所有業務都有參與的活動-春節紅包,大家可能還有印像在2016年春節晚上時不停戳螢幕領紅包的操作。這種全民狂歡的背後帶來了巨大的流量壓力,每秒鐘大概給用戶發出30萬左右的禮包,引導用戶的web流量大概每秒鐘會有十萬次H5頁面的打開,當時評估的流量峰值超過1TB。

我們分析了裡面的圖片流量,確實佔據了接近一半的水平,有一部分我們已經走離線包預推的方式提前下發到用戶的手機中,但在活動期間現網的圖片流量仍超過了200GB。

流量並不是簡單花錢向業者買就能解決的問題,春節的活動我們幾乎遇到了單域名下流量接近200GB的情況,當時CDN的架構已經快扛不住了。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

我們都認為這裡大有可為,如果圖片流量能節省的話,頻寬成本能夠降低。用戶側所消耗的網路流量和手機電量等等體驗都能更好,所以我們團隊check了有關圖片格式方面的新東西。

SharpP的應用

大家都比較熟悉WebP,而且Android對其支援也比較好,而QQ團隊內部自己研發了叫SharpP的圖片格式,在檔案大小上能比WebP節省約10%的體積。以下是抽取我們CDN伺服器上已有圖片進行的資料比對。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

圖片體積是佔優的,但解碼速度方面呢?我們分別使用了高、中、低端的機型分析,很不幸SharpP確實會比WebP甚至比JPG要慢一點,但幸運的是我們業務的圖片尺寸還不算太大,頁面中多花幾十毫秒也能接受,相較於節省等待網路的時間我們覺得這是更有利的。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

於是我們準備在手機QQ H5業務中推廣SharpP格式,但推廣新圖片格式會帶來很大的應用成本。首先大部分的圖片連結都是寫死在程式碼裡面,而且頁面並不知道行動終端機有沒有能力去解碼SharpP的格式。

難道H5頁面要針對不同的手機QQ版本去準備不同的HTML?或圖片資源發佈到CDN上時產生兩個不同格式的鏈接,然後在H5內部根據終端版本選擇不同的鏈接?這個開發成本當然是不可接受的。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

除了圖片格式的問題,我們發現使用者不同的機型會有流量浪費的情況。我們的UI設計通常都是針對iPhone6的螢幕尺寸做的,預設是750px的圖片素材。小螢幕的手機,例如640px和480px,同樣是下載750px的圖片,然後在渲染的時候縮小。

這樣實際上浪費了非常大的頻寬,所以我們思考CDN是否能根據用戶手機螢幕尺寸來下發不同格式的圖片。

reshape架構

這種螢幕自適應#的策略也面臨近似私有格式的成本,因為CDN也不知道手機的情況,最後我們提出了reshape的架構,從圖片下載完整的環節來看,大概可以分成4個層級:

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

  • 最底層我們稱為CDN來源站,這裡我們部署了圖片格式轉換工具,業務方不需要care JPG製作出來後再生成sharpP還是WebP,只需要把圖片發佈在CDN源站上就能自動轉成對應的格式和屏幕分辨率;

  • 往上是用戶手機接取的CDN節點,部署全國各地用於加速和快取檔案的server。

  • 我們和瀏覽器團隊做了合作,把sharpP的解碼格式放在瀏覽器核心中,這樣最上層的業務不需要關心目前的瀏覽器是否支援WebP還是sharpP 。

在開啟頁面的時候,WebView會自動帶上終端機的螢幕尺寸以及支援哪些圖片格式給CDN節點,CDN節點再從來源站取得最新的圖片,來源站這個時候有可能已經離線或即時產生好對應的圖片了。

拆開來看WebView這一層,除了整合sharpP的解碼庫之外,其他事情相對簡單,例如:

  • 在請求header裡面額外添加了字段,例如User-Agent裡添加了“Pixel/750”,如果是480px的機器這個值就變成480;

  • 在Accept裡增加了sharpP的協定頭:image/sharpP

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

在來源站裡會儲存3 *3數量的圖片,每一張業務圖片提交給源站發布的時候,都會產生9張圖片。 CDN節點會根據WebView的請求,在回源的時候向CDN源站請求對應類型的圖片,但對於業務和WebView來看請求的還是同一個鏈接,這樣手機QQ所有的H5頁面都不需要任何一行前端程式碼的修改,就能享受圖片格式所帶來的尺寸自適應和流量節省。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

以下是更形象化的過程,在Accept增加字段,然後返回對應的圖片:

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

這個技術並不複雜,我個人認為不存在太深的技術門檻,更多的是從客戶端、Web到CDN後台這整個鏈條的打通。但過程中我們也踩了一些坑:我們在灰度的時候發現很多iOS用戶來投訴說頁面展示時圖片不能展示。

這讓我們非常驚訝,因為當時還沒有把這項技術部署到iOS上,只是Android在應用。我們檢查了CDN的程式碼也沒問題,那為什麼會把sharpP的圖片下發到iOS用戶呢?

後來分析發現,中國不同地區業者之間,會做類似CDN Cache的快取服務。當Android用戶第一次請求sharpP圖片的時候,運營商的server從我們的CDN拿到了sharpP格式連結。當快取生效期間內,同一個地區其他iOS用戶上來請求時,運營商發現URL一樣,直接就把sharpP格式的圖片回傳給iOS用戶。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

這個問題是我們整體架構上沒有去全碟review而踩中的坑,HTTP有個標準的約定可以解決這個快取問題。在CDN分發內容的時候,透過Vary字段指定快取的時候要去參考Accept和User-Agent裡的字段,我們把這個Vary加上之後問題基本上解決了。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

這個案例給了我們額外的啟發。我們現網中,Pixel欄位有三種取值:480px、640px、750px。我們內部討論過是否可以把螢幕尺寸直接寫在User-Aagent裡,這樣以後Android出了一些新的螢幕解析度我們也能在後台做更好的自適應,為每種機型去生成不同格式的圖片。

假如真的這麼做的話,會為運營商和我們自己的CDN快取帶來巨大的回源開銷。每個解析度的圖片都要緩存一份,例如498px,中間運營商沒有這機型的緩存,就會到我們的服務去回源,這樣N個屏幕尺寸會給我們CDN帶來N倍的回源壓力。

資料以及效果

言歸正傳,最後資料效果也是比較明顯的,下圖是我們在Android灰階的效果資料。我們H5業務的圖片流量從40+GB下降了20+GB。對騰訊來說20+GB的頻寬不是特別大的成本,但在春節活動場景下,可以增加近一倍的業務空間。額外帶來的好處,是用戶看到頁面圖片所等待的時間相對縮減了,用戶側的流量也節省了一半。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

H5快速運作時的穩定性

#當我們解決了頁面載入速度和流量消耗的問題時,也開始考慮H5在快速營運下的穩定性問題。相信前端開發都有遇過某個頁面程式碼一改,其他功能就不正常了的狀況。採用hybrid開發很有可能native是要提供JS頁面很多API的,客戶端小小的改動可能導致JS API受到影響,進而導致全網的H5頁面功能不正常。

除了功能穩定性之外還有一個很大的問題,我們每天都在發布前端頁面,那頁面的優化效能如何不被劣化?我們好不容易花了時間把頁面載入的效能降低到1秒,會不會有一些前端的修改例如引入更多的外鏈JS/CSS依賴導致整個頁面效能劣化?我們做了一些工具去解決這些問題。

Quick Test Automation

這是我們內部稱為快速自動化的工具。我們會把前端所有的測試案例集寫成自動化測試,然後每天都會把全網所有頁面的測試案例集跑一遍,檢查功能是否正常。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

Web Performance Test

我們會對Web的效能做Web Performance Test的監控,這裡我們首要觀察的是頁面每次開啟所消耗的流量,因此會用工具去分析頁面中所有載入的圖片是不是有些可以轉成sharpP但還是使用了JPG的。有了這套監控,能促使我們團隊以外的H5開發者去優化他們的頁面。

前端經常提到優化時要減少請求數量等等,這些可以認為是軍規的規則,我們都會在測試中進行監管。前面沒有詳細提到客戶端優化的一些方法,但是我們對於WebView在客戶端啟動的耗時也做了一些監控。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

前端部署流程

我們還有更嚴格的前端發布流程,所有在測試環境中寫好的並且測試通過的程式碼,如果要發佈到正式環境必須要通過QTA和WPT的驗證,如果自動化測試成功率低於95%則不允許發布。

發佈到正式環境之後,我們在外網還有綜合評分監控的系統,其首要監控的指標是關於速度的,我們把頁面打開的速度拆解為客戶端耗時、網絡耗時和頁面耗時並對它們分別監控。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

我們每天都會輸出如下的監控報表來觀察每天速度變化,這裡我們並不單純關心全網的效能怎麼樣,我們更關心慢速使用者的體驗,例如大於5秒的使用者最近佔比會有多少。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

除了這些,H5經常遇到的某些JS報錯而導致頁面不正常,加載過慢導致用戶看到白屏的時間過長等等問題,我們對這些都有系統的監控。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

整合營運體系

除了先前提到的內容之外我們還做了Debug平台,許多調試能力已經提前部署在所有手機QQ終端。我們可以透過遠端指令去檢查使用者的DNS解析情況,命中了哪台server,使用者是否受到電信商劫持等等。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

寫在最後

整個QQHybrid的架構基本上介紹完了,我們除了效能上的最佳化,也對CDN上的架構做了調整,也做了營運監控工具。我認為正是有了營運監控系統,才能讓我們整個H5和hybird團隊能放心大膽地修改頁面和發布新功能,同時確保穩定和可靠。

h5深度優化實戰案例:手機QQ Hybrid 的架構如何最佳化演進?

整個過程中也讓我們覺得hybrid架構並不像以前大家理解的,只是客戶端和前端配合的工作就OK了,在整個架構體系中後台技術也發揮了很大的作用。而CDN改造我們也請教了維運團隊的支持,QTA和WPT中也有測試開發團隊的參與。可以說整個體系的建立,是所有崗位並肩作戰的結果。

相關文章推薦:

今日h5特效推薦:最近超流行的H5 下拉上滑動效

php網站效能優化實戰:淘寶首頁載入速度優化實踐

web前端學習路線:WEB前端開發快速入門

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn