攜程App的網絡性能優化實踐

原文:http://www.infoq.com/cn/articles/how-ctrip-improves-app-networking-performance#theCommentsSection算法

編者按:在4月23日~25日舉行的QCon全球軟件開發大會(北京站)上,攜程無線開發總監陳浩然分享了《移動開發網絡性能優化實踐》,總結了攜程在App網絡性能優化方面的一些實踐經驗。在2014年接手攜程無線App的框架和基礎研發工做以後,陳浩然面對的首要工做就是App客戶端性能優化,尤爲是網絡服務性能,這是全部App優化工做的重中之重。如下爲正文。後端

首先介紹一下攜程App的網絡服務架構。因爲攜程業務衆多,開發資源致使沒法所有使用Native來實現業務邏輯,所以有至關一部分頻道基於Hybrid實現。網絡通信屬於基礎&業務框架層中基礎設施的一部分,爲App提供統一的網絡服務:緩存

  • Native端的網絡服務

Native模塊是攜程的核心業務模塊(酒店、機票、火車票、攻略等),Native模塊的網絡服務主要經過TCP鏈接實現,而很是見的Restful HTTP API那種HTTP鏈接,只有少數輕量級服務使用HTTP接口做爲補充。
TCP鏈接網絡服務模塊使用了長鏈接+短鏈接機制,即有一個長鏈接池保持必定數目長鏈接,用於減小每次服務額外的鏈接,服務完成後會將該鏈接Socket放回長鏈接池,繼續保持鏈接狀態(一段時間空閒後會被回收);短鏈接做爲補充,每次服務完成後便會主動關閉鏈接。
TCP網絡服務的Payload使用的是自定義的數據及序列化協議;HTTP服務的Payload比較簡單,即常見的JSON數據格式。
性能優化

  • Hybrid端的網絡服務

Hybrid模塊因爲是在WebView中展現本地或者直連的H5頁面,頁面邏輯發起的網絡服務都是經過系統WebView的HTTP請求實現的。少許業務場景(須要加密和支付等)以Hybrid橋接接口形式的Native TCP通道來完成網絡服務。服務器

下圖是網絡服務的部署架構圖:網絡

攜程App全部網絡服務,不管是TCP仍是HTTP都會先鏈接到一個API Gateway服務器。若是是TCP服務,會先鏈接上TCP Gateway,TCP Gateway會負責將請求經過HTTP轉發到後端的SOA服務接口。HTTP Gateway的原理與之相似。TCP Gateway和HTTP Gateway的區別僅僅在客戶端到服務端的鏈接方式不一樣而已。Gateway的做用除了業務請求還有流量控制和熔斷。架構

要發現常見網絡性能問題,先來看看一個網絡服務作了哪些事情:併發

1.DNS Lookupapp

2.TCP Handshake框架

3.TLS Handshake

4.TCP/HTTP Request/Response

首先會是DNS解析,而後TCP鏈接握手,TLS鏈接握手(若是有的話),鏈接成功後再發送TCP或HTTP請求以及收到響應。若是可以將這些過程逐一梳理並確保不會存在明顯的性能問題,那麼基本能夠確保得到不錯的網絡性能。網絡服務裏有一個重要的性能標準,即 RTT(Round-Trip Time),往返時延,它表示從發送端發送數據開始,到發送端收到來自接收端的確認(接收端收到數據後便當即發送確認)所間隔的時間。理想狀況下能夠假設 4G網絡RTT爲100ms,3G網絡RTT爲200ms,很容易就能計算出咱們的App網絡服務耗時的下限,固然還要加上服務器處理時間。

常見的網絡性能問題有以下幾種:

  • 問題一:DNS問題

DNS出問題的機率其實比你們感受的要大,首先是DNS被劫持或者失效,2015年初業內比較知名的就有Apple內部 DNS問題致使App Store、iTunes Connect帳戶沒法登陸;京東由於CDN域名付費問題致使服務停擺。攜程在去年11月也遇到過DNS問題,主域名被國外服務商誤列入黑名單,致使主站和H5等全部站點沒法訪問,可是App客戶端的Native服務都正常,緣由後面介紹。

另外一個常見問題就是DNS解析慢或者失敗,例如國內中國運營商網絡的DNS就很慢,一次DNS查詢的耗時甚至都能遇上一次鏈接的耗時,尤爲2G網絡狀況下,DNS解析失敗是很常見的。所以若是直接使用DNS,對於首次網絡服務請求耗時和總體服務成功率都有很是大的影響。

  • 問題二:TCP鏈接問題

DNS成功後拿到IP,即可以發起TCP鏈接。HTTP協議的網絡層也是TCP鏈接,所以TCP鏈接的成功和耗時也成爲網絡性能的一個因素。咱們發現常見的問題有TCP端口被封(例如上海長寬對非HTTP常見端口80、8080、443的封鎖),以及TCP鏈接超時時長問題。端口被封,直接致使沒法鏈接;鏈接超時時長太短,在低速網絡上可能老是沒法鏈接成果;鏈接超時過長,又有可能致使用戶長時間等待,用戶體驗差。不少時候儘快失敗從新發起一次鏈接會很快,這也是移動網絡帶寬不穩定狀況下的一個常見狀況。

  • 問題三:Write/Read問題

DNS Lookup和TCP鏈接成功後,就會開始發送Request,服務端處理後返回Response,若是是HTTP鏈接,業內大部分App是使用第三方 SDK或者系統提供的API來實現,那麼只能設置些緩存策略和超時時間。iOS上的NSURLConnection超時時間在不一樣版本上還有不一樣的定義,不少時候須要本身設置Timer來實現;若是是直接使用TCP鏈接實現網絡服務,就要本身對讀寫超時時間負責,與網絡鏈接超時時長參數相似,過小了在低速網絡很容易讀寫失敗,太大了又可能影響用戶體驗,所以須要很是當心地處理。

咱們還遇到另外一類問題,某些酒店Wi-Fi對使用非80、8080和443等常見HTTP端口的服務進行了限制,即便發送Request是正常的,服務端可以正常收到,可是Response卻被酒店網絡proxy或防火牆攔截,客戶端最終會等待讀取超時。

移動網絡和傳統網絡另外一個很大的區別是Connection Migration問題。定義一個Socket鏈接是四元組(客戶端IP,客戶端Port,服務端IP,服務端Port),當用戶的網絡在WIFI/4G /3G/2G類型中切換時,其客戶端IP會發生變化,若是此時正在進行網絡服務通信,那麼Socket鏈接自身已經失效,最終也會致使網絡服務失敗。

  • 問題四:傳輸Payload過大

傳的多就傳的慢,若是沒作過特別優化,傳輸Payload可能會比實際所須要的大不少,那麼對於總體網絡服務耗時影響很是大。

  • 問題五:複雜的國內外網絡狀況

國內運營商互聯和海外訪問國內帶寬低傳輸慢的問題也使人難很是頭疼。

看下攜程App用戶的網絡類型分佈:

Wi-Fi用戶佔比已超過60%,4G用戶量正接近3G用戶量,2G用戶在逐步減小,用戶的網絡愈來愈好。4G/3G/2G網絡的帶寬和延遲差異很大,而帶寬和延遲是網絡性能的重要指標:

針對攜程App用戶的網絡帶寬和延遲,咱們採樣了海內外各8個城市的數據:

注意網絡帶寬和延遲並無直接相關性,帶寬高不意味着延遲低,延遲再低也不可能快過光速。從上圖咱們能夠看到海內外帶寬相差很大,可是延遲基本一致。

針對上面這些問題,在網絡複雜環境和國內運營商互通情況無能爲力的狀況下,就針對性地逐一優化,以期達到目標:連得上、連得快、傳輸時間短。

  • 優化實踐一:優化DNS解析和緩存

因爲咱們的App網絡服務主要基於TCP鏈接,爲了將DNS時間降至最低,咱們內置了Server IP列表,該列表能夠在App啓動服務中下發更新。App啓動後的首次網絡服務會從Server IP列表中取一個IP地址進行TCP鏈接,同時DNS解析會並行進行,DNS成功後,會返回最適合用戶網絡的Server IP,那麼這個Server IP會被加入到Server IP列表中被優先使用。

Server IP列表是有權重機制的,DNS解析返回的IP很明顯具備最高的權重,每次從Server IP列表中取IP會取權重最高的IP。列表中IP權重也是動態更新的,根據鏈接或者服務的成功失敗來動態調整,這樣即便DNS解析失敗,用戶在使用一段時間後也會選取到適合的Server IP。

  • 優化實踐二:網絡質量檢測(根據網絡質量來改變策略)

針對網絡鏈接和讀寫操做的超時時間,咱們提出了網絡質量檢測機制。目前作到的是根據用戶是在2G/3G/4G/Wi-Fi的網絡環境來設置不一樣的超時參數,以及網絡服務的併發數量。2G/3G/4G網絡環境對併發TCP鏈接的數量是有限制的(2G網絡下運營商常常只能容許單個Host一個TCP鏈接),所以網絡服務重要參數可以根據網絡質量情況來動態設定對性能和體驗都很是重要。

不過目前攜程App網絡00質量檢測的粒度還比較粗,咱們正在作的優化就是可以測算到用戶當前的網絡RTT,根據RTT 值來設置參數,那會更加準確。Facebook App的作法是HTTP網絡服務在HTTP Response的Header中下發了預估的RTT值,客戶端根據這個RTT值便可以設計不一樣的產品和服務策略。

  • 優化實踐三:提供網絡服務優先級和依賴機制

因爲網絡對併發TCP鏈接的限制,就須要可以控制沒必要要的網絡服務數量,所以咱們在通信模塊中加入了網絡服務優先級和依賴機制。發送一個網絡服務,能夠設置它的優先級,高優先級的服務優先使用長鏈接, 低優先級的就是用短鏈接。長鏈接因爲是從長鏈接池中取到的TCP鏈接,所以節省了TCP鏈接時間。

網絡服務依賴機制是指能夠設置數個服務的依賴關係,即主從服務。假設一個App頁面要發多個服務,主服務成功的狀況下,纔去發子服務,若是主服務失敗了,自服務就無需再關心成功或者失敗,會直接被取消。若是主服務成功了,那麼子服務就會自動觸發。

  • 優化實踐四:提供網絡服務重發機制

移動網絡不穩定,若是一次網絡服務失敗,就馬上反饋給用戶你失敗了,體驗並不友好。咱們提供了網絡服務重發機制,即當網絡服務在鏈接失敗、寫Request失敗、讀Response失敗時自動重發服務;長鏈接失敗時就用短鏈接來作重發補償,短鏈接服務失敗時固然仍是用短鏈接來補償。這種機制增長了用戶體驗到的服務成功機率。

固然不是全部網絡服務均可以重發,例如當下訂單服務在讀取Response失敗時,就不能重發,由於下單請求可能已經到達服務器,此時重發服務可能會形成重複訂單,因此咱們添加了重發服務開關,業務段能夠自行控制是否須要。

  • 優化實踐五:減小數據傳輸量

咱們優化了TCP服務Payload數據的格式和序列化/反序列化算法,從自定義格式轉換到了Protocol Buffer數據格式,效果很是明顯。序列化/反序列算法也作了調整,若是你們使用JSON數據格式,選用一個高效的反序列化算法,針對真實業務數據進行測試,收益明顯。
圖片格式優化在業界已有成熟的方案,例如Facebook使用的WebP圖片格式,已經被國內衆多App使用。

  • 優化實踐六:優化海外網絡性能

海外網絡性能的優化手段主要是經過花錢,例如CDN加速,提升帶寬,實現動靜資源分離,對於App中的Hybrid模塊優化效果很是明顯。

通過上面的優化手段,攜程App的網絡性能從優化之初的V5.9版本到如今V6.4版本,服務成功率已經有了大幅提高,核心服務成功率都在99%以上。注意這是客戶端採集的服務成功率,即用戶感知到的網絡服務成功率,失敗量中包含了客戶端無網絡和服務端的錯誤。網絡服務平均耗時降低了150-200ms。咱們的目標是除2G網絡外,核心業務的網絡服務成功率都可以達到三個九。

數據格式優化的效果尤爲明顯,採用新的Protocol Buffer數據格式+Gzip壓縮後的Payload大小下降了15%-45%。數據序列化耗時降低了80%-90%。

經歷了這半年的網絡性能優化,體會最深的就是Logging基礎設施的重要性。若是咱們沒有完整端到端監控和統計的能力,性能優化只能是盲人摸象。Logging基礎設施須要包括客戶端埋點採集、服務端T+0處理、後期分析、Portal展現、自動告警等多種功能,這也不是單純的客戶端框架團隊能夠完成的,而須要公司多個部門合做完成。

攜程基於Elastic Search開發了網絡實時監控Portal,可以實時監控全部的網絡服務,包括多種維度,能夠跟蹤到單個目標用戶的全部網絡請求信息。
用戶的性能數據都被噴到Haddop和Hive大數據平臺,咱們能夠輕鬆制定並分析網絡性能KPI,例如服務成功率、服務耗時、鏈接成功率和鏈接耗時等,咱們作到了在時間、網絡類型、城市、長短鏈接、服務號等多緯度的分析。下圖是咱們的網絡性能KPI Portal,能夠查看任一服務的成功率,服務耗時、操做系統、版本等各類信息,對於某個服務的性能分析很是有用。

最後看看業界網絡性能優化的新技術方向,目前最有潛力的是Google推出的SPDY和QUIC協議。

SPDY已成爲HTTP/2.0 Draft,有但願成爲將來HTTP協議的新標準。HTTP/2.0提供了不少誘人的特性(多路複用、請求優先級、支持服務端推送、壓縮HTTP Header、強制SSL傳輸、對服務端程序透明等)。國內不少App包括美團、淘寶、支付寶都已經在嘗試使用SPDY協議,Twitter的性能測試代表能夠下降30%的網絡延遲,攜程也作了性能測試,因爲和TCP性能差距不明顯,暫未在生產上使用。

QUIC是基於UDP實現的新網絡協議,因爲TCP協議實現已經內置在操做系統和路由器內核中,Google沒法直接改進TCP,所以基於無鏈接的UDP協議來設計全新協議能夠得到不少好處。首先可以大幅減小鏈接時間,QUIC能夠在發送數據前只須要0 RTT時間,而傳統TCP/TLS鏈接至少須要1-3 RTT時間才能完成鏈接(即便採用Fast-Open TCP或TLS Snapshot);其次能夠解決TCP Head-of-Line Blocking問題,一般前一個TCP Packet發送成功前會擁塞後面的Packet發送,而QUIC能夠避免這樣的問題;QUIC也有更好的移動網絡環境下擁塞控制算法;新的鏈接方式也大幅減小了Connectiont Migration問題的影響。

隨着這些新協議的逐漸成熟,相信將來可以進一步提升移動端的網絡服務性能,值得你們保持關注。

相關文章
相關標籤/搜索