首先介紹一下攜程App的網絡服務架構。由于攜程業務眾多,開發資源導致無法全部使用Native來實現業務邏輯,因此有相當一部分頻道基于Hybrid實現。網絡通訊屬于基礎&業務框架層中基礎設施的一部分,為App提供統一的網絡服務:
1Native端的網絡服務
Native模塊是攜程的核心業務模塊(酒店、機票、火車票、攻略等),Native模塊的網絡服務主要通過TCP連接實現,而非常見的Restful HTTP API那種HTTP連接,只有少數輕量級服務使用HTTP接口作為補充。
TCP連接網絡服務模塊使用了長連接+短連接機制,即有一個長連接池保持一定數目長連接,用于減少每次服務額外的連接,服務完成后會將該連接Socket放回長連接池,繼續保持連接狀態(一段時間空閑后會被回收);短連接作為補充,每次服務完成后便會主動關閉連接。
TCP網絡服務的Payload使用的是自定義的數據及序列化協議;HTTP服務的Payload比較簡單,即常見的JSON數據格式。
2Hybrid端的網絡服務
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 Lookup
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網絡服務耗時的下限,當然還要加上服務器處理時間。
3常見的網絡性能問題有如下幾種:
-
問題一: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問題的影響。
隨著這些新協議的逐漸成熟,相信未來能夠進一步提高移動端的網絡服務性能,值得大家保持關注。
文章列表