簡單談談移動網絡端的優化
來源:樂云踐新作者:樂云踐新發布時間:2021-08-17
就 "進入某個頁面到該頁面新內容顯示" 這個優化目標而言,我們先拋棄 Android、iOS、Web 的差異,縮減成 "在移動設備上網絡發起請求到接收數據" 的時間,這樣剔除掉組件加載、頁面構建等等其他不確定因素。 那么首先映入我們腦海的,肯定是響應速度,同樣的請求要是只用更少的時間就能拿回數據,那一定很棒!所以我們有了第一個考慮維度 — 速度。 第二個需要考慮的點是安全,用戶在請求數據時,往往會攜帶很多隱私信息 (地區、設備、賬號等等),如何保護這些信息不被竊取,也是另一個需要考慮的地方。 第三個需要考慮的點是穩定,這里主要由兩部分組成。一是服務端的宕機率,很多大型 APP 的宕機率都要求小于 0.1%;二是復雜網絡環境下的策略,這里簡單地舉個例子,用戶在偏遠地區使用我們的 APP,信號不穩定,此時還能否正常返回數據? 這是三點,我考慮到的衡量內容加載的三個維度,這篇文章的后續內容也從這三個維度上,去思考如何優化內容加載。
解剖 我們知道如何衡量這件事情后,接下來就解剖 "內容加載",把其中發生的各個步驟拎出來,通過上述三個維度,來分析每個步驟。當然如果要詳細地將每一個步驟說清楚,這就不是一篇文章的事情,因而在這里只能言簡意賅地說說,最常見的路徑下的各個步驟如下: DNS 查詢 URL 對應 IP 地址。 與服務器建立連接 (通常情況下為 TCP/IP 協議)。 根據應用層協議 (HTTP/HTTPS) 發送請求。 服務器響應請求,返回序列化的數據 (Json/Proto)。 APP 反序列化數據,并予以呈現。 更多更詳細信息,可以參考 GitHub - alex/what-happens-when: An attempt to answer the age old interview question "What happens when you type google.com into your browser and press enter?",詳細地解答了 "當你在瀏覽器中輸入 google.com 并且按下回車之后發生了什么?" 這個問題。 那現在開始,分別從上一小節提到的三個維度出發,分析每一個步驟。
DNS 加載內容時,我們往往是通過 URL (統一資源定位符),諸如 www.google.com 這樣的鏈接。但這樣的 URL 是不能直接使用的,就好像知道一個人的別名,但不能送貨給他。因此我們訪問 Google 時,通過某種查詢服務得知到對應的 IP 地址,然后通過這個 IP 地址,我們才能建立連接請求,獲取內容信息。
這個服務叫做 Domain Name System,也就是大家常說的 DNS。 DNS 本身非常復雜,這里簡要介紹流程。假設用戶使用移動網絡訪問 APP 時,就會首先由網絡服務商 (移動網絡就是電信、移動和聯通等等運營商) 分配一個本地域名服務器 LocalDNS,層層向上詢問,最終通過權威域名服務器,返回一個 IP 地址。 問題 本地域名服務器 LocalDNS 是一個經常被人詬病的服務,我們具體看看都有些什么問題。 1. 安全 首先 LocalDNS 為了自身效率考慮,會做一些緩存,也就是將一些數據記錄在本地,但這樣會導致時效性問題。設想服務端在 12:00 上線了一個很棒的活動,并更改了 IP 地址和對應的解析協議,但由于 LocalDNS 的緩存導致過了一定時間后新的 IP 才生效,用戶就不能及時地體驗這個活動。
上面這條還不是最嚴重的情況,LocalDNS 特別是一些小運營商,經常被人噴的是 DNS 劫持??赡転榱四撤N創收,LocalDNS 緩存了部分頁面,篡改了一下并添加了廣告后,當用戶請求 DNS 服務時,直接返回這個添加了廣告的頁面,用戶就會相當反感! 2. 速度 不僅安全方面可能出現問題,速度也同樣得不到保障。
導致速度可能出現問題的本質原因是,本應作為參考的原始信息丟失,最終導致權威服務器沒有返回一個最優 IP 地址,從而速度受到影響。下面羅列幾種可能性: 小運營商直接將解析請求轉給大運營商,權威 DNS 服務誤以為這是大運營商的請求,從而沒有返回服務器專門針對小運營商優化的 IP 地址。 NAT,更多信息參考網絡地址轉換 - 維基百科,自由的百科全書。當內網的某臺設備想要與互聯網上的服務器進行通信時,IP 地址可能會被更換,一旦做了網絡地址的轉換,權威的 DNS 服務器,就沒辦法通過這個信息作出最優解。
方案 優化的出發點就是盡量減少 DNS 請求,例如將大部分請求都放在同一個域名下。另外也已經有比較成熟的方案,既然 LocalDNS 坑,那我不陪你玩了,自己搞一套! 1. HttpDns HttpDns 就是應運而生的一套解決方案。APP 不再通過 LocalDNS 解析域名,而是通過服務端實現的服務,自己來查詢域名對應的 IP 地址,這里查詢的時候,是直接通過 IP 地址進行查詢的。這樣就略掉了域名解析,速度上面會有優化,直連服務器的做法也規避了 DNS 劫持導致的安全性問題。 當然 HttpDns 能做的事情還有很多,例如客戶端可以有一定的緩存策略,通過緩存來進一步優化時間。又比如服務端可以通過客戶端提供的地區、服務商等等信息,做一些策略優化。
2. CDN 我們查看快遞的時候,經常會發現這樣一種類型的 Case,例如我在南寧買了一個手機,那京東會首先查看南寧倉庫有沒有,沒有繼續就查詢廣西倉庫 (不一定真實存在),如果還沒有就再查詢京東物流總部。這樣下來,快遞的效率很高。某些服務提供商,就提供了這樣的服務 — CDN(Content Delivery Network),讓對應的請求能夠找到最優的倉庫,降低網絡擁塞,以最快的速度返回。 CDN 通常會和 DNS 配合起來使用,所以這里單獨拎出來說,運營同學修改 DNS 的設置,使得用戶在訪問資源時能夠通過 CDN 來執行。由于 CDN 部署和生效需要一定的時間,一般用于分發靜態資源。 TCP - HTTP 再來看看拿到 IP 地址之后的事情,大多數情況下,App 在請求數據時,都是通過 TCP 協議來建立和關閉連接。只有在鏈接建立的基礎之上,才能通過 Http/Https 或者其他應用層協議與服務端交互。
由于 Http 的優化與 TCP 協議緊密相關,這里就放在一塊講。 問題 TCP 協議是面向連接的,可靠的流協議,但在移動網絡下也有些水土不服,需要針對性地做一些優化。HTTP 本身也存在安全性等等問題,咱們具體看看。 1. 速度 TCP 協議在建立和關閉鏈接的時候,會涉及到三次握手和四次揮手,這是相對耗時的操作。但對于絕大多數 App 而言, 單次數據量都不大,但是次數很多,這會導致頻繁地建立和關閉鏈接,導致用戶體感上響應較慢。 HTTP/1.1 的時候,通過管道一次性發送多個請求,希望這樣來提高效率。由于 TCP 協議的設定,每個請求必須按順序進行,也就是說如果上一個請求阻塞住,后面的請求必須等待被阻塞的請求處理完畢過后再進行,這個問題被稱為隊頭阻塞 (Head-of-line blocking)。盡管在 HTTP/2 的時候,將數據拆分成若干個 Frame 發送,減少了阻塞的可能性,但只要是 TCP 協議,問題本質是在傳輸層,其實還是不能完全解決。 2. 安全 前些年 iOS 強制要求開發者使用 HTTPS 協議的新聞,在 IT 圈被廣泛討論。原因就在于 HTTP 協議不能很好地保護用戶隱私,隱患一直存在。因而即便在 Android 上,越來越多的 APP 也主動切換到更為安全的 HTTPS 上。 3. 穩定 移動 APP 可能處于各種網絡環境下,2G/3G/4G/校園網/公網等等。Socket 的參數不能適用于所有情況,默認的參數可能表現很差。前面也提到,TCP 協議是有狀態的,請求過去都需要回來的 ACK 包,但弱網環境下,包可能有很大的延遲,包越多就能耗時越久,用戶體感越差。
方案 1. 鏈接復用 既然建立和關閉鏈接耗時,那就盡可能地復用它,這樣就能優化速度。HTTP/1.x 可以設置為 keep-alive,或者接入 HTTP/2,HTTP/2 不僅能提供連接復用,也提供了諸多其他優化,例如 header 數據壓縮,TLS 優化等等。 2. HTTPS HTTP 協議存在安全隱患,那我們給他加上安全控制不就好了嗎? HTTPS 也就誕生了,關于其如何加密數據的方式,也隨著時間迭代了數個版本。有興趣的同學,可以深入地了解下這段歷史,能學到不少東西呢。 3. QUIC 既然 TCP 協議的機制決定速度不是最優的,那能不能用它的兄弟 UDP 來做一些事情? 在 UDP 的基礎之上,添加一些控制,在保證安全性的基礎之上,盡可能地加快速度呢? QUIC,a multiplexed stream transport over UDP 在 Google 的推動下就誕生了,相較于 TCP + TLS + HTTP2 的模式,有以下幾點優勢: Dramatically reduced connection establishment time Improved congestion control Multiplexing without head of line blocking Forward error correction Connection migration DATA 終于到實際傳輸的數據了,這里核心的點,在于如何盡可能地減少包大小和如何保證數據安全上。羅列一下常見的優化方法: 對于服務端定義的協議,查看有沒有冗余的地方,優化數據結構。對于常見的公參字段做簡化,例如 vc = version code,vn = version name 等等。 嘗試使用 Protocol Buffers | Google Developers,相較于其他格式而言,更小更快。 對于圖片而言,可以使用 A new image format for the Web | WebP | Google Developers。
篇幅所限,很多知識都是點到為止,起到拋磚引玉的作用。最后闡述下,并沒有萬能的銀彈,網絡本身的復雜性就決定了沒有統一的解決方案,各 APP 都需要針對自身的情況,去做一些特定的優化,來達到優化的目的,實踐才是唯一的真理。
本文標簽: