前言
成爲一名優秀的Android開發,須要一份完備的知識體系,在這裏,讓咱們一塊兒成長爲本身所想的那樣~。
本文思惟導圖
1、網絡優化維度
一、網絡優化分析
基礎網絡的效率就像一輛列車,時延是火車的速度 (啓動時間),而帶寬就像火車的車箱裝載量,整個傳輸的物理鏈路就像火車的鐵軌。從網絡的通訊過程來看,共涉及到 「三個模塊」:html
-
1)、
「網絡庫 SDK 內部的設計與策略:I/O 併發模型,針對網絡問題的優化」。
-
-
3)、
「網絡相關:用戶網絡(弱網/強網)、運營商、網絡鏈路等」。
而對於網絡的優化,咱們能夠從如下五個維度來進行。java
1)、流量優化
精確獲取網絡流量的消耗量,解決總體均值掩蓋單點異常流量的問題。android
2)、網絡監控
建設全面的網絡監控,由於粗粒度的監控不可以幫助咱們發現和解決問題。git
3)、流量消耗
-
一、精準獲取一段時間的流量消耗、網絡類型、先後臺。
-
-
三、完整鏈路全監控(Request、Response)、主動上報。
4)、網絡請求質量
-
一、請求時長、業務成功率、失敗率、TOP 失敗接口,致使請求失敗的緣由一般有兩種狀況:
-
1)、弱信號:能夠簡單當作手機信號只有一兩格的時候,這是不只僅是信令(無線網絡通訊的都是一個個的信令)發出去困難,還可能致使不斷切換網絡、基站。App 只能在應用層作重試,由於弱信號通常都是一時的。
-
2)、擁塞網絡:能夠類比爲堵車、排隊的場景,數據包排隊,信令也在排隊。這時 App 不斷重試,只會使得擁塞網絡更爲嚴重。咱們只能讓本身的非核心業務不要去排隊,並讓核心業務的數據量更少,協議來回更少。
-
-
三、請求速度、成功率:網絡正常時如何更好地利用帶寬提高網絡請求速度?
-
四、弱網:網絡不穩定是如何最大程度上保證網絡的連通性?
-
5)、其它
二、網絡優化誤區
2、網絡優化工具
一、Network Profiler
特色
-
-
-
3)、僅支持 HttpURLConnection 與 OkHttp
打開高級分析
❝
Run => Edit Cofigurations => 界面最右邊 Profiling => 打開 Enable advanced profiling (required for API level < 26 only)github
❞
使用 Network Profiler 調試 WanAndroid 網絡請求
選中目標網絡請求,能夠看到在下方的 Connection View 一欄看到對應的網絡數據,以下所示:web
選中 Connection View 特定的一條數據便可在右邊看到該請求對應的網絡數據。chrome
Overview
該網絡請求的預覽信息json
普通 Json 數據請求
圖片加載請求
Response
Response Header 與 Body 信息數組
Request
Request Header 與 Body 信息瀏覽器
CallStack
網絡請求的調用堆棧信息, 下圖就是 Awesome-WanAndroid 發起一個網絡請求所經歷的調用堆棧:
Awesome-WanAndroid 使用 Glide 發起一個圖片加載請求所經歷的調用堆棧:
關鍵細節
高級配置中的 required for API level < 26 only 不是限定調試的手機版本小於26,我使用 API 27 的手機也能夠調試。
實踐中得到的新知識及感悟
若是想快速搞懂接手項目中的網絡/圖片加載等框架的w網絡請求流程,可使用 Profiler NETWORK 的 CallStack 功能,而且雙擊其中任意的一行調用鏈方法均可以 jump to 指定源碼。
❝
選中網絡請求沒法顯示數據?
❞
打開高級分析便可。
二、Charles
使用 Java 開發的,MAC 上使用較多。
特色
安裝配置
二、截獲手機端的網絡包。
須要配置手機與電腦鏈接同一 WIFI。
1)、電腦端設置 Charles — 打開 HTTP 代理並設置代理端口
-
Charles 菜單欄 => Proxy => Proxy Settings => 填代理端口 8888 並勾選 Enable transparent HTTP proxying。
2)、手機端設置 WIFI 代理及端口
-
獲取電腦 IP 地址
-
點擊 Charles 的 help => local address。
-
設置 WIFI 代理及端口號
-
手機設置 => WLAN => 查看當前鏈接的 WIFI 詳情 => 最底部代理項設置爲手動 => 配置 電腦 IP 地址與端口號8888。
3)、設置完成,運行任意聯網程序,Charles 會彈出請求鏈接的確認框,點擊 allow 便可。
三、截取 HTTPS
須要信任 Charles 的 CA 證書。
1)、打開 SSL 代理,並配置 Host 與 Port
-
電腦端 Proxy => SSL Proxying Setting => 選中 Enable SSL Proxying 並點擊 Add 配置 Host 與 Port 分半爲 * 與 443。
2)、信任 Charles Proxy CA 機構
-
電腦端 Help => SSL Proxying => Install Charles Root Certificate => 選中並雙擊 Charles Proxy CA 根證書頒發機構 => 點擊信任 => 使用此證書時選擇始終信任。
3)、手機端安裝 Charles 頒發的 SSL 證書
-
電腦端 Help => SSL Proxying => Install Charles Root Certificate on a Mobile Device,此時會彈出提示框讓手機端訪問 http://chls.pro/ssl 去下載證書。
4)、手機端安裝證書
-
從文件管理器中找到下載文件 => 若是是 .pem 結尾i,將後綴名改成 .crt 並點擊該文件 => 輸入鎖屏密碼 => 等待證書導入後配置證書名(我填的是 Charles)便可。
實踐過程
選中目標網絡請求
從 Overview 中能夠看到很全面抓包信息 。
使用斷點功能
1)、右鍵點擊要斷點的 URL,選中 BreakPoints 開啓斷點功能。
2)、點擊頂部 Proxy => Breadkpoint Settings。
3)、雙擊 Breakpoints Settings 面板中的目標
URL,在彈出的 Edit Breakpoint 面板中進行編輯。
4)、這裏默認選擇斷點 Request 與 Response,咱們能夠選擇僅斷點 Response 或 Request。點擊確認即斷點設置完成。
5)、而後,咱們就能夠點擊主面板右側的 Edit Response 編輯 Response,修改完成後點擊最下方的 Execute 便可。
使用 Map Local
1)、自由模擬服務端的返回數據,以提早進行接口測試。
1)、右鍵點擊要使用 Map Local 的 URL,選中Map Local 開啓斷點功能。
1)、而後,咱們在 Edit Mapping 面板中選擇 Map To 的 Local path,選擇本地設定的 maplocal 本地數據(例如 JsonString)
弱網模擬功能
-
-
2)、點擊 Proxy => Throttle Setting => 選中 Enable Throttling
-
3)、這裏預設了不少模擬設置,咱們只需將 網絡包傳輸的速率 Throttle preset 設置爲較低的速率(通常設爲 256/512)。
碰到的問題
-
1)、注意手機與筆記本電腦須要同一 WIFI 下,不能本身開熱點或使用公司內網,不然沒法在 電腦端 沒法彈出手機鏈接 Charles 的提示確認框,而且也沒法下載 Charles 提供的 SSL 證書。
-
2)、手機端下載 Charles 提供的 SSL 證書時最好不使用系統瀏覽器訪問。
三、Wireshark
❝
強烈推薦 geektime-webprotocol
❞
WireShark 主要能夠用來對四種流進行跟蹤,以下所示:
1)、WireShark 基本使用
如何捕獲報文
-
1)、點擊捕獲->選項,打開捕獲窗口
-
網卡設備/流量/捕獲過濾器,點擊「開始」按鈕開始抓包
-
輸出(指定緩存文件)/選項(顯示、名稱解析、自動中止抓包條件) 面板
-
Wireshark 面板
快捷方式工具欄
數據包的顏色(視圖->着色規則)
設定時間顯示格式
數據包列表面板的標記符號
文件操做
-
-
2)、導出標記報文(文件->導出特定分組),亦可按過濾器導出報文 ,
-
如何快速抓取移動設備的報文?
-
-
-
三、用 Wireshark 打開捕獲->選項面板,選擇 wifi 熱點對應的接口設備抓包便可。
2)、Wireshark 過濾器
若是表達式的背景爲綠色,則說明過濾器的語法是正確的,紅色則說明有錯誤。
捕獲過濾器
它用於減小抓取的報文體積,使用 BPF(Berkeley Packet Filter) 語法,功能相對有限。
BPF 能夠在設備驅動級別提供抓包過濾接口,多數抓包工具都支持此語法。而 BPF 的 Expression 表達式由多個 primitives 原語組成。而每個 primitives 原語則由名稱或數字,以及描述它的多個 qualifiers 限定詞組成。
qualifiers 限定詞
-
一、Type:設置數字或者名稱所指示類型
-
-
net ,設定子網,net 192.168.0.0 mask 255.255.255.0 等價於 net 192.168.0.0/24。
-
portrange,設置端口範圍,例如 portrange 6000-8000。
-
二、Dir:設置網絡出入方向
-
src、dst、src or dst、src and dst。
-
ra、ta、addr一、addr二、addr三、addr4(僅對 IEEE 802.11 Wireless LAN 有效)。
-
三、Proto:指定協議類型
-
-
-
decnet、 tcp、udp、icmp、igmp、icmp
-
-
四、其餘
-
gateway:指明網關 IP 地址,等價於 ether host ehost and not host host。
-
broadcast:廣播報文,例如 ether broadcast 或者 ip broadcast。
-
multicast:多播報文,例如 ip multicast 或者 ip6 multicast。
-
簡單示例
src or dst portrange 6000-8000 && tcp or ip6
複製代碼
顯示過濾器
它對已經抓取到的報文進行過濾顯示,功能強大。
基於協議域過濾
-
捕獲全部 TCP 中的 RST 報文:tcp[13]&4==4。
-
抓取 HTTP GET 報文:port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420。(47455420 是 ASCII 碼的 16 進制,表示」GET 」)
-
抓取 HTTP POST 報文:port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504F5354
顯示過濾器的過濾屬性
任何在報文細節面板中解析出的字段名,均可以做爲過濾屬性。在視圖->內部->支持的協議面板裏,能夠看到各字段名對應的屬性名。例如,在報文細節面板中 TCP 協議頭中的 Source Port,對應着過濾屬性爲 tcp.srcport。
經常使用操做符
-
1)、and(&&):AND 邏輯與,ip.src==10.0.0.5 and tcp.flags.fin。
-
2)、or(||):OR 邏輯或,ip.scr==10.0.0.5 or ip.src==192.1.1.1。
-
3)、xor(^^):XOR 邏輯異或,tr.dst[0:3] == 0.6.29 xor tr.src[0:3] == 0.6.29。
-
4)、not(!):NOT 邏輯非,not llc。
-
5)、[...]:中括號[]Slice 切片操做符
-
[n:m]表示 n 是起始偏移量,m 是切片長度,例如:eth.src[0:3] == 00:00:83
-
[n-m]表示 n 是起始偏移量,m 是截止偏移量,例如:eth.src[1-2] == 00:83
-
[:m]表示從開始處至 m 截止偏移量,例如:eth.src[:4] == 00:00:83:00
-
[m:]表示 m 是起始偏移量,至字段結尾,例如:eth.src[4:] == 20:20
-
[m]表示取偏移量 m 處的字節,例如:eth.src[2] == 83
-
[,]使用逗號分隔時,容許以上方式同時出現,例如:eth.src[0:3,1-2,:4,4:,2] ==00:00:83:00:83:00:00:83:00:20:20:83
-
6)、in:大括號{}集合操做符,例如 tcp.port in {443 4430..4434} ,實際等價於 tcp.port == 443 || (tcp.port >= 4430 && tcp.port ⇐ 4434)。
可用函數
顯示過濾器的可視化對話框
環形緩衝器
例如使用 3 個文件的環形緩存器,從 **.1 => **.2 => **.3 而後又從 **.1 文件開始記錄,造成環形。
四、TcpDump(網絡數據包嗅探器)
1)、抓包步驟
一、獲取 ROOT 權限的手機一部
三、將 tcpdump 安裝到手機上
adb push tcpdump /data/local/tmp
複製代碼
四、修改 tcpdump 的權限,使其具備可執行的權限
chmod 777 /data/local/tmp/tcpdump
複製代碼
五、執行 tcpdump 命令進行抓包,按組合鍵 Ctrl + C 能夠中止抓包
六、將抓到的數據包的信息保存爲 Pcap 文件,這裏僅需在執行 tcpdump 後加上 -w 參數
tcpdump-w /data/local/tmp/tcp.pcap
複製代碼
七、把 Pcap 複製到 電腦上,使用 Wireshark 分析數據包的流量。
2)、捕獲及中止條件
-
-
-
-
--time-stamp-precision:指定捕獲時的時間精度,默認毫秒 micro,可選納秒 nano。
-
-s:指定每條報文的最大字節數,默認 262144 字節。
3)、文件操做
-
-w:輸出結果至文件(可被Wireshark讀取分析)。
-
-C:限制輸入文件的大小,超出後之後綴加 1 等數字的形式遞增。 注意單位是 1,000,000 字節。
-
-W:指定輸出文件的最大數量,到達後會從新覆寫第 1 個文件。
-
-G:指定每隔N秒就從新輸出至新文件,注意-w 參數應基於 strftime 參數指定文件名。
-
-
-V:將待讀取的多個文件名寫入一個文件中,經過讀取該文件同時 讀取多個文件。
4)、輸出時間戳格式
5)、分析信息詳情
-
-
-
-v:顯示網絡層頭部更多的信息,如 TTL、id 等。
-
-n:顯示 IP 地址、數字端口代替 hostname 等。
-
-
-A:以 ASCII 方式顯示報文內容,適用 HTTP 分析。
-
-x:以 16 進制方式顯示報文內容,不顯示數據鏈路層。
-
-xx:以 16 進制方式顯示報文內容,顯示數據鏈路層。
-
-X:同時以 16 進制及 ACII 方式顯示報文內容,不顯示數據鏈路層 • -XX 同時以 16 進制及 ACII 方式顯示報文內容,顯示數據鏈路層。
五、Stetho
-
1)、在 build.gradle 中,除了 Stetho 依賴外,還需添加 'com.facebook.stetho:stetho-okhttp3:1.5.0'。
-
2)、在 Application 的 onCreate 方法中初始化 'Stetho.initializeWithDefaults(this)'。
-
3)、調用 OkHttp 的 'addNeworkInterceptor' 方法添加 Stetho 用於收集網絡信息而提供的網絡攔截器。
-
4)、訪問 Chrome 調試頁面 'chrome://inspect'。
六、其它的性能檢測工具
-
strace:跟蹤 Socket 相關的系統調用。
-
-
-
-
-
-
/proc/net 命令:查看網絡統計信息,Android TrafficState 使用了 /proc/net/xt_qtaguid/stats 和 /proc/net/xt_qtaguid/iface_stat_fmt 文件來統計 App 的流量信息。
3、精準獲取流量消耗
一、如何判斷 App 流量消耗偏高?
二、測試方案
-
1)、打開手機設置 => 流量管理 => 僅容許目標 App 聯網
-
2)、能夠查找出大多數的問題,可是線上場景線下可能遇不到。
三、線上流量獲取方案
1)、TrafficStats
特色
API
-
getMobileRxBytes():經過蜂窩流量接收到的信息。
-
getUidRxBytes(int uid):獲取指定 uid 的接收流量。
-
缺點
沒法獲取某個時間段內的流量消耗。
2)、NetworkStatsManager
API 23 以後。
特色
NetUtils.getStats
獲取指定時間間隔的 蜂窩 + WIFI 流量總信息
四、先後臺流量獲取方案
問題:線上反饋 App 後臺流量消耗大?
只獲取一個時間段的流量不夠全面。
實現原理
❝
後臺定時任務 => 獲取時間間隔內流量 => 記錄先後臺 => 分別計算 => 上報 APM 後臺 => 流量治理依據
❞
小結
-
1)、該方案沒法獲取應用在先後臺切換時的流量,所以有必定的偏差,但這個偏差是能夠接受的。
-
2)、結合精細化的流量異常報警針對性的解決後臺跑流量的問題。
成功 log 以下所示:
2020-05-11 10:47:55.633 4036-4181/json.chao.com.wanandroid I/WanAndroid-LOG: │ [MainActivity.java | 193 | lambda$initEventAndData$1$MainActivity] backNetUseData: 4 MB
2020-05-11 10:47:55.646 4036-4181/json.chao.com.wanandroid I/WanAndroid-LOG: │ [MainActivity.java | 194 | lambda$initEventAndData$1$MainActivity] foreNetUseData: 4 MB 2020-05-11 10:47:55.652 4036-4181/json.chao.com.wanandroid I/WanAndroid-LOG: │ [MainActivity.java | 197 | lambda$initEventAndData$1$MainActivity] totalNetUseData: 8 MB 複製代碼
4、網絡請求流量優化
一、常見使用網絡的場景
1)、數據壓縮
POST 請求 Body 使用 GZip 壓縮,同時服務端返回 Body 也使用 GZip 壓縮。
2)、圖片
-
-
圖片使用策略細化:讓 服務端/CDN 雲服務器 優先使用縮略圖/WebP格式圖片。
3)、性能日誌上報:批量 + 特定場景上報
APM 相關、單點問題相關。例如埋點數據能夠等到某一時機點(例如 開啓了 WIFI、數據量過大必須上傳一部分時)再上傳。
4)、數據緩存
服務端返回加上過時時間,避免每次從新獲取。 節約流量且大幅提升數據訪問速度,更好的用戶體驗。
Request 緩存設置
-
一、Pragma:no-cache:去服務器拉取最新的資源,不使用緩存。
-
二、If-Modified-Since:datetime:若是資源在客戶端提供的時間後發生改變,服務器會返回新的資源,不然使用緩存。
-
三、If-None-Match:etagvalue:若是資源的標識和服務器的不一樣,返回新的資源。
當 Request 的頭部是 2 和 3 時,若是服務器的資源沒有修改,則服務器會返回 HTTP/304 Not Modified,客戶端會使用緩存的 Response。
Response 緩存設置
HTTP Response 是否能夠緩存是由 Response 的頭部控制的,服務器能夠經過 Expires 和 Cache-Control 控制 Response 如何在客戶端緩存。
Expires
Expires 頭部會包含一個日期,即該資源緩存的有效期,客戶端有新的相同請求時,若是資源緩存沒有過時,則使用緩存資源,服務器不會返回任何東西。
Cache-Control
Cache-Control 能夠標明 Response 如何存儲及其如何使用,其選項以下所示:
-
1)、public:Response 能夠存儲在任何 Cache 中,包括共享的 Cache。
-
2)、private:Response 存儲在私有 Cache 中,只能被一個用戶使用。
-
3)、no-cache:Response 未來不會被使用。
-
4)、no-store:Response 未來不會被使用,也不會寫到磁盤上。
-
5)、max-age=#seconds:Response 在設定的時間內能夠被重複使用。
-
6)、must-revalidate:和原始服務器確認 Response 是最新後,可使用緩存。
OKHttp 無網數據緩存實現
POST 在 OKHttp 中默認不會緩存,由於 POST 通常是用來修改數據的。在 Awesome-WanAndroid 中的 HttpModule—cacheInterceptor 中就已經實現了 OKHttp 的無網數據緩存,代碼以下所示:
File cacheFile = new File(Constants.PATH_CACHE);
Cache cache = new Cache(cacheFile, 1024 * 1024 * 50); Interceptor cacheInterceptor = chain -> { Request request = chain.request(); if (!CommonUtils.isNetworkConnected()) { request = request.newBuilder() .cacheControl(CacheControl.FORCE_CACHE) .build(); } Response response = chain.proceed(request); if (CommonUtils.isNetworkConnected()) { int maxAge = 0; response.newBuilder() .header("Cache-Control", "public, max-age=" + maxAge) .removeHeader("Pragma") .build(); } else { int maxStale = 60 * 60 * 24 * 28; response.newBuilder() .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale) .removeHeader("Pragma") .build(); } return response; }; builder.addNetworkInterceptor(cacheInterceptor); builder.addInterceptor(cacheInterceptor); builder.cache(cache); 複製代碼
5)、離線包、增量數據更新
加上版本的概念,僅傳輸有變化的數據。
6)、請求頭壓縮
若是請求頭不變,服務端可使用映射緩存 請求頭 MD5 : 請求頭,以後請求頭都使用 MD5 便可。
7)、優化發送頻率和時機
8)、合併網絡請求、減小請求次數。
9)、流量兜底能力
若是發現流量異常,咱們能夠經過後臺服務器終止協議交互,以免問題惡化。
二、流量統計
咱們能夠利用 network-connection-class 進行流量統計,它內部使用的是 API 8 的 TrafficStats 類,用於獲取整個手機或者某個 UID 從開機算起的網絡流量。
1)、四個核心 API
getMobileRxBytes() getTotalRxBytes() getMobileTxBytes() getTotalTxBytes() 複製代碼
2)、對應的Linux 內核 proc 統計接口
/proc/net/xt_qtaguid/stats proc/net/xt_qtaguid/iface_stat_fmt 複製代碼
3)、工做原理
-
1)、讀取 proc,並將目標 UID 下面全部網絡接口的流量相加。
-
2)、Android 7.0 以後只能經過 TrafficStats 拿到本身應用的流量信息。
❝
《深刻探索 Android 性能優化(3、網絡優化篇)下》將在本週四發佈,敬請期待。
❞
公衆號
個人公衆號 JsonChao
開通啦,若是想第一時間(明天8:30)查看《深刻探索 Android 性能優化(3、網絡優化篇)下》,歡迎掃描二維碼進行閱讀~
參考連接:
Contanct Me
● 微信:
❝
歡迎關注個人微信:bcce5360
❞
● 微信羣:
❝
「因爲微信羣人數過多,麻煩你們想進微信羣的朋友們,加我微信拉你進羣。」
❞
● QQ羣:
❝
2千人QQ羣,「Awesome-Android學習交流羣,QQ羣號:959936182」, 歡迎你們加入~
❞
About me
很感謝您閱讀這篇文章,但願您能將它分享給您的朋友或技術羣,這對我意義重大。
但願咱們能成爲朋友,在 Github、掘金上一塊兒分享知識。