Jack Jiang

          我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
          posts - 494, comments - 13, trackbacks - 0, articles - 1

          本文由百度技術團隊“蔡銳”原創發表于“百度App技術”公眾號,原題為《百度App網絡深度優化系列《二》連接優化》,感謝原作者的無私分享。

          一、前言

          在《百度APP移動端網絡深度優化實踐分享(一):DNS優化篇》里大家了解到網絡優化一般會首選優化DNS,而接下來的HTTP協議成為優化的重點,一般優化者會選擇協議切換,合并請求,精簡數據包大小等手段來對HTTP協議進行優化,嚴謹的說這都不屬于網絡優化的范疇。

          HTTP協議的基礎是連接,所以我們的《百度APP移動端網絡深度優化實踐分享(二):網絡連接優化篇》應運而生,希望對大家在網絡方向的學習和實踐有所幫助。

          本系列文章目錄如下:

          (本文同步發布于:http://www.52im.net/thread-2479-1-1.html

          二、相關文章

          TCP/IP詳解 - 第17章·TCP:傳輸控制協議
          TCP/IP詳解 - 第18章·TCP連接的建立與終止
          TCP/IP詳解 - 第21章·TCP的超時與重傳
          通俗易懂-深入理解TCP協議(上):理論基礎
          通俗易懂-深入理解TCP協議(下):RTT、滑動窗口、擁塞處理
          理論經典:TCP協議的3次握手與4次揮手過程詳解
          現代移動端網絡短連接的優化手段總結:請求速度、弱網適應、安全保障
          移動端IM開發者必讀(一):通俗易懂,理解移動網絡的“弱”和“慢”
          移動端IM開發者必讀(二):史上最全移動弱網絡優化方法總結

          三、技術背景

          連接優化需要解決兩個核心問題:

          1)連接建立耗時較長,導致請求的總時長變長,進而影響用戶體驗;

          2)在多變的網絡環境下,連接建立的過程可能會失敗,導致成功率下降,進而影響用戶體驗。

          百度App承載著億級流量,對于每一個請求都需要追求耗時短,成功率高的體驗。從協議角度出發,如何才能做到這一點呢?首先我們來看下建立連接耗時的原理。

          ▲ 建立連接耗時的原理

          從上圖我們能清晰的看出:

          1)DNS Query需要1個RTT(Round-Trip Time,即往返時間),百度App都是基于HTTPDNS服務的,所以大部分會命中緩存,如果降級走了系統DNS,也會命中緩存,命中不了的由于是基于UDP協議,所以在連接耗時上沒有太大的影響,線上的數據也能說明這點;

          2)TCP要經歷SYN,SYN/ACK,ACK三次握手的1.5個RTT,不過ACK和ClientHello合并了,所以就是1個RTT;

          3)TLS(Transport Layer Security,即傳輸層安全性協議)需要經過握手和密鑰交換2個RTT。

          綜上所述:DNS、TLS、TCP握手階段用了4個RTT才到了ApplicationData階段,也就是數據開始傳輸階段。

          通過上面的分析可以總結出,如果我們能盡量的將TLS和TCP的RTT減少,將會大大降低連接耗時的時間。

          四、連接優化我們都能做什么?

          百度App的優化目標分為兩類,一類是TLS的連接優化,一類是TCP的連接優化。

          下面,我們將分別介紹基于這兩種優化的思路和實踐總結。

          五、連接優化之“TLS的連接優化”

          TLS的連接優化,需要服務端和客戶端都需要支持,共同完成優化手段,包括Session Resumption和False Start。

          5.1 Session Resumption

          Session Resumption中文意思是會話復用,下圖講解了Session Resumption的協議原理。

          ▲ Session Resumption的協議原理

          通過上圖可以看出TLS密鑰協商交換的過程沒有了,但具體是如何實現的呢?包含兩種方式,一種是Sesssion Identifier,一種是Session Ticket。

          1)Session Identifier:

          Session Identifier中文為會話標識符,更像我們熟知的session的概念。是 TLS 握手中生成的 Session ID。服務端會將Session ID保存起來,客戶端也會存儲Session ID,在后續的ClientHello中帶上它,服務端如果能找到匹配的信息,就可以完成一次快速握手。

          2)Session Ticket:

          Session Identifier存在一些弊端,比如客戶端多次請求如果沒有落在同一臺機器上就無法找到匹配的信息,但Session Ticket可以。Session Ticket更像我們熟知的cookie的概念,Session Ticket用只有服務端知道的安全密鑰加密過的會話信息,保存在客戶端上。客戶端在ClientHello時帶上了Session Ticket,服務器如果能成功解密就可以完成快速握手。

          不管是Session Identifier還是Session Ticket都存在時效性問題,不是永久生效,對于這兩種方式大家可以查看參考資料【4】。百度App的網絡協議層對這兩種方式都是支持的,省去了TLS握手過程中證書下載,密鑰協商交換的環節,節省了1個RTT的時間。

          5.2 False Start

          False Start的中文意思是搶跑,下圖講解了False Start的協議原理。

          ▲ False Start的協議原理

          上圖很清晰的說明在TLS第一步握手成功后,客戶端在發送Change Cipher Spec Finished的同時開始數據傳輸,服務端在TLS握手完成時直接返回應用數據。應用數據的發送實際上并未等到握手全部完成,所以稱之為搶跑。

          從結果看省去了1個RTT的時間。False Start有兩個前提條件:

          一是要通過應用層協議協商ALPN(Application Layer Protocol Negotiation)握手;

          二是要支持前向安全的加密算法。

          False Start在未完成握手的情況下就發送了數據,前向安全可以提高安全性,具體協議實現,大家可以查看參考資料【3】。百度App的網絡協議層對False Start是支持的。

          這里說句題外話,其實TCP層有個類似的連接優化手段叫Fast Open,感興趣的同學,可以查看參考資料【5】。

          5.3 Session Resumption和False Start的區別

          兩者對于TLS來說都是節省一個RTT,Session Resumption在第一次握手時還是需要2個RTT,在第二次握手時才能復用減少到1個RTT。False Start是端上的行為,故每次都會減少到1個RTT。

          六、連接優化之“TCP的連接優化”

          TCP的連接優化,我們先從連接池說起,首先讓我們來認識下連接池都有哪些類型。

          6.1 連接池

          ▲ 連接池的類型

          上圖展示了連接池的不同類型,都是大家耳熟能詳的協議連接池,有低級連接池,包含TCP連接池(管理HTTP請求的連接)和WebSocket連接池(管理WebSocket連接)。

          有高級連接池,包括HTTP代理連接池(管理HTTP代理請求的連接),SpdySession連接池(管理SPDY和HTTP/2請求的連接),SOCKS連接池(管理SOCKS和SOCKS5代理的連接),SSL連接池(管理HTTPS請求的連接)。

          不同類型的連接池以組合的形式互相復用能力:

          1)SSL連接池管理的是SSLSocket,但SSLSocket又依賴于TCP連接池提供的TCPSocket;

          2)HTTP代理連接池如果走HTTP協議,那么就需要TCP連接池提供TCPSocket,如果走HTTPS協議,那么就需要SSL連接池提供SSLSocket;

          3)SpdySession連接池依賴SSL連接池提供SSLSocket,這里需要說明下,雖然HTTP/2協議沒有強制綁定HTTPS,但是在實際開發中確實都是綁定HTTPS,百度App使用ALPN來協商HTTP/2;

          4)SOCKS連接池管理的SOCKSSocket和SOCKS5Socket都需要依賴TCP連接池提供的TCPSocket,雖然SOCKS5支持UDP,但cronet網絡庫暫時沒有實現;

          5)WebSocket連接池依賴TCP連接池提供的TCPSocket,聲明下這里沒有說明WSS(Web Socket Secure)的情況。

          TCP連接優化是一個比較復雜的內容,百度App做了針對性場景優化,包括預連接,連接重建,備用連接,復合連接。

          6.2 預連接

          ▲ 預連接和連接重建

          預連接:預先創建好的連接。它解決的場景是在App使用階段可以無耗時的獲取連接。下面用四個問答來解釋預連接。

          問題一:預連接是否能解決所有網絡請求的提前連接建立?

          答:答案是否定的,預連接需要業務方進行核心業務的評估,針對核心的域名進行預連接的建立。

          問題二:預連接既然針對的是特定的域名,那么是如何配置的呢?

          答:采用域名+連接數的方式進行配置,比如https://a.baidu.com|2,表示給a.baidu.com這個域名配置兩條預連接,這里要說明下,在HTTP/1.x協議下,網絡庫的實現都會對于單域名有最大連接數的限制,不同網絡庫的個數限制不一樣,有5個也有6個,但對于HTTP/2協議,這個連接數就只能是1個。

          問題三:預連接是如何建立的?

          答:在網絡庫初始化的時候,會根據使用者的配置延遲5s進行預連接的建立,主要是考慮網絡庫在冷啟動下對于啟動性能的影響,為了保證網絡庫的整體性能,預連接的總個數限制在20個。

          問題四:預連接是如何保持的?

          答:在網絡庫初始化的時候,除了進行預連接的建立,還會創建一個預連接的定時器,這個定時器會每隔31s,這個值的設定取決于BFE(Baidu Front End,是七層流量的統一接入系統)和BGW(Baidu Gate Way,百度自主研發的四層負載均衡平臺)對超時的最小值設定,根據使用者的配置重新建立連接。

          6.3 連接重建

          連接重建,將連接重新建立。它解決的場景是App網絡狀態發生變化,IP地址變化,導致連接不可用。下面用三個問答來解釋連接重建。

          問題一:連接重建是否針對連接池里的所有連接?

          答:答案是肯定的。

          問題二:連接重建的過程是什么樣的?

          答:在網絡狀態變化的時候,第一步會清除掉連接池里的idle socket,何為idle socket?即空閑socket,對于從未使用過的空閑socket超過60秒清除,對于使用過的空閑socket超過90秒清除。第二步重建連接需要等待200ms,目的是等待DNS先重建完成。

          問題三:連接重建對于性能有影響嗎?

          答:出于性能考慮,連接重建的連接個數限制是100個。

          6.4 備用連接

          ▲ 備用連接和復合連接

          備用連接,預備的連接。它解決的場景是正常發送一個請求當group內無連接可用的時候(何為group?group是管理socket的最小單元,內部包含活躍socket,空閑socket,連接任務,等待請求)。下面用三個問答來解釋備用連接。

          問題一:備用連接是否針對所有請求?

          答:答案是肯定的。

          問題二:備用連接的過程是什么樣的?

          答:當有請求來臨時,連接池內無連接可用,會啟動一個定時器開啟備用連接,定時器的間隔時間是250ms,與主連接進行競爭,如果主連接因為網絡抖動或者網絡狀態不好,導致連接失敗,那么備用連接就直接發送請求。如果主連接成功,那么備用連接就被取消掉。

          問題三:備用連接的目的是什么?

          答:在連接池無連接的情況下,務必是要創建連接的,在主連接之外加一個備用連接,會大大提升創建連接的成功率,從而提升用戶體驗。

          6.5 復合連接

          復合連接,即多條連接。它解決的場景是為了多個IP地址的連接選取問題。下面用三個問答來解釋復合連接。

          問題一:復合連接是否針對所有請求?

          答:答案是肯定的。復合連接可以全局開關,百度App現階段暫時沒有開啟復合連接。

          問題二:復合連接的過程是什么樣的?

          答:眾所周知域名DNS查詢一般情況下會返回多個IP,我們以域名查詢返回兩個IP為例

          1)如果結果中存在IPv6的地址,那么會優先選用IPv6的地址,這個規則follow HappyEyeBall機制(可參考系列一對于HappyEyeBall的介紹)。

          2) 接下來這兩個IP會按照順序嘗試建立連接,如果第一個IP返回失敗,將立即開始連接第二個IP。

          3)如果第一個IP率先成功返回,那么第二個IP將被加入連接嘗試列表并停止所有嘗試連接。

          4)如果第一個IP失敗,會立刻開始第二個IP的連接。

          5)如果第一個IP處于pending狀態,那么會啟動一個定時器,默認延遲2s會發起第二個IP的連接,如果是多個IP將會遞歸連接,需要特別說明下,不同的網絡制式延遲時間會不一樣,這樣體驗也會更好。

          問題三:復合連接的目的是什么?

          答:復合連接的好處是提供最優的IP選取機制,但也會帶來服務端的高負載,所以使用的時候需要進行綜合評估。

          七、連接優化的最佳實踐

          百度App目前客戶端網絡架構由于歷史原因還未統一,不過我們正朝著這個目標努力。

          我們的中心思想是以系統網絡庫的API調用接口為中心,上層建立網絡門面,供外部便捷調用,底層通過系統機制以AOP的方式將cronet(chromium的net模塊)注入進系統網路庫,達到雙端網絡架構統一,能力復用。

          下面著重介紹下連接優化在Android和iOS網絡架構中的位置及實踐。

          7.1 連接優化在Android網絡架構的位置及實踐

          ▲ 連接優化在Android網絡架構的位置

          百度App的Android網絡流量目前都在okhttp之上,上層進行了網絡門面的封裝,封裝內部的實現細節和對外友好的API,目前我們正在進行重構,默認采用Android標準的網絡接口HttpURLConnection,它的底層由系統提供的okhttp的實現。

          訂制方面利用URL Stream Protocol機制將HttpURLConnection底層網絡協議棧接管為cronet,供各個業務和基礎模塊使用,連接優化的所有內容在cronet網絡庫內部實現。

          7.2 連接優化在iOS網絡架構的位置及實踐

          ▲ 連接優化在iOS網絡架構的位置

          百度App的iOS網絡流量目前都在cronet之上,上層我們使用iOS的URL Loading System機制將cronet stack注入進URLSession里,這樣我們就可以直接使用URLSession的API進行網絡的操作而且更易于系統維護,在上層封裝了網絡門面,供各個業務和基礎模塊使用。

          在cronet內部實現了預連接(主要針對百度App的幾個核心域名進行預連和保活),連接重建(針對所有請求),備用連接(針對所有請求),復合連接(iOS上暫時沒有開啟),Session Resumption(針對所有請求),False Start(針對所有請求)。

          八、實際收益

          連接優化的收益主要體現在網絡時延和網絡成功率上,這兩點收益需要結合業務來說,以百度App Feed刷新這個典型業務場景為例。

          Feed刷新文本請求網絡時延降低16%,Feed刷新圖片請求網絡時延降低12%,可謂收益相當明顯。

          成功率方面,Feed刷新文本請求成功率提升0.29%,Feed刷新圖片請求成功率提升0.23%,也是非常不錯的收益。

          九、本文結語

          連接優化是個持續性的話題,沒有最優只有更優。上面介紹的百度App的一些經驗和做法并不見得完美,但我們會繼續深入的優化下去,持續提升百度App的網絡性能。

          以上優化由百度App團隊,內核團隊,OP團隊共建完成。最后感謝大家的辛苦閱讀,希望對你有所幫助,后面會繼續推出-百度App網絡深度優化系列《三》弱網優化,敬請期待。

          十、參考資料

          [1]https://chromium.googlesource.co ... ild_instructions.md

          [2] https://chromium.googlesource.co ... ild_instructions.md

          [3] False Start:https://tools.ietf.org/html/rfc7918

          [4] Session Resumption:https://tools.ietf.org/html/rfc5077

          [5] TCP Fast Open:https://tools.ietf.org/html/rfc7413

          (原文鏈接:點此進入

          附錄:更多網絡通信方面的精華文章

          TCP/IP詳解 - 第11章·UDP:用戶數據報協議
          TCP/IP詳解 - 第17章·TCP:傳輸控制協議
          TCP/IP詳解 - 第18章·TCP連接的建立與終止
          TCP/IP詳解 - 第21章·TCP的超時與重傳
          技術往事:改變世界的TCP/IP協議(珍貴多圖、手機慎點)
          通俗易懂-深入理解TCP協議(上):理論基礎
          通俗易懂-深入理解TCP協議(下):RTT、滑動窗口、擁塞處理
          理論經典:TCP協議的3次握手與4次揮手過程詳解
          理論聯系實際:Wireshark抓包分析TCP 3次握手、4次揮手過程
          計算機網絡通訊協議關系圖(中文珍藏版)
          UDP中一個包的大小最大能多大?
          P2P技術詳解(一):NAT詳解——詳細原理、P2P簡介
          P2P技術詳解(二):P2P中的NAT穿越(打洞)方案詳解
          P2P技術詳解(三):P2P技術之STUN、TURN、ICE詳解
          通俗易懂:快速理解P2P技術中的NAT穿透原理
          高性能網絡編程(一):單臺服務器并發TCP連接數到底可以有多少
          高性能網絡編程(二):上一個10年,著名的C10K并發連接問題
          高性能網絡編程(三):下一個10年,是時候考慮C10M并發問題了
          高性能網絡編程(四):從C10K到C10M高性能網絡應用的理論探索
          高性能網絡編程(五):一文讀懂高性能網絡編程中的I/O模型
          高性能網絡編程(六):一文讀懂高性能網絡編程中的線程模型
          不為人知的網絡編程(一):淺析TCP協議中的疑難雜癥(上篇)
          不為人知的網絡編程(二):淺析TCP協議中的疑難雜癥(下篇)
          不為人知的網絡編程(三):關閉TCP連接時為什么會TIME_WAIT、CLOSE_WAIT
          不為人知的網絡編程(四):深入研究分析TCP的異常關閉
          不為人知的網絡編程(五):UDP的連接性和負載均衡
          不為人知的網絡編程(六):深入地理解UDP協議并用好它
          不為人知的網絡編程(七):如何讓不可靠的UDP變的可靠?
          不為人知的網絡編程(八):從數據傳輸層深度解密HTTP
          網絡編程懶人入門(一):快速理解網絡通信協議(上篇)
          網絡編程懶人入門(二):快速理解網絡通信協議(下篇)
          網絡編程懶人入門(三):快速理解TCP協議一篇就夠
          網絡編程懶人入門(四):快速理解TCP和UDP的差異
          網絡編程懶人入門(五):快速理解為什么說UDP有時比TCP更有優勢
          網絡編程懶人入門(六):史上最通俗的集線器、交換機、路由器功能原理入門
          網絡編程懶人入門(七):深入淺出,全面理解HTTP協議
          網絡編程懶人入門(八):手把手教你寫基于TCP的Socket長連接
          網絡編程懶人入門(九):通俗講解,有了IP地址,為何還要用MAC地址?
          技術掃盲:新一代基于UDP的低延時網絡傳輸層協議——QUIC詳解
          讓互聯網更快:新一代QUIC協議在騰訊的技術實踐分享
          現代移動端網絡短連接的優化手段總結:請求速度、弱網適應、安全保障
          聊聊iOS中網絡編程長連接的那些事
          移動端IM開發者必讀(一):通俗易懂,理解移動網絡的“弱”和“慢”
          移動端IM開發者必讀(二):史上最全移動弱網絡優化方法總結
          IPv6技術詳解:基本概念、應用現狀、技術實踐(上篇)
          IPv6技術詳解:基本概念、應用現狀、技術實踐(下篇)
          從HTTP/0.9到HTTP/2:一文讀懂HTTP協議的歷史演變和設計思路
          腦殘式網絡編程入門(一):跟著動畫來學TCP三次握手和四次揮手
          腦殘式網絡編程入門(二):我們在讀寫Socket時,究竟在讀寫什么?
          腦殘式網絡編程入門(三):HTTP協議必知必會的一些知識
          腦殘式網絡編程入門(四):快速理解HTTP/2的服務器推送(Server Push)
          腦殘式網絡編程入門(五):每天都在用的Ping命令,它到底是什么?
          腦殘式網絡編程入門(六):什么是公網IP和內網IP?NAT轉換又是什么鬼?
          以網游服務端的網絡接入層設計為例,理解實時通信的技術挑戰
          邁向高階:優秀Android程序員必知必會的網絡基礎
          全面了解移動端DNS域名劫持等雜癥:技術原理、問題根源、解決方案等
          美圖App的移動端DNS優化實踐:HTTPS請求耗時減小近半
          Android程序員必知必會的網絡通信傳輸層協議——UDP和TCP
          IM開發者的零基礎通信技術入門(一):通信交換技術的百年發展史(上)
          IM開發者的零基礎通信技術入門(二):通信交換技術的百年發展史(下)
          IM開發者的零基礎通信技術入門(三):國人通信方式的百年變遷
          IM開發者的零基礎通信技術入門(四):手機的演進,史上最全移動終端發展史
          IM開發者的零基礎通信技術入門(五):1G到5G,30年移動通信技術演進史
          IM開發者的零基礎通信技術入門(六):移動終端的接頭人——“基站”技術
          IM開發者的零基礎通信技術入門(七):移動終端的千里馬——“電磁波”
          IM開發者的零基礎通信技術入門(八):零基礎,史上最強“天線”原理掃盲
          IM開發者的零基礎通信技術入門(九):無線通信網絡的中樞——“核心網”
          IM開發者的零基礎通信技術入門(十):零基礎,史上最強5G技術掃盲
          IM開發者的零基礎通信技術入門(十一):為什么WiFi信號差?一文即懂!
          IM開發者的零基礎通信技術入門(十二):上網卡頓?網絡掉線?一文即懂!
          IM開發者的零基礎通信技術入門(十三):為什么手機信號差?一文即懂!
          IM開發者的零基礎通信技術入門(十四):高鐵上無線上網有多難?一文即懂!
          IM開發者的零基礎通信技術入門(十五):理解定位技術,一篇就夠
          百度APP移動端網絡深度優化實踐分享(一):DNS優化篇
          百度APP移動端網絡深度優化實踐分享(二):網絡連接優化篇
          >> 更多同類文章 ……

          (本文同步發布于:http://www.52im.net/thread-2479-1-1.html



          作者:Jack Jiang (點擊作者姓名進入Github)
          出處:http://www.52im.net/space-uid-1.html
          交流:歡迎加入即時通訊開發交流群 215891622
          討論:http://www.52im.net/
          Jack Jiang同時是【原創Java Swing外觀工程BeautyEye】【輕量級移動端即時通訊框架MobileIMSDK】的作者,可前往下載交流。
          本博文 歡迎轉載,轉載請注明出處(也可前往 我的52im.net 找到我)。


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          Jack Jiang的 Mail: jb2011@163.com, 聯系QQ: 413980957, 微信: hellojackjiang
          主站蜘蛛池模板: 三河市| 和顺县| 瑞金市| 安康市| 罗定市| 汝城县| 梨树县| 易门县| 永城市| 九龙坡区| 肥西县| 林州市| 钟山县| 江口县| 大宁县| 溧水县| 慈利县| 孟津县| 博兴县| 松阳县| 巴彦淖尔市| 兰溪市| 潜山县| 辛集市| 桐梓县| 利津县| 娱乐| 钟祥市| 广宗县| 宕昌县| 阳信县| 西安市| 桐城市| 射洪县| 南京市| 五莲县| 开江县| 洱源县| 连山| 无锡市| 克东县|