百度App網絡深度優化系列《三》弱網優化

本文做者:yanxin1563html

本文做者:android

蔡銳ios

1、前言

網絡優化解決的核心問題有三個,第一是安全問題,咱們在系列《一》DNS優化進行了詳細的講解。第二是速度問題,咱們在系列《二》鏈接優化也作了詳細的介紹。第三是弱網問題,它是網絡優化中最爲複雜且須要反覆驗證和分析的問題,咱們的系列《三》弱網優化就是要深刻探討這個問題。git

2、背景

弱網優化須要解決的核心問題有兩點github

【1】移動網絡環境如此複雜,咱們如何肯定當下就是弱網環境編程

【2】肯定爲弱網環境下,咱們如何提高弱網下的成功率,下降弱網下的時延,進而提高用戶的網絡體驗windows

百度App承載着億級流量,弱網比例0.95%,可謂不小,這個比例是如何得來的呢?仍是要從什麼是判斷弱網指標提及。安全

3、判斷弱網的指標

首先咱們來探討下都有哪些指標會影響到網絡的質量,包括httprtt,tcprtt,throughput,signal strength,bandwidth-delay product。服務器

1.httprtt

httprtt(http Round-Trip Time)又名TTFB(Time to first byte),指從客戶端請求的第一個字節開始發送到接收到http header的第一個字節的時間差。httprtt的時間若是過長,一方面是客戶端自己接入網絡質量的問題,另外一方面是服務的延時比較大。微信

2.tcprtt

tcprtt(tcp Round-Trip Time)指客戶端tcp信道第一個字節發送到接收第一個字節的時間差。由於HTTP協議底層是基於TCP的,因此在複用同一條tcp鏈接的前提下,httprtt的時間是包含tcprtt的時間的。大部分狀況下httprtt已經能夠說明問題的緣由。

3.throughput

throughput,中文名字吞吐量,它是用來衡量單位時間內成功傳送數據的數量,是能夠比較客觀的衡量網絡質量的指標。吞吐量 =(獲bits結束大小 - 獲bits開始大小)/(獲bits結束時間 - 獲bits開始時間),這裏有個細節須要注意,posix socket的read函數返回值是bytes,因此要乘以8獲得bits。一般在httprtt比較小的狀況下,網絡依然很慢,這個時候就可使用吞吐量來肯定網絡的質量。

4.signal strength

signal strength,這裏指的是無線信號強度,在Android上能夠經過PhoneStateListener的onSignalStrengthsChanged方法獲取到信號強弱,但要注意只能在Android M以上的版本才生效。iOS上暫時沒有靠譜的實現。

5.bandwidth-delay product

bandwidth-delay product,中文名帶寬時延乘積指的是一個數據鏈路的能力(throughput)與來回通訊延遲(rtt)的乘積。帶寬時延乘積的結果是比特不是位,這個比特值反應出當前網絡管道的最大容量。TCP中有一個窗口大小的概念,會限制發送和接收數據的大小,因此TCP窗口大小的調節是直接受帶寬時延乘積的影響,根據帶寬時延乘積的值去設置套接字的setsockopt方法,設置的option是SO_RCVBUF(接收緩衝區大小)和SO_SNDBUF(發送緩衝區大小)。

經過上面的內容,咱們對影響網絡質量的指標有了必定了解,對於不一樣的產品,影響網絡質量的指標能夠理解成同樣的,但對於每一個指標的閾值確定是不同的,由於這包含着業務場景,好比抖音是視頻類網絡傳輸,微信是長鏈接數據傳輸,百度是文本圖片類數據傳輸。還包括服務端配備,不一樣產品線的服務集羣能力確定不同,好比返回客戶端的服務端耗時確定不同。因此針對不一樣的產品弱網指標是基本一致的,可是指標的取值確定是不同的。

4、如何創建弱網標準

創建弱網標準是一個按部就班的過程,在一貧如洗的時候咱們應該如何創建這個標準呢?答案分爲三個階段。

如下爲創建弱網標準的步驟:

1.第一階段,線下進行測試。獲取一些符合咱們預期的閾值,這個時候咱們須要藉助一些網絡測試工具,好比蘋果的Network Link Conditioner,Facebook的ATC(Augmented Traffic Control),來獲取到線下不一樣網絡狀況的閾值,通常咱們會測試App冷啓動的場景,網絡切換的場景,DNS故障場景,弱網場景(通常都是配置上下行的帶寬,丟包率,延遲,DNS延遲參數,或者更爲簡單的是使用工具默認的一些弱網配置)。

2.第二階段,線上進行驗證。經過線下充分測試獲取到的閾值,在線上能夠獲取到弱網的比例,在這裏百度App是針對特定場景的,好比Feed刷新,搜索落地頁打開等,就算是在移動時代被你們公認的網絡體驗好的微信,也只是在信令傳輸(收發消息)上作到極致優化,因此針對場景蒐集弱網數據很重要。

3.第三階段,線上的反覆試驗。想作到理想的弱網效果,少不了線上反覆的閾值調整,經過調整閾值比較針對場景的網絡請求的成功率、耗時、鏈接複用率等指標,使咱們得到趨向於針對場景的合理閾值。

聊了這麼多,那麼弱網的探測如何實現呢?

5、網絡探測的總體架構和實現

網絡探測是弱網檢測的基礎,是否能即時,正確的檢測出網絡質量,是咱們首先要解決的問題。咱們把網絡探測劃分爲兩部分,主動網絡探測被動網絡採集

1.主動網絡探測

所謂主動探測,就是在觸發了某些條件後,主動的進行網絡探測,並按照必定的條件檢查出是不是弱網狀態。百度App自研了主動探測組件,以下圖所示。

1.1策略層

探測策略層經過多種策略的組合,使主動探測的即時性和準確性得以大大提升,咱們結合上面的策略層圖來解釋下檢測維度的意義。

咱們分別在網絡請求成功和失敗的時候觸發了弱網檢測的邏輯。主要分爲以下三種邏輯。

1)成功時,如何判斷進入弱網狀態?檢查weakhttprtt的閾值,這個值取決於業務的設置(通常這個值會針對特殊場景的請求取95分位或者更大分位的值),大於這個值就會進入弱網檢測,爲了防止頻繁觸發探測加了時間間隔維度,目前定義的是10分鐘。從線下模擬測試來看,只要大於這個閾值,檢測結果必然是弱網狀態。

2)成功時,如何判斷退出弱網狀態?檢查goodhttprtt的閾值,這個值取決於業務的設置(通常這個值會取總體網絡的95分位或者更大分位的值),小於這個值證實要切換回正常網絡狀態,爲了防止頻繁觸發探測加了時間間隔維度,目前定義的是30秒。從線下模擬測試來看,只要小於這個閾值,檢測結果必然是正常狀態。若是大於或者等於這個閾值,也不能證實必定不是正常網絡,因此也須要發起網絡探測,可是因爲這是在成功回調裏,頻次會很高,因此咱們加上時間間隔的限制30秒,還加入了次數的限制,連續成功次數%次數閾值(4次)等於0。但這看起來仍是頻次有點高,因此咱們引入了階梯遞增機制,隨着次數的增加,成60秒幾何倍數增加。

3)失敗時,如何判斷進入弱網狀態?首先會判斷連續失敗次數,連續失敗次數/次數閾值(2次)等於1而且連續失敗次數%次數閾值(2次)等於0,相比成功,失敗的次數檢查較爲苛刻,主要仍是考慮屢次觸發網絡檢測損耗性能

進入弱網狀態後,就會觸發基礎能力層的ping和dns query的探測。

1.2基礎能力層

探測基礎能力層,主要提供弱網檢測的手段,一是dns query,一是ping,百度App使用C++實現了這兩個能力。爲何要選用這兩種手段呢?咱們在系列二中介紹過,一個網絡請求,分爲DNS-》TLS-》TCP-》數據傳輸 四個階段。想斷定網絡連通性主要在DNS和TCP階段,因此dns query和ping就是用來檢測這兩個階段的連通性手段。dns query向百度核心域名mbd.baidu.com發起dns查詢,查詢的DNS服務器爲系統配置的DNS服務器(iOS經過res_ninit函數構建一個__res_state的結構體,Android經過systemproperty獲取net.dns1和net.dns2的值,即可獲取系統配置的DNS服務器),DNS查詢的超時時間爲3s。ping的目標地址爲百度核心域名mbd.baidu.com,ping的次數爲兩次,每次超時時間是默認的1s。

判斷出弱網狀態後,會將結果提供給接口層。

1.3接口層

接口層主要提供主動探測出來的網絡狀態,目前包括GOOD,BAD,UNKNOWN,OFFLINE

1)GOOD:dns查詢成功而且ping也成功,即標記爲GOOD狀態。

2)BAD:ping失敗一次標記爲BAD狀態。

3)UNKNOWN:初始狀態或者識別不出來狀態爲UNKNOWN狀態。

4)OFFLINE:dns server錯誤(沒有獲取到要發送的DNS server地址),網關錯誤(讀取/proc/net/route文件內容失敗),發送dns錯誤(發送dns數據出錯),ping讀寫錯誤(ping的過程當中讀寫錯誤),接收dns錯誤(接收dns數據出錯),ping地址錯誤(ping地址是空),dns未知域名錯誤(dns沒有查詢到域名錯誤),初始化icmp錯誤(初始化icmp失敗),dns udp錯誤(建立UDP socket失敗),即標記爲OFFLINE狀態。

2.被動網絡採集

所謂被動採集,就是每一次網絡請求的全部細節都進行記錄,並按照必定的條件將原始信息進行上報,上層再根據條件判斷是不是弱網狀態。百度App基於cronet的NQE(Network Quality Estimator)進行了二次訂製開發。

首先咱們講解下須要採集的數據,包括tcprtt、httprtt、throughput三個維度,以下圖所示。

1)tcprtt,基於posix和windows的socket編程接口來獲取tcprtt。獲取時機在鏈接完成,讀完成和寫完成。

2)httprtt,基於HTTP協議棧實現,經過計算接收response數據開始和開始發送的時間差,來獲取httprtt。獲取時機在讀首包完成時。

3)throughput,經過上面的計算公式須要獲取bytes和時間,基於posix和windows的socket編程接口來獲取bytes。獲取時機在讀完成時記錄接收的bytes,在寫完成時記錄發送的bytes。時間的獲取在吞吐量管理模塊裏完成,下面會講到。獲取時機在請求完成和請求銷燬時。

以下爲被動網絡採集的總體架構圖。

1.1能力層

能力層內容上面咱們已經講過,主要採集tcprtt、httprtt、throughput三個維度的數據

1.2策略層

被動採集策略層經過多種策略的組合,下降各類採集數據的上報時機,下降性能的影響

1)套接字管理模塊,首先負責獲取tcprtt的值,如何獲取tcprtt呢?經過getsockopt函數獲取tcp_info結構體裏的tcpi_rtt值。其次因爲tcprtt的上報頻次比較頻繁,因此作了1秒的時間間隔上報限制。

2)吞吐量管理模塊,負責吞吐量的計算,上面介紹了計算公式,從網絡活動監控器模塊獲取bytes,但吞吐量的計算單位是bits(位),因此將bytes乘以8。只有GET請求會被列入統計計算,而且至少要累計5個請求後才能開始統計計算。排除精準度的干擾,好比localhost,私有子網上的主機,特定用途子網主機,可參考RFC1918。

3)網絡質量管理模塊,從套接字管理模塊獲取tcprtt,從吞吐量管理模塊獲取吞吐量,而且在HTTP協議棧讀首包完成時獲取httprtt。獲取到這三個值後,須要通過一些策略限制上報的頻次,10秒間隔的限制;網絡類型不能是UNKNOWN(1.3的第三部分會詳細講解);網絡不能頻繁切換;rtt和吞吐量總大小各300個。

1.3接口層

接口層主要提供被動採集出來的網絡狀態,目前包括GOOD,BAD,UNKNOWN,OFFLINE

1)GOOD:3G和廣義的4G,任一條件知足標記爲GOOD狀態。經過閾值標記3G和廣義的4G,httprtt大於等於273ms,tcprtt大於等於204ms,即標記爲3G狀態。小於這兩個值被標記爲廣義的4G,所謂廣義的4G包含4G、WiFi、以及質量較好的各類接入網絡。

2)BAD:慢2G,2G和httprtt大於1.31秒,任一條件知足標記爲BAD狀態。經過閾值標記慢2G和2G,httprtt大於等於2.01秒,tcprtt大於等於1.87秒,標記爲慢2G。httprtt大於等於1.42秒,tcprtt大於等於1.28秒,標記爲2G。httprtt大於1.31秒,爲百度App的Feed刷新業務閾值。

注:上面涉及的時間值爲nqe內部的機制,具備普適性。

3)UNKNOWN:非法的httprtt,tcprtt,吞吐量,任一條件知足標記爲UNKNOWN狀態。何爲非法?值爲-1爲非法,那什麼條件被標記爲-1呢?首先初始化時會被標記爲-1,其次在歷來沒有獲取到過httprtt,tcprtt,throughput的值時,會使用本地默認的值作爲判斷標準,這是一種容錯處理。

4)OFFLINE:依賴平臺能力進行判斷,Android平臺依賴ConnectivityManager獲取NetworkInfo,經過NetworkInfo的isConnected獲取是否鏈接,若是未鏈接則判斷爲OFFLINE狀態,若是NetworkInfo爲空則判斷爲OFFLINE狀態。

6、弱網狀態下百度App如何改善用戶體驗

以下爲百度App在弱網下的手段:

1.QUIC在百度App弱網下的最佳實踐

QUIC(Quick UDP Internet Connections)是新一代的互聯網傳輸協議,最先源於Google,它的詳盡內容可參考資料【3】,本章咱們不作QUIC的科普介紹。

百度App的普通網絡請求在弱網狀態下會切換到QUIC,本章重點講解下百度App針對弱網下開啓QUIC後遇到的問題,一是開啓QUIC一旦遇到問題是否能夠回滾?二是在弱網下如何能讓流量儘量的走QUIC?針對這兩個問題,咱們的解決方案是QUIC升降級原理和QUIC預鏈接

1.1QUIC升降級原理

如上圖QUIC部分所示,QUIC的升降級依賴於HTTP Alternative Services,HTTP Alternative Services是與HTTP有關的一個協議,它不是爲QUIC專門設計的,在HTTP協議上主要負責新服務的替換,對於HTTP1.1協議,它是經過HTTP響應頭傳輸回來的,因此只能在第二次請求時生效,以下面格式。

Alt-Svc: quic="alt.example.com:443", quic=":443"; ma=2592000

如上信息代表切換到quic協議,指定了域名服務和端口,而且指定了生效時間,以秒爲單位。

Alt-Svc: clear

如上信息代表將alter配置清空

在網絡庫內部有一個alter鏈接和原鏈接的競爭機制,若是alter信息已經存在,優先發送alter鏈接,而原鏈接會延遲發送,延遲時間默認300ms,誰先成功就使用哪一個鏈接,若是alter鏈接在QUIC握手時失敗,會記錄這個alter信息的失敗次數,並根據失敗的次數,計算出一個過時時間,這個過時時間會隨失敗次數指數增長,最長爲2天。當過時時間到期後,會清除這個alter信息,當這個alter鏈接在QUIC握手成功後,會清除這個alter信息。

1.2QUIC預鏈接

所謂QUIC的預鏈接,就是在進入弱網狀態前提早創建QUIC鏈接。你們都知道QUIC引覺得傲的0RTT,但第一次創建鏈接的時候是須要1RTT的,客戶端首先會向服務器發送一個client hello消息,服務器會回覆一個server reject消息,這個消息中包括了server config,有了server config後客戶端就能夠直接計算出密鑰,完成0RTT,詳盡內容可參考資料【4】。

經過上面的原理,客戶端拉取server config的成功機率會直接影響QUIC在弱網下的流量,因此咱們在App啓動的過程當中會作一次QUIC預鏈接,將server config拉取下來,這樣等進入弱網後alter鏈接會大機率的競爭過原鏈接,進而走QUIC協議。

2.複合鏈接在百度App弱網下的最佳實踐

複合鏈接的具體原理能夠查看《百度App網絡深度優化系列《二》鏈接優化》裏的具體介紹,百度App目前在弱網下只是針對圖片網絡請求開啓了複合鏈接,由於圖片請求無論是HTTPDNS結果仍是localDNS的結果都是多個IP,這是知足複合鏈接的前提。在弱網下多IP的嘗試會比單IP的結果好些,另外弱網的比例相對較小,複合鏈接對於服務器的負載也會小些。

7、百度App網絡總體架構

下圖爲百度App網絡總體架構:

百度App網絡總體架構,以網絡門面爲中間層,隔離上層的最佳實踐和底層的基礎網絡庫

1.1最佳實踐

客戶端網絡庫的一部分工做量是在如何讓最佳實踐作的更好,在音視頻上,無論是iOS的AVPlayer,仍是雙端的ijkPlayer,都是使用HTTPDNS組件接管DNS模塊,沒有所有接管網絡模塊。ReactNative的網絡模塊RCTNetworking,圖片庫Android的Fresco和iOS的SDWebImage,WebView組件Android的Chromium和iOS的WKWebView,以及百度App的自有業務,都是經過網絡門面的接口層直接接管。而對於第三方業務考慮到與宿主耦合的關係,直接使用Android的HttpURLConnection和iOS的URLSession系統標準的接口。

1.2網絡門面

網絡門面主要包括,攔截器模塊(提供給業務訂製網絡門面的機制)、併發隊列模塊(提供高中低以及很是高的網絡請求優先級)、網絡探測組件(弱網主動探測能力)、網絡診斷模塊(包括https,ping,dns的校驗)、HTTPDNS組件(《百度App網絡深度優化系列《一》DNS優化》裏詳細講解)、網絡監控模塊(客戶端的打點機制,服務端的例行和突發監控)、HttpURLConnection封裝層、URLSession封裝層。

1.3基礎網絡庫

基礎網絡庫包含兩部分,一部分是基於cronet二次訂製的統一網絡庫,一部分是WebSocket基礎庫(Android的JavaWebSocket,iOS的SocketRocket)。統一網絡庫內部包含鏈接優化的內容(在《百度App網絡深度優化系列《二》鏈接優化》裏詳細講解),弱網優化的內容(上面提到的被動採集)。經過AOP的方式將底層協議棧注入進HttpURLConnection(利用URLStreamHandlerFactory)和URLSession(利用URLSessionConfiguration的protocolClasses屬性),二者都是系統提供的URL Loading機制。

8、收益

弱網優化的收益咱們主要從上面講到的進入弱網狀態後的手段來看,包括開啓QUIC,QUIC預鏈接,開啓複合鏈接

1)弱網下開啓QUIC後,網絡鏈接成功率提高0.01%,平均耗時下降23.5%。

2)弱網下開啓QUIC預鏈接後,QUIC協議的pv從37萬漲到90萬。

3)弱網下開啓複合鏈接後,bad狀態下耗時下降2.5%,offline狀態下耗時下降7.7%。

9、結語

系列一到系列三的內容到今天所有完成,但願能對你們的工做和學習有所幫助,感謝你們的持續關注和鼓勵。生命不息,優化不止,作技術咱們是認真的

10、參考資料

1. https://chromium.googlesource.com/chromium/src/+/HEAD/docs/android_build_instructions.md

2. https://chromium.googlesource.com/chromium/src/+/HEAD/docs/ios/build_instructions.md

3. https://www.wolfcstech.com/2019/03/27/quic_2019_03_27/

4. https://www.wolfcstech.com/2017/03/09/QUIC%E5%8A%A0%E5%AF%86%E5%8D%8F%E8%AE%AE/

5. https://tools.ietf.org/html/rfc1918

6. https://github.com/Tencent/mars

---------------------------------

在微信-搜索頁面中輸入「百度App技術」,便可關注微信官方帳號。

原文連接地址:https://developer.baidu.com/topic/show/290428

相關文章
相關標籤/搜索