實例分析攜程App網絡服務通道治理和性能優化
大小:0.6 MB 人氣: 2017-10-10 需要積分:1
一、攜程App無線網絡服務架構
2014年攜程為無線服務開發了Mobile Gateway,有兩種類型:TCP Gateway和HTTP Gateway。 TCP Gateway設計用于App中Native業務網絡服務,基于TCP協議之上設計了應用層協議,類似于RPC機制。TCP Gateway兼具了接入層和服務動態路由的功能,接入層的功能基于Netty實現,管理客戶端的TCP長連接或者短連接;動態路由的功能基于Netfix開源的Zuul實現(Zuul is a gateway service that provides dynamic routing, monitoring, resiliency, security, and more. ),可以在TCP Gateway上實現服務路由、監控、反爬和用戶鑒權等功能。
每個TCP服務請求到達TCP Gateway之后,會根據報文頭中的服務號,轉發到后端對應的業務服務集群上,從而實現后端服務的解耦。TCP Gateway到后端業務服務集群之間的轉發使用HTTP協議的接口形式實現,一個TCP服務請求的完整報文會作為HTTP請求的Payload轉發到后端業務服務集群,接收到HTTP響應后,會將其Payload完整的返回到對應的TCP連接中。
HTTP Gateway用于App中Hybrid和H5 Web站點的網絡服務,采用HTTP Restful接口形式提供服務,其邏輯相對簡單,核心是HTTP服務動態轉發的功能。
Mobile Gateway的更多設計實現細節可以參考王興朝同學在2015上海QCon的演講《攜程無線Gateway》。
二、基于TCP協議實現App網絡服務
帶寬和延遲是影響網絡服務性能的兩個因素,帶寬受網絡通道上最小帶寬的網段限制,延遲是網絡包在客戶端和服務端之間的來回傳輸時長,不同網絡類型上的帶寬和延遲差別非常大(見下圖)。
我們要實現更好性能的網絡服務,對于網絡自身的帶寬和延遲這兩點而言,能做只是盡可能選擇最合適的網絡通道,其他只能在如何使用網絡通道上進行優化。
傳統的非IM即時消息類App通常都是使用HTTP協議來實現網絡服務的(Restful API形式),攜程使用TCP協議來實現,確實會增加很多開發成本,例如需要設計應用層協議、管理網絡連接、處理異常等,但下面幾點原因還是讓我們最終選擇基于TCP協議來實現App網絡服務:
攜程用戶有時會在網絡環境非常差的景區使用,需要針對弱網進行特別的優化,單純HTTP應用層協議很難實現;
HTTP請求首次需要進行DNS域名解析,我們發現國內環境下針對攜程域名的失敗率在2-3%(包含域名劫持和解析失敗的情況),嚴重影響用戶體驗;
HTTP雖然是基于TCP協議實現的應用層協議,優勢是封裝性好,客戶端和服務端解決方案成熟。劣勢是可控性小,無法針對網絡連接、發送請求和接收響應做定制性的優化,即使是HTTP的特性如保持長連接KeepAlive或者管道Pipeline等都會受制于網絡環境中的Proxy或者服務端實現,很難充分發揮作用。
基于TCP協議實現可以讓我們能夠完整控制整個網絡服務生命周期的各個階段,包括如下幾個階段:
獲取服務端IP地址建立連接序列化網絡請求報文發送網絡請求接受網絡響應反序列化網絡響應報文
我們的網絡服務通道治理和優化工作就是從這幾個方面展開的。
三、TCP網絡服務通道治理和性能優化
1. 告別DNS,直接使用IP地址
如果是首次發送基于HTTP協議的網路服務,第一件事就是進行DNS域名解析,我們統計過DNS解析成功率只有98%,剩下2%是解析失敗或者運營商DNS劫持(Local DNS返回了非源站IP地址),同時DNS解析在3G下耗時200毫秒左右,4G也有100毫秒左右,延遲明顯。我們基于TCP連接,直接跳過了DNS解析階段,使用內置IP列表的方式進行網絡連接。
攜程App內置了一組Server IP列表,同時每個IP具備權重。每次建立新連接,會選擇權重最高的IP地址進行連接。App啟動時,IP列表的所有權重是相同的,此時會啟動一組Ping的操作,根據Ping值的延遲時間來計算IP的權重,這么做的原理是Ping值越小的IP地址,連接后的網絡傳輸延遲也應該相對更小。業界也有使用HTTP DNS方式來解決DNS劫持問題,同時返回最合適用戶網絡的Server IP。然而HTTP DNS的開發和部署需要不小的開發成本,我們目前沒有使用。
內置Server IP列表也會被更新,每次App啟動后會有個Mobile Config服務(支持TCP和HTTP兩種網絡類型服務)更新Server IP列表,同時支持不同產品線的Server IP列表更新。因此,傳統DNS解析能夠解決多IDC導流的功能也可以通過此方法解決。
2. Socket連接優化,減少連接時間
和HTTP協議中的Keepalive特性一樣,最直接減少網絡服務時間的優化手段就是保持長連接。每次TCP三次握手連接需要耗費客戶端和服務端各一個RTT(Round trip time)時間才能完成,就意味著100-300毫秒的延遲;TCP協議自身應對網絡擁塞的Slow Start機制也會影響新連接的傳輸性能。
攜程App使用了長連接池的方式來使用長連接,長連接池中維護了多個保持和服務端的TCP連接,每次網絡服務發起后會從長連接池中獲取一個空閑長連接,完成網絡服務后再將該TCP連接放回長連接池。我們沒有在單個TCP連接上實現Pipeline和Multiplexing機制,而是采用最簡單的FIFO機制,原因有二:1. 簡化Mobile Gateway的服務處理邏輯,減少開發成本;2. 在服務端同時返回多個響應時,如果某個響應報文非常大,使用多個長連接方式可以加快接收服務響應報文速度。
如果發起網絡服務時長連接池中的TCP連接都正在被占用,或者TCP長連接的網絡服務失敗,則會發起一個TCP短連接實現網絡服務。這里長連接和短連接的區別僅僅是服務完成后是否直接關閉這個TCP連接。
附:Pipeline和Multiplexing是有區別的,如HTTP/1.1支持Pipeline,客戶端能否同時發送多個請求,但是服務端返回響應時也要按照請求的發送次序來返回響應;SPDY和HTTP/2協議支持Multiplexing,即支持響應報文的亂序返回,發送請求和接收響應互不干擾,因此避免了HTTP/1.1 Pipeline也沒能完全解決的Head of line blocking問題。參考資料:1, 2。參考資歷2中提到HTTP/1.1的Pipeline特性只是部分解決了Head of line blocking問題,因為a large or slow response can still block others behind it。
3. 弱網和網絡抖動優化
攜程App引入了網絡質量參數,通過網絡類型和端到端Ping值進行計算,根據不同的網絡質量改變網絡服務策略:
1) 調整長連接池個數:例如在2G/2.5G Egde網絡下,會減少長連接池個數為1(運營商會限制單個目標IP的TCP連接個數);WIFI網絡下可以增加長連接池個數等機制;
2) 動態調整TCP connection、write、read的超時時間;
3) 網絡類型切換時,例如WIFI和移動網絡、4G/3G切換至2G時,客戶端IP地址會發生變化,已經連接上的TCP Socket注定已經失效(每個Socket對應一個四元組:源IP、源Port、目標IP、目標Port),此時會自動關閉所有空閑長連接,現有網絡服務也會根據狀態自動重試。
4. 數據格式優化,減少數據傳輸量和序列化時間
傳輸數據量越小,在相同TCP連接上的傳輸時間越短。攜程App曾經使用自行設計的一套數據格式,后來和Google ProtocolBuffer對比后發現,特定數據類型下數據包大小會降低20-30%,序列化和反序列化時間可以降低10-20%,因此目前核心服務都在逐步遷移到到ProtocolBuffer格式。另外Facebook曾分享過他們使用FlatBuffer數據格式提高性能的實踐,我們分析后不太適合攜程的業務場景因而沒有使用。
5. 引入重試機制,提升網絡服務成功率
受TCP協議重傳機制來保證可靠傳輸的機制啟發,我們在應用層面也引入了重試機制來提高網絡服務成功率。我們發現90%以上的的網絡服務失敗都是由于網絡連接失敗,此時再次重試是有機會連接成功并完成服務的;同時我們發現前面提到的網絡服務生命周期處于1建立連接、序列化網絡請求報文、發送網絡請求這三個階段失敗時,都是可以自動重試的,因為我們可以確信請求還沒有達到服務端進行處理,不會產生冪等性問題(如果存在冪等性問題,會出現重復訂單等情況)。當網絡服務需要重試時,會使用短連接進行補償,而不再使用長連接。
實現了上述機制后,攜程App網絡服務成功率由原先的95.3%+提升為如今的99.5%+(這里的服務成功率是指端到端服務成功率,即客戶端采集的服務成功數除以請求總量計算的,并且不區分當前網絡狀況),效果顯著。
6. 其他網絡服務機制 & Tricks
攜程App也實現了其他一些網絡服務機制方便業務開發,如網絡服務優先級機制,高優先級服務優先使用長連接,低優先級服務默認使用短連接;網絡服務依賴機制,根據依賴關系自動發起或取消網絡服務,例如主服務失敗時,子服務自動取消。
開發過程中我們也發現一些移動平臺上的TCP Socket開發tricks:
1) iOS平臺上的原生Socket接口創建連接并不會激活移動網絡,這里原生Socket接口是指POSIX Socket接口,必須使用CFSocket或者再上層的網絡接口嘗試網絡連接時才會激活網絡。因此攜程App啟動時會優先激活注冊一些第三方SDK以及發送HTTP請求來激活移動網絡;
2) 合理設置Socket的幾個參數:SOKEEPALIVE參數確保TCP連接保持(注:此KeepAlive是TCP中的屬性,和HTTP的KeepAlive是兩個場景概念),SONOSIGPIPE參數關閉SIGPIPE事件,TCP_NODELAY參數關閉TCP Nagle算法的影響;
3) 由于iOS要求支持IPv6-Only網絡,因此使用原生Socket必須支持IPv6;
4) 如果使用select來處理nonblocking IO操作,確保正確處理不同的返回值和超時參數;
5) 保持TCP長連接可用性的心跳機制:對于非IM類應用而言,心跳機制的作用不大,因為用戶會不斷觸發請求去使用TCP連接,尤其在攜程業務場景下,通過數據統計發現使用心跳與否對服務耗時和成功率影響極小,因此目前已經關閉心跳機制。原先的心跳機制是TCP長連接池中的空閑TCP連接每60秒發送一個心跳包到Gateway,Gateway返回一個心跳響應包,從而讓雙方確認TCP連接有效。
四、Hybrid網絡服務優化
攜程App中有相當比例的業務是使用Hybrid技術實現的,運行在WebView環境中,其中的所有網絡服務(HTTP請求)都是由系統控制的,我們無法掌控,也就無法進行優化,其端到端服務成功率也僅有97%左右(注:這里指頁面中業務邏輯發送的網絡服務請求,而非靜態資源請求)。
我們采用了名為『TCP Tunnel for Hybrid』的技術方案來優化Hybrid網絡服務,和傳統HTTP加速產品的方法不同,我們沒有采用攔截HTTP請求再轉發的方式,而是在攜程Hybrid框架中的網絡服務層進行自動切換。
非常好我支持^.^
(0) 0%
不好我反對
(0) 0%