默認
打賞 發表評論 6
想開發IM:買成品怕坑?租第3方怕貴?找開源自已擼?盡量別走彎路了... 找站長給點建議
移動端IM開發者必讀(二):史上最全移動弱網絡優化方法總結
閱讀(35160) | 評論(6 收藏7 淘帖2 2

本系列文章引用了騰訊技術專家樊華恒《海量之道系列文章之弱聯網優化 gad.qq.com/article/detail/29546》的章節,感謝原作者。


1、前言


本文接上篇《移動端IM開發者必讀(一):通俗易懂,理解移動網絡的“弱”和“慢”》,關于移動網絡的主要特性,在上篇中已進行過詳細地闡述,本文將針對上篇中提到的特性,結合我們的實踐經驗,總結了四個方法來追求極致的“爽快”:快鏈路、輕往復、強監控、多異步,從理論講到實踐、從技術講到產品,理論聯系實際,舉一反三,希望給您帶來啟發

如果您還未閱讀完上篇《移動端IM開發者必讀(一):通俗易懂,理解移動網絡的“弱”和“慢”》,建議您先行讀完后再續本文。

本篇的目的,就是希望以通俗易懂的語言,幫助移動端IM開發者更好地針對性優化移動網絡的各種特性,使得開發出的功能給用戶帶來更好的使用體驗。

本文乃全網同類文章中,唯一內容最全、“糞”量最重者,請做好心理準備耐心讀下去,不要辜負作者已打上石膏的雙手和用廢的鍵盤。

另外,《現代移動端網絡短連接的優化手段總結:請求速度、弱網適應、安全保障》這篇文章也提到了本文所闡述的相關內容,強烈建議閱讀。

2、系列文章


本文是《移動端IM開發者必讀》系列文章的第2篇:


如果您是IM開發初學者,強烈建議首先閱讀《新手入門一篇就夠:從零開發移動端IM》。

3、相關文章


1)關于網絡通信的基礎文章:


2)涉及移動端網絡特性的文章:


3)如果您覺得有些網絡問題,已無法從應用層找到答案,那么以下這個系列是你的“菜”:
    以下文章為IM/推送技術開發的邊界知識,但有助于你從物理層理解各種網絡問題。如無興趣,可忽略之!

4、優化方法一:“快鏈路”


我們需要有一條(相對)快速、(相對)順暢、(相對)穩定的網絡通道承載業務數據的傳輸,這條路的最好是傳輸快、不擁堵、帶寬大、收費少。生活中做個類比,我們計劃驅車從深圳到廣州,如果想當然走廣深高速十之八九要杯具,首先這個高速略顯破敗更像省道,路況不佳不敢提速;其次這條路上的車時常如過江之鯽,如果身材不好操控不便,根本就快不起來;最后雙向六車道雖然勉強可以接受,但收費居然比廣深沿江高速雙向八車道還貴;正確的選路方案目前看是走沿江高速,雖然可能要多跑一段里程,但是通行更暢快。

實際上,真實情況要更復雜,就如同上篇中【圖二 有線互聯網和移動互聯網網絡質量差異】所示(就是下圖),漫漫征途中常常會在高速、國道、省道、田間小道上切換。

移動端IM開發者必讀(二):史上最全移動弱網絡優化方法總結_11.jpg

4.1TCP/IP協議棧參數調優


純技術活,直接上建議得了,每個子項爭取能大致有個背景交待,如果沒說清楚,可以先看看以下資料:
TCP/IP詳解 - 第17章·TCP:傳輸控制協議
TCP/IP詳解 - 第18章·TCP連接的建立與終止
TCP/IP詳解 - 第21章·TCP的超時與重傳
通俗易懂-深入理解TCP協議(上):理論基礎
通俗易懂-深入理解TCP協議(下):RTT、滑動窗口、擁塞處理
理論經典:TCP協議的3次握手與4次揮手過程詳解
不為人知的網絡編程(一):淺析TCP協議中的疑難雜癥(上篇)
不為人知的網絡編程(二):淺析TCP協議中的疑難雜癥(下篇)
不為人知的網絡編程(三):關閉TCP連接時為什么會TIME_WAIT、CLOSE_WAIT
網絡編程懶人入門(三):快速理解TCP協議一篇就夠

① 控制傳輸包大小

控制傳輸包的大小在1400字節以下。暫時不講為什么這樣建議,先舉個例子來類比一下,比如一輛大卡車滿載肥豬正在高速上趕路,豬籠高高層疊好不壯觀,這時前方突然出現一個隧道限高標識,司機發現卡車超限了,這下咋整。方案一,停車調頭重新找路,而且十之八九找不到,最后只能哪來回哪;方案二,把其中一群豬卸下來放本地找人代養,到達目的地卸完貨回來再取,你別說,這個機制在TCP/IP協議棧中也有,學名“IP分片”,后面會專門介紹。這個故事側面證實美國計算機科學家也曾經蹲在高速路邊觀察生豬超載運輸的過程,并飽受啟發。且慢,每次遇到問題,想到一些方案后我們都應該再捫心自問:“還有沒有更好的辦法呢?”。當然有,參照最近流行的說法,找個臺風眼,把豬都趕過去,飛一會就到了,此情此景想想也是醉了。

回歸正題,概括的說,我們設定1400這個閾值,目的是減少往復,提高效能。因為TCP/IP網絡中也有類似高速限高的規定,如果在超限時想要繼續順暢傳輸,要么做IP分片要么把應用數據拆分為多個數據報文(意指因為應用層客戶端或服務器向對端發送的請求或響應數據太大時,TCP/IP協議棧控制機制自動將其拆分為若干獨立數據報文發送的情況,后面為簡化討論,都以IP分片這個分支為代表,相關過程分析和結論歸納對二者均適用)。而一旦一個數據報文發生了IP分片,便會在數據鏈路層引入多次的傳輸和確認,加上報文的拆分和拼接開銷,令得整個數據包的發送時延大大增加,并且,IP分片機制中,任何一個分片出現丟失時還會帶來整個IP數據報文從最初的發起端重傳的消耗。有點枯燥了,更深入的理解,請參見:《海量之道系列文章之弱聯網優化 (二)》。

我們可以得出如下結論,TCP/IP數據報文大小超過物理網絡層的限制時,會引發IP分片,從而增加時空開銷。

因此,設定合理的MSS至關重要,對于以太網MSS值建議是1400字節。什么,你的數學是體育老師教的嗎?前面說以太網最大的傳輸數據大小是1500字節,IP數據報文包頭是20字節,TCP報文包頭是20字節,算出來MSS怎么也得是1460字節呀。如果回答是因為很多路由設備比如CISCO路由器把MSS設定為1400字節,大伙肯定不干,回憶一下IP和TCP的數據報包頭都各有40字節的可選項,MTU中還需要為這些可選項留出空間,也就壓縮了MSS的空間。要是再追問為啥這個值不是1380字節,那就有點過分了。

知識加油站:什么是MSS?

TCP MSS(TCP Maximum Segment Size,TCP最大報文段長度,后面均簡稱MSS)表示TCP/IP協議棧一次可以傳往另一端的最大TCP數據長度,注意這個長度是指TCP報文中的有效“數據”(即應用層發出的業務數據)部分,它不包括TCP報文包頭部分,我們可以把它理解為卡車能裝運生豬的最大數量或重量。它是TCP選項中最經常出現,也是最早出現的選項,占4字節空間。

MSS是在建立TCP鏈接的三次握手過程中協商的,每一方都會在SYN或SYN/ACK數據報文中通告其期望接收數據報文的MSS(MSS也只能出現在SYN或SYN/ACK數據報中),說是協商,其實也沒太多回旋的余地,原因一會講。如果協商過程中一方不接受另一方的MSS值,則TCP/IP協議棧會選擇使用默認值:536字節。


那么問題來了,控制“限高”哪種方案才最強。我們嘗試探討一下。

首先,可以在我們自己IDC內將各種路由交換設備的MSS設定小于或等于1400字節,并積極參與TCP三次握手時的MSS協商過程,期望達到自動控制服務器收發數據報文大小不超過路徑最小MTU從而避免IP分片。這個方案的問題是如果路由路徑上其它設備不積極參與協商活動,而它的MTU(或MSS設置值)又比較low,那就白干了。這就好比國家制定了一個高速沿途隧道限高公示通告標準,但是某些地方政府就是不告訴你,沒轍。

其次,可以在業務服務中控制應用數據請求/響應的大小在1400字節以下(注:也無法根本避免前述方案中間路由MTU/MSS low的問題),在應用層數據寫入時就避免往返數據包大小超過協商確定的MSS。但是,歸根到底,在出發前就把數據拆分為多個數據報文,同IP分片機制本質是相同的,交互響應開銷增加是必然的。考慮到人在江湖,安全第一,本方案從源頭上控制,顯得更實際一些。

當然,最靠譜的還是做簡法,控制傳輸數據的欲望,用曼妙的身姿騰挪有致,相關的內容放到輕往復章節探討。

對應到前面的快樂運豬案例,就是要么在生豬裝車之前咱們按照這條路上的最低限高來裝車(問題是怎么能知道整個路上的最低限高是多少),要么按照國家標準規定允許的最小限高來裝車,到這里,肥豬們終于可以愉快的上路了,風和日麗,通行無阻,嗯,真的嗎?

② 放大TCP擁塞窗口

把TCP擁塞窗口(cwnd)初始值設為10,這也是目前Linux Kernel中TCP/IP協議棧的缺省值。放大TCP擁塞窗口是一項有理有據的重要優化措施,對移動網絡尤其重要,我們同樣從一些基本理論開始逐步深入理解它。

TCP是個傳輸控制協議,體現控制的兩個關鍵機制分別是基于滑動窗口的端到端之間的流量控制和基于RTT/RTO測算的端到網絡之間的擁塞控制。

流量控制目標是為了避免數據發送太快對端應用層處理不過來造成SOCKET緩存溢出,就像一次發了N車肥豬,買家那邊來不及處理,然后臨時囤貨的豬圈又已客滿,只好拒收/拋棄,相關概念和細節我們不展開了,有興趣可以研讀《TCP/IP詳解 卷一:協議》。

擁塞控制目標是在擁塞發生時能及時發現并通過減少數據報文進入網絡的速率和數量,達到防止網絡擁塞的目的,這種機制可以確保網絡大部分時間是可用的。擁塞控制的前提在于能發現有網絡擁塞的跡象,TCP/IP協議棧的算法是通過分組丟失來判斷網絡上某處可能有擁塞情況發生,評判的具體指標為分組發送超時和收到對端對某個分組的重復ACK。在有線網絡時代,丟包發生確實能比較確定的表明網絡中某個交換設備故障或因為網絡端口流量過大,路由設備轉發處理不及時造成本地緩存溢出而丟棄數據報文,但在移動網絡中,丟包的情況就變得非常復雜,其它因素影響和干擾造成丟包的概率遠遠大于中間路由交換設備的故障或過載。比如短時間的信號干擾、進入一個信號屏蔽的區域、從空閑基站切換到繁忙基站或者移動網絡類型切換等等。網絡中增加了這么多不確定的影響因素,這在TCP擁塞控制算法最初設計時,是無法預見的,同時,我們也確信未來會有更完善的解決方案。這是題外話,如有興趣可以找些資料深入研究(詳見:《TCP/IP詳解 - 第21章·TCP的超時與重傳》、《通俗易懂-深入理解TCP協議(下):RTT、滑動窗口、擁塞處理》、《海量之道系列文章之弱聯網優化 (三)》)。

擁塞控制是TCP/IP協議棧最經典的和最復雜的設計之一,互聯網自我犧牲的利他精神表露無遺,設計者認為,在擁塞發生時,我們應該減少數據報文進入網絡的速率和數量,主動讓出道路,令網絡能盡快調整恢復至正常水平。

③ 調大SOCKET讀寫緩沖區

把SOCKET的讀緩沖區(亦可稱為發送緩沖區)和寫緩沖區(亦可稱為接收緩沖區)大小設置為64KB。在Linux平臺上,可以通過 setsockopt 函數設置SO_RCVBUF和SO_SNDBUF選項來分別調整SOCKET讀緩沖區和寫緩沖區的大小。

這兩個緩沖區跟我們的TCP/IP協議棧到底有怎么樣的關聯呢。我們回憶一下TCP數據報格式及首部中的各字段里面有個16位窗口大小(見下圖),還有我們前面提到的流量控制機制和滑動窗口的概念,大幕徐徐拉開,主角紛紛粉墨登場。在正式詳細介紹之前,按照傳統,我們還是先站在豬場老板的角度看一下,讀緩沖區就好比買家用來囤貨的臨時豬圈,如果貨到了買家使用部門來不及處理,就先在這里臨時囤著,寫緩沖區就好比養豬場根據訂單裝好車準備發貨,如果買家說我現在可以收貨便可速度發出,有點明白了吧。

移動端IM開發者必讀(二):史上最全移動弱網絡優化方法總結_222.png

④ 調大RTO(Retransmission TimeOut)初始值

將RTO(Retransmission TimeOut)初始值設為3s。

TCP為每一個報文段都設定了一個定時器,稱為重傳定時器(RTO),當RTO超時且該報文段還沒有收到接收端的ACK確認,此時TCP就會對該報文段進行重傳。當TCP鏈路發生超時時,意味著很可能某個報文段在網絡路由路徑的某處丟失了,也因此判斷此時網絡出現擁塞的可能性變得很大,TCP會積極反應,馬上啟動擁塞控制機制。

RTO初始值設為3s,這也是目前Linux Kernel版本中TCP/IP協議棧的缺省值,在鏈路傳輸過程中,TCP協議棧會根據RTT動態重新計算RTO,以適應當前網絡的狀況。有很多的網絡調優方案建議把這個值盡量調小,但是,我們開篇介紹移動網絡的特點之一是高時延,這也意味著在一個RTT比較大的網絡上傳輸數據時,如果RTO初始值過小,很可能發生不必要的重傳,并且還會因為這個事件引起TCP協議棧的過激反應,大炮一響,擁塞控制閃亮登場。

豬場老板的態度是什么樣的呢:曾經有一份按時發貨的合同擺在我的面前,我沒有去注意,等到重新發了貨才追悔莫及,塵世間最痛苦的事莫過于此,如果上天能給我一個再來一次的機會,我希望對甲方說耐心點,如果非要給這個耐心加一個期限的話,我希望是一萬年。

⑤ 禁用TCP快速回收


TCP快速回收是一種鏈接資源快速回收和重用的機制,當TCP鏈接進入到TIME_WAIT狀態時,通常需要等待2MSL的時長,但是一旦啟用TCP快速回收,則只需等待一個重傳時間(RTO)后就能夠快速的釋放這個鏈接,以被重新使用。

Linux Kernel的TCP/IP協議棧提供了一組控制參數用于配置TCP端口的快速回收重用,當把它們的值設置為1時表示啟用該選項:

  • 1)  net.ipv4.tcp_tw_reuse = 1
  • 2) net.ipv4.tcp_tw_recycle = 1
  • 3)  net.ipv4.tcp_timestamps = 1(tcp_tw_recycle啟用時必須同時啟用本項,反之則不然,timestamps用于RTT計算,在TCP報文頭部的可選項中傳輸,包括兩個參數,分別為發送方發送TCP報文時的時間戳和接收方收到TCP報文響應時的時間戳。Linux系統和移動設備上的Android、iOS都缺省開啟了此選項,建議不要隨意關閉)

以上參數中tw是TIME_WAIT的縮寫,TIME_WAIT與TCP層的鏈接關閉狀態機相關。具體TIME_WAIT是誰,從哪里來,往哪里去,可以詳見:《海量之道系列文章之弱聯網優化 (四)》。

⑥ HTTP協議:打開SOCKET的TCP_NODELAY選項

TCP/IP協議棧為了提升傳輸效率,避免大量小的數據報文在網絡中流竄造成擁塞,設計了一套相互協同的機制,那就是Nagle's Algorithm和TCP Delayed Acknoledgement。

Nagle算法(Nagle's Algorithm)是以發明人John Nagle的名字來命名。John Nagle在1984年首次用這個算法來嘗試解決福特汽車公司的網絡擁塞問題(RFC 896),該問題的具體描述是:如果我們的應用程序一次產生1個字節的數據(典型的如telnet、XWindows等應用),而這個1個字節數據又以網絡數據包的形式發送到遠端服務器,那么就很容易使網絡中有太多微小分組而導致過載。

因為傳輸1個字節有效數據的微小分組卻需花費40個字節的額外開銷(即IP包頭20字節 + TCP包頭20字節),這種有效載荷利用率極其低下的情況被統稱為愚蠢窗口癥候群(Silly Window Syndrome),前面我們在談MSS時也提到過,如果為一頭豬開個大卡車跑一趟,也夠愚鈍的。對于輕負載廣域網或者局域網來說,尚可接受,但是對于重負載的廣域網而言,就極有可能引起網絡擁塞導致癱瘓。

現代TCP/IP 協議棧默認幾乎都啟用了這兩個功能。

我們在移動APP的設計實現中,請求大部分都很輕(數據大小不超過MSS),為了避免上述分析的問題,建議開啟SOCKET的TCP_NODELAY選項,同時,我們在編程時對寫數據尤其要注意,一個有效指令做到一次完整寫入(后面會講協議合并,是多個指令一次完整寫入的設計思想),這樣服務器會馬上有響應數據返回,順便也就捎上ACK了。

4.2接入調度


① 就快接入

在客戶端接入服務器調度策略的演化過程中,我們最早采用了“就近接入”的策略,在距離客戶端更近的地方部署服務器或使用CDN,期望通過減少RTT來提高網絡交互響應性能。這個策略在國內的落地執行還需要加一個前綴:“分省分運營商”,這就給廣大負責IDC建設的同學帶來了巨大的精神和肉體折磨。

在持續運營的過程中,根據觀察到的數據,發現并非物理距離最近的就是最快的。回憶一下前面談到的吞吐量指標BDP,它與鏈路帶寬和RTT成正比關系,而RTT是受物理距離、網絡擁塞程度、IDC吞吐量、跨網時延等諸多因素綜合影響的,單純的就近顯然不夠精細了。

“就快接入”在“就近接入”策略的基礎上改善提升,它利用客戶端測速和報告機制,通過后臺大數據分析,形成與客戶端接入IP按就快原則匹配接入服務器的經驗調度策略庫,令客戶端總能優先選擇到最快的服務器接入點。

有關就快接入的更詳細方案,請參見:《海量之道系列文章之弱聯網優化(五)》一文的“3.1.2節”。

② 去DNS的IP直連

DNS不但需要1個RTT的時間消耗,而且移動網絡下的DNS還存在很多其它問題:

  • 1) 部分DNS承載全網用戶40%以上的查詢請求,負載重,一旦故障,影響巨大,這樣的案例在PC互聯網也有很多,Google一下即可感受觸目驚心的效果;
  • 2) 山寨、水貨、刷ROM等移動設備的LOCAL DNS設置錯誤;
  • 3) 終端DNS解析濫用,導致解析成功率低;
  • 4) 某些運營商DNS有域名劫持問題,實際上有線ISP也存在類似問題。域名劫持對安全危害極大,產品設計時要注意服務端返回數據的安全校驗(如果協議已經建立在安全通道上時則不用考慮,安全通道可以基于HTTPS或者私有安全體系)。對于劫持的判斷需要客戶端報告實際拉取服務數據的目標地址IP等信息;
  • 5) DNS污染、老化、脆弱。

綜上就是在前述就快接入小節中,接入調度FSM會優先使用動態服務器列表的原因。

有關移動端網絡的DNS問題,詳見:《全面了解移動端DNS域名劫持等雜癥:技術原理、問題根源、解決方案等》。

③ 網絡可達性探測

在連接建立過程中如果出現連接失敗的現象,而終端系統提供的網絡狀態接口反饋網絡可用時,我們需要做網絡可達性探測(即向預埋的URL或者IP地址發起連接嘗試),以區別網絡異常和接入服務異常的情況,為定位問題,優化后臺接入調度做數據支持。

探測數據可以異步報告到服務器,至少應該包含以下字段:

  • 1) 探測事件ID,要求全局唯一不重復;
  • 2) 探測發生時間;
  • 3) 探測發生時網絡類型和其它網絡信息(比如WIFI時的SSID等);
  • 4) 本地調度的接入服務器集合類型;
  • 5) 本地調度的接入服務器IP(如使用域名接入,可忽略);
  • 6) 探測的目標URL或IP地址
  • 7) 本次探測的耗時。

4.3鏈路管理


鏈路就是運肥豬的高速路,就快接入是選路,鏈路管理就是如何高效的使用這條路。下面是一些實踐總結:

① 鏈路復用

我們在開篇討論無線網絡為什么慢的時候,提到了鏈接建立時三次握手的成本,在無線網絡高時延、頻抖動、窄帶寬的環境下,用戶使用趨于碎片化、高頻度,且請求響應又一次性往返居多、較頻繁發起等特征,建鏈成本顯得尤其顯著。

因此,我們建議在鏈路創建后可以保持一段時間,比如HTTP短鏈接可以通過HTTP Keep-Alive,私有協議可以通過心跳等方式來保持鏈路。

具體要點建議如下:

  • 1) 鏈路復用時,如果服務端按就快策略機制下發了新的接入動態服務器列表,則應該按照接入調度FSM的狀態變遷,在本次交互數據完成后,重建與新的接入服務器的IP鏈路,有三個切換方案和時機可選擇:
        - a. 關閉原有鏈接,暫停網絡通訊,同時開始建立與新接入服務器的TCP鏈路,成功后恢復與服務器的網絡交互;
        - b. 關閉原有鏈接,暫停網絡通訊,待有網絡交互需求時開始建立與新接入服務器的IP鏈路;
        - c. 原有鏈接繼續工作,并同時開始建立與新接入服務器的TCP鏈路,成功后新的請求切換到新建鏈路上,這個方式或可稱為預建鏈接,原鏈接在空閑時關閉。
  • 2) 鏈路復用時區分輕重數據通道,對于業務邏輯等相關的信令類輕數據通道建議復用,對于富媒體拉取等重數據通道就不必了;
  • 3) 鏈路復用時,如與協議合并(后面會討論)結合使用,效果更佳。

② 區分網絡類型的超時管理

在不同的網絡類型時,我們的鏈路超時管理要做精細化的區別對待。鏈路管理中共有三類超時,分別是連接超時、IO超時和任務超時。

我們有一些經驗建議,提出來共同探討:

  • 1) 連接超時:2G/3G/4G下5 ~ 10秒,WIFI下5秒(給TCP三次握手留下1次超時重傳的機會,可以研究一下《TCP/IP詳解 卷一:協議》中TC P的超時與重傳部分);
  • 2) IO超時:2G/3G/4G下15 ~ 20秒(無線網絡不穩定,給抖動留下必要的恢復和超時重傳時間),WIFI下15秒(1個MSL);
  • 3) 任務超時:根據業務特征不同而差異化處理,總的原則是前端面向用戶交互界                     面的任務超時要短一些(盡量控制在30秒內并有及時的反饋),后臺任務可以長一些,輕數據可以短一些,重數據可以長一些;
  • 4) 超時總是伴隨著重試,我們要謹慎小心的重試,后面會討論。

超時時間宜短不宜長,在一個合理的時間內令當前鏈路因超時失效,從而驅動調度FSM狀態的快速變遷,效率要比癡癡的等待高得多,同時,在用戶側也能得到一個較好的正反饋。

各類超時參數最好能做到云端可配可控。

③ 優質網絡下的并發鏈路

當我們在4G、WIFI(要區分是WIFI路由器還是手機熱點)等網絡條件較優時,對于請求隊列積壓任務較多或者有重數據(富媒體等下載類數據)請求時,可以考慮并發多個鏈路并行執行。

對于單一重數據任務的多鏈接并發協同而言,需要服務器支持斷點續傳,客戶端支持任務協同調度;

④ 輕重鏈路分離


輕重鏈路分離,也可以說是信令和數據分離,目的是隔離網絡通訊的過程,避免重數據通訊延遲而阻塞了輕數據的交互。在用戶角度看來就是信息在異步加載,控制指令響應反饋及時。

移動端大部分都是HTTP短鏈接模式工作,輕重數據的目標URL本身就不同,比較天然的可以達到分離的要求,但是還是要特別做出強調,是因為實踐中有些輕數據協議設計里面還會攜帶類似頭像、驗證碼等的實體數據。

⑤ 長鏈接

長鏈接對于提升應用網絡交互的及時性大有裨益,一方面用戶使用時,節省了三次握手的時間等待,響應快捷;另一方面服務器具備了實時推送能力,不但可以及時提示用戶重要信息,而且能通過推拉結合的異步方案,更好的提升用戶體驗。

長鏈接的維護包括鏈接管理、鏈接超時管理、任務隊列管理等部分,設計實施復雜度相對高一些,尤其是在移動網絡環境下。為了保持鏈路還需要做心跳機制(從另外一個角度看,這也是針對簡單信息一個不錯的PULL/PUSH時機,,但需注意數據傳輸要夠輕,比如控制在0.5KB以內),而心跳機制是引入長鏈接方案復雜度的一個重要方面,移動網絡鏈路環境復雜,國內網關五花八門,鏈路超時配置各有千秋,心跳時長選擇學問比較大,不但要區分網絡類型,還得區分不同運營商甚至不同省市,歷史上曾經實踐了2分鐘的心跳間隔,最近比較多的產品實踐選擇4.5分鐘的心跳間隔。而且長鏈接除了給移動網絡尤其是空中信道帶來負擔外,移動設備自身的電量和流量也會有較大的消耗,同時還帶來后端帶寬和服務器投入增加。

所以,除了一些粘性和活躍度很高、對信息到達實時性要求很高的通訊類APP外,建議謹慎使用長鏈接,或可以考慮采用下面的方式:

  • 1)  退化長鏈接:即用戶在前臺使用時,保持一個長鏈接鏈路,活躍時通過用戶使用驅動網絡IO保持鏈路可用;靜默時通過設置HTTP Keep-Alive方式,亦或通過私有協議心跳方式來保持鏈路。一旦應用切換后臺,且在5~10分鐘內沒有網絡交互任務則自行關閉鏈路,這樣在用戶交互體驗和資源消耗方面取得一個平衡點;
  • 2)  定時拉取/詢問:對于一些有PUSH需求的APP,我們可以采用一個云端可配置間隔時長的定時拉取/詢問方案。有三個重點,一是定時的間隔云端可以配置,下發更新到客戶端后下次生效;二是拉取/詢問時,如果下發的指令有要求進一步PULL時,可以復用已建立的鏈路,即前述退化長鏈接的模式;三是定時拉取/詢問時機在客戶端要做時間上的均勻離散處理,避免大的并發查詢帶來帶寬和負載的巨大毛刺;
  • 3) 如果可能,優先使用OS內置的PUSH通道:比如iOS的APNS、Andriod的 GCM(Google這個以工程師文化著稱的公司,在做OS級基礎設施建設時,卻表現出了很差的前瞻性和系統思考的能力,GCM的前身C2DM都沒怎么普及使用就被替換了,這也意味著Android各種版本PUSH能力不 一致的問題。但無論怎么說,OS級的基礎設施無論在性能、穩定性還是在效率上都會優于APP層自己實現的方案),實施推拉結合的方案。特別要提到的一點是,中國特色無所不在,國內運營商曾經封過APNS的PUSH端口2195,也會干擾GCM的端口5528,更別提這些底層服務的長鏈接會被運營商干擾。對于Android平臺,還存在系統服務被各種定制修改的問題。別擔心,辦法總比問題多,保持清醒。

有關Android的推送問題,可以參考:
應用保活終極總結(三):Android6.0及以上的保活實踐(被殺復活篇)
Android進程保活詳解:一篇文章解決你的所有疑問
Android端消息推送總結:實現原理、心跳保活、遇到的問題等
深入的聊聊Android消息推送這件小事
為何基于TCP協議的移動端IM仍然需要心跳保活機制?
微信團隊原創分享:Android版微信后臺保活實戰分享(網絡保活篇)
移動端IM實踐:實現Android版微信的智能心跳機制
移動端IM實踐:WhatsApp、Line、微信的心跳策略分析》)

⑥ 小心重試

自動重試是導致后臺雪崩的重要因素之一。在移動網絡不穩定的條件下,大量及時的重試不但不能達到預期,反而無謂的消耗移動設備的電量甚至流量。

因此,我們在重試前要有一些差異化的考慮:

  • 1) 當前移動設備的網絡狀況如何,如果沒有網絡,則不必重試;
  • 2) 重試設定必要的時間間隔,因為移動接入網絡抖動到恢復可能需要一點時間,馬上重試并非最佳策略,反而可能無謂的消耗電量。實踐中,可以在一次連接或IO失敗(立即失敗或超時)時,過3 ~ 5秒后再試;
  • 3)  重試應設定必要的總時限,因為三個服務器列表比較長,每個服務器地址都要重試和等待若干次,最終可能導致接入調度FSM和服務器列表調度FSM流轉耗時過長,此時用戶側體驗表現為長時間等待無響應。總時限參數可以參考前述區分網絡類型的超時管理中的任務超時值。一旦某次重試成功,重試總時限計時器要歸零;
  • 4) 服務器下發特定錯誤碼(比如服務器故障、過載或高負載)時,提示客戶端停止重試并告知安撫用戶,我們在強監控這個主題下有詳細的討論。

每個目標服務器地址的重試次數、重試總時限和重試時間間隔最好能做到云端可配可控。

特別需要提出的一點是,移動APP采用HTTP短鏈接模式實現CS交互時,廣泛的使用了系統原生組件或者開源組件,這些友好的模塊把超時和重試都封裝起來,其缺省值是否適合自己的業務特點,需要多多關注。使用前,最好能知其然更知其所以然。

⑦ 及時反饋

透明和尊重,會帶來信任和默契,家庭如此、團隊如此、用戶亦如此。欲蓋彌彰和裝傻充愣也許短暫取巧,拉長時間軸來看,肯定要付出慘重的代價。及時和真誠的告知狀況,贏得諒解和信任,小付出,大回報,試過都知道。

當發現因為網絡不存在或者其它屬于移動端設備鏈路的異常時,應該及時和顯著的提示用戶,讓用戶注意到當前有諸如網絡不存在、FREE WIFI接入認證頁面需確認等等問題,使用戶可以及時處理或理解問題狀態。

當發現是服務器問題時,應及時、顯著和真誠的告知用戶,爭取用戶的諒解。

網絡異常提示或服務器故障通告等信息的呈現要做到一目了然,無二義和二次交互。

4.4IO管理


基于一個快速和高效管理的鏈路之上,做好IO調度和控制,也是提升效能和改善用戶體驗的重要環節。

要探討的內容包括:

① 異步IO

異步化IO的目的就是避免資源的集中競爭,導致關鍵任務響應緩慢。我們在后面差異服務個大的分類中會重點探討。這里特別先提出來,是建議在程序架構頂層設計時,要在整體機制上支持異步化,設計必要的異步總線來聯系各個層級模塊,總線可能會涉及包括隊列管理(優先級、超時、CRUD等)、事件驅動、任務調度等。

異步IO除了網絡方面外,對移動設備,我們還特別要考慮一下磁盤IO的異步。因為頻繁、大吞吐量的磁盤IO會造成APP的UI卡頓,從用戶體驗上看就是交互響應遲鈍或者滑動幀率下降。一般來說,磁盤IO異步會選用空間換時間的方案,即緩存數據批量定時寫入磁盤。

② 并發控制

有了異步IO,并發控制就顯得尤為重要。把異步機制當作銀彈任意使用,就如同我們給移動APP設計了一個叫“發現”的地方一樣,很可能各種膨脹的需求、不知道如何歸類的需求就紛至沓來,期待有朝一日被“發現”。

異步IO提供了一個很好的發射后不用管的機制,這就會造成使用者的膨脹,無論是否必要、無論輕重緩急,把請求一股腦的丟給異步隊列,自己瀟灑的轉身就走。這樣不但會帶來效率和交互響應性能的下降,也會造成資源的無謂消耗。

在后面多異步這個大分類的討論中會涉及到輕重緩急的話題,在前述異步IO的磁盤IO的時空效率轉換話題中,還應該包括IO并發的控制,我們即不能因為并發過多的鏈路造成網絡帶寬的獨占消耗影響其它APP的使用,也不可因快速、大量的異步數據造成緩寫機制形同虛設或是占用過大的內存資源。

③ 推拉結合

PUSH機制應該是蘋果公司在移動設備上取得輝煌成就的最重要兩個機制之一,另外一個是移動支付體系。我們這里的討論不包括iOS和APPLE移動設備的擬人化交互體驗,只側重根基性的機制能力。APNS解決了信息找人的問題,在過去,只有運營商的短信有這個能力,推送和拉取使得我們具備了實時獲取重要信息的能力。

為何要推拉結合。因為系統級的推送體系也必須維持一個自己的鏈路,而這個鏈路上要承載五花八門的APP推送數據,如果太重,一方面會在設計上陷入個性化需求的繁瑣細節中,另外一方面也會造成這條鏈路的擁堵和性能延遲。因此,通過PUSH通知APP,再由APP通過自己的鏈路去PULL數據,即有效的利用了PUSH機制,又能使得APP能按需使用網絡,不但簡化了鏈路管理,而且節省了電量和流量。

④ 斷點續傳

一方面,在討論鏈路管理時,我們建議了優質網絡下的并發鏈路來完成同一個重數據拉取任務。這就會涉及到任務的拆分和并行執行,基礎是后臺能支持斷點續傳。

另外一方面,從客戶端的角度而言,移動網絡的不穩定特點,可能會造成某個重數據拉取任務突然失敗,無論是自動重試還是用戶驅動的重試,如果能從上次失效的上下文繼續任務,會有省時間、省電量和省流量的效果,想想也會覺得十分美好。

5、優化方法二:“輕往復”


“技”止此爾。強調網絡交互的“少”,更應強調網絡交互的“簡”。

我們在一條高時延易抖動的通道上取得效率優勢的關鍵因素就是減少在其上的往復交互,最好是老死不相往來(過激),并且這些往復中交換的數據要盡量的簡潔、輕巧,輕車簡從。這個概念是不是有點像多干多錯,少干少錯,不干沒錯。

把我們實踐過的主要手段提出來探討:

① 協議二進制化

二進制比較緊湊,但是可讀性差,也因此形成可維護性和可擴展性差、調測不便的不良印象。這也造成了大量可見字符集協議的出現。計算機是0和1的世界,她們是程序猿的水和電,任何一個整不明白,就沒法愉快的生活了。

② 高效協議

高效的協議可以從兩個層面去理解,一是應用層標準協議框架,二是基于其上封裝的業務層協議框架,有時候也可以根據需要直接在TCP之上把這兩個層面合并,形成純粹的業務層私有協議框架。不過,為了簡化網絡模塊的通訊機制和一些通用性、兼容性考慮,目前大多數情況下,我們都會選擇基于HTTP這個應用層標準協議框架之上承載業務層協議框架。下面我們針對上述兩個層面展開探討。

首先是應用層的標準協議優化:比如HTTP/1.1的Pipeline、WebSocket(在HTML5中增加)、SPDY(由Google提出)、HTTP/2等,其中特別需要關注的是處在試驗階段的SPDY和草案階段的HTTP/2。

SPDY是Google為了規避HTTP/1.1暨以前版本的局限性開展的試驗性研究,主要包括以下四點:

  • 1) 鏈路復用能力:HTTP協議最早設計時,選擇了一問一答一連接的簡單模式,這樣對于有很多并發請求資源或連續交互的場景,鏈路建立的數量和時間成本就都增加了;
  • 2) 異步并發請求的能力:HTTP協議最早的設計中,在拉取多個資源時,會對應并發多個HTTP鏈路(HTTP/1.1的Pipeline類似)時,服務端無法區分客戶端請求的優先級,會按照先入先出(FIFO)的模式對外提供服務,這樣可能會阻塞客戶端一些重要優先資源的加載,而在鏈路復用的通道上,則提供了異步并發多個資源獲取請求指令的能力,并且可以指定資源加載的優先級,比如CSS這樣的關鍵資源可以比站點ICON之類次要資源優先加載,從而提升速度體驗;
  • 3) HTTP包頭字段壓縮:(注:特指字段的合并刪減,并非壓縮算法之意)精簡,HTTP協議中HEAD中字段多,冗余大,每次請求響應都會帶上,在不少業務場景中,傳遞的有效數據尺寸遠遠小于HEAD的尺寸,帶寬和時間成本都比較大,而且很浪費;
  • 4) 服務器端具備PUSH能力:服務器可以主動向客戶端發起通信向客戶端推送數據。

HTTP/2由標準化組織來制定,是基于SPDY的試驗成果開展的HTTP協議升級標準化工作,有興趣了解詳細情況可以參考HTTP/2的DRAFT文檔。

其次是業務層的協議框架優化:它可以從三個方面考察

  • 一是協議處理性能和穩定性好,包括諸如協議緊湊占用空間小,編碼和解碼時內存占用少CPU消耗小計算快等等,并且bad casae非常少;
  • 二是可擴展性好,向下兼容自不必說,向上兼容也并非不能;
  • 三是可維護性強,在協議定義、接口定義上,做到可讀性強,把二進制協議以可讀字符的形式展示,再通過預處理轉化為源碼級文件參與工程編譯。

可能會有同學強調協議調測時的可閱讀、可理解,既然讀懂01世界應該是程序員的基本修養,這一項可能就沒那么重要了。

高效的業務層協議框架從分布式系統早期代表Corba的年代就有很多不錯的實踐項目,目前最流行的開源組件應屬ProtoBuf,可以學習借鑒。

正所謂殊途同歸、心有靈犀、不謀而合,英雄所見略同......,說來說去,高效協議的優化思路也都在鏈路復用、推拉結合、協議精簡、包壓縮等等奇技淫巧的范疇之內。

有關Protobuf等技術的詳細文章,請參見:
Protobuf通信協議詳解:代碼演示、詳細原理介紹等
如何選擇即時通訊應用的數據傳輸格式
強列建議將Protobuf作為你的即時通訊應用數據傳輸格式
全方位評測:Protobuf性能到底有沒有比JSON快5倍?
移動端IM開發需要面對的技術問題(含通信協議選擇)
簡述移動端IM開發的那些坑:架構設計、通信協議和客戶端
理論聯系實際:一套典型的IM通信協議設計詳解
58到家實時消息系統的協議設計等技術實踐分享
技術掃盲:新一代基于UDP的低延時網絡傳輸層協議——QUIC詳解
金蝶隨手記團隊分享:還在用JSON? Protobuf讓數據傳輸更省更快(原理篇)
金蝶隨手記團隊分享:還在用JSON? Protobuf讓數據傳輸更省更快(實戰篇)

③ 協議精簡

協議精簡的目的就是減少無謂的數據傳輸,提升網絡效能。俗話說“千里不捎針”,古人誠不我欺也。

我們實踐總結以下三點供參考:

  • 1) 能不傳的就不傳:把需要的和希望有的數據都列出來,按照對待產品需求的態 度,先砍掉一半,再精簡一半,估計就差不多了。另外,高效協議提供了比較好的擴展性,預留字段越少越好,移動互聯網演化非常快,經常會發現前瞻的預留總是趕不上實際的需求;
  • 2) 抽象公共數據:把各協議共性的屬性數據抽象出來,封裝在公共數據結構中, 即所謂包頭一次就傳一份,這個想法不新鮮,TCP/IP的設計者們早就身體力行了。除了帶來數據冗余的降低外,還降低了維護和擴展的復雜度,一石二鳥,且抽且行;
  • 3) 多用整數少用字符:數字比文字單純,即簡潔又清晰,還不需要擔心英文不好被后繼者BS;
  • 4) 采用增量技術:通知變化的數據,讓接收方處理差異,這是個很好的設計思想,實踐中需要注意數據一致性的校驗和保障機制,后面會有專門的細節討論。

④ 協議合并

協議合并的目標是通過將多條交互指令歸并在一個網絡請求中,減少鏈路創建和數據往復,提升網絡效能。

把實戰總結的六點提出來供參考:

  • 1) 協議合并結合協議精簡,效率翻番;
  • 2) 協議合并的基礎是業務模型的分析,在分類的基礎上去做聚合。首先得區分出來緩急,把實時和異步的協議分類出來分別去合并;其次得區分出來輕重,協議請求或協議響應的數據規模(指壓縮后),盡量確保在一個數據報文中可完成推拉;
  • 3) 協議合并在包的封裝上至少有兩種選擇,一是明文協議合并后統一打包(即壓縮和解密);二是明文協議分別打包,最后匯總;前者效率高一些,在實戰中用的也較普遍;后者為流式處理提供可能;
  • 4) 協議合并對服務器的異步處理架構和處理性能提出了更高的要求,特別需要權衡網絡交互效率和用戶對后臺處理返回響應期待之間的取舍;
  • 5) 協議間有邏輯順序關系時,要認真考慮設計是否合理或能否合并;
  • 6) 重數據協議不要合并。

⑤ 增量技術

增量技術準確分類應該算是協議精簡的一個部分,它與業務特點結合的非常緊密,值得單獨討論一下。增量技術在CS數據流交互比較大的時候有充分發揮的空間,因為這個技術會帶來客戶端和服務器計算、存儲的架構復雜度,增加資源消耗,并且帶來許多保障數據一致性的挑戰,當然,我們可以設計的更輕巧,容許一些不一致。

我們用一個案例來看看增量技術的運用。

在應用分發市場產品中,都有一個重要功能,叫更新提醒。它的實現原理很簡單,以Android設備為例,客戶端把用戶移動設備上安裝的APP包名、APP名稱、APP簽名、APP版本號等信息發送到服務器,服務器根據這些信息在APP庫中查找相應APP是否有更新并推送到客戶端。這個過程非常簡單,但如果用戶手機上裝了50個APP,網絡上交互的數據流就非常客觀了,即浪費流量和電量,又造成用戶體驗的緩慢,顯得很笨重。

這個時候,增量技術就可以派上用場了,比如下面的方案:

  • 1) 每個自然日24小時內,客戶端選擇一個時間(優先選擇駐留在后臺的時候)上報一次全量數據;
  • 2) 在該自然日24小時的其它時間,客戶端可以定時或在用戶使用時發送增量數據,包括卸載、安裝、更新升級等帶來的變化;
  • 3) 作為弱一致性的保障手段,客戶端在收到更新提示信息后,根據提醒的APP列表對移動設備上實際安裝和版本情況做一次核對;
  • 4) 上述擇機或定時的時間都可以由云端通過下發配置做到精細化控制。

⑥ 包壓縮

前面精打細算完畢,終于輪到壓縮算法上場了。選擇什么算法,中間有哪些實戰的總結,下面提出來一起探討:

  • 1) 壓縮算法的選擇:我們比較熟悉的壓縮算法deflate、gzip、bzip2、LZO、Snappy、FastLZ等等,選擇時需要綜合考慮壓縮率、內存和CPU的資源消耗、壓縮速率、解壓速率等多個緯度的指標,對于移動網絡和移動設備而言,建議考慮使用gzip。另外需要注意的是,輕數據與重數據的壓縮算法取舍有較大差異,不可一概而論;
  • 2) 壓縮和加密的先后秩序:一般而言,加密后的二進制數據流壓縮率會低一些,建議先壓縮再加密;
  • 3) 注意一些協議組件、網絡組件或數據本身是否已經做過壓縮處理,要避免重復工作,不要造成性能和效率的下降:比如一些圖片格式、視頻或APK文件都有自己的壓縮算法。

說到這,問題又來了,如果應用層標準協議框架做了壓縮,那么基于其上封裝的業務層協議框架還需要壓縮嗎,壓縮技術到底哪家強?這個問題真不好回答,考慮到HTTP/2這樣的應用層標準協議框架定稿和普及尚需時日,建議在業務層協議框架中做壓縮機制。或者追求完美,根據后端應用層標準協議框架響應是否支持壓縮及在支持時的壓縮算法如何等信息,動態安排,總的原則就是一個字:只選對的,不選貴的。

5、優化方法三:“強監控”


可監方可控,我們在端云之間,要形成良好的關鍵運營數據的采集、匯總和分析機制,更需要設計云端可控的配置和指令下發機制。

本篇重點討論與主題網絡方面相關關鍵指標的“監”和“控”

以就快接入為例來探討一下強監控能力的構建和使用:

  • 1) 接入質量監控:客戶端匯總接入調度FSM執行過程元信息以及業務請求響應結果的元信息,并由此根據網絡類型不同、運營商不同、網絡接入國家和省市不同分析接入成功率、業務請求成功率(還可細化按業務類型分類統計)、前述二者失敗的原因歸類、接入302重定向次數分布暨原因、接入和業務請求測速等;
  • 2) 建設云端可控的日志染色機制:便于快速有針對性的定點排查問題;
  • 3) 終端硬件、網絡狀態的相關參數采集匯總;
  • 4) 建設云端可控的接入調度(比如接入IP列表等)和網絡參數(比如連接超時、IO超時、任務超時、并發鏈接數、重試間隔、重試次數等)配置下發能力;
  • 5) 服務器根據匯總數據。

通過數據分析,結合服務器自身的監控機制,可以做到:

  • a. 支持細粒度的接入調度和網絡參數的優化云控;
  • b. 支持服務器的部署策略優化;
  • c. 發現移動運營商存在的一些差異化問題比如URL劫持、網絡設備超時配置不當等問題便于推動解決;
  • d. 發現分省市服務器服務質量的異常情況,可以動態云端調度用戶訪問或者降級服務,嚴重時可以及時提示客戶端發出異常安撫通告,避免加劇服務器的負載導致雪崩。安民告示的快速呈現能力,考驗了一個團隊對可“控”理解的深度,我們在實踐中,提供了三級措施來保障:
        - 第一級是服務器端通過協議或跳轉URL下發的動態通告,這在非IDC公網故障且業務接入服務器正常可用時適用;
        - 第二級是預埋靜態URL(可以是域名或IP形式,優先IP)拉取動態通告,適用其它故障,靜態URL部署的IP地址最好同本業務系統隔離,避免因為業務服務所在IDC公網故障不可用時無法訪問;
        - 第三級是客戶端本地預埋的靜態通告文案,內容會比較模糊和陳舊,僅作不時之需;
  • e. 支持異步任務的云端可配可控,比如下載類APP的下載時間、下載標的和下載條件約束(磁盤空間、移動設備電量、網絡類型等)的差異化配置,通過錯峰調度,達到削峰平谷并提升用戶體驗的效果。

特別需要注意的是,客戶端數據報告一定要有數據篩選控制和信息過濾機制,涉及用戶隱私的敏感信息和使用記錄必須杜絕采樣上報。在我們的日志染色機制中要特別注意,為了排查問題極可能把關鍵、敏感信息記錄報告到后端,引入安全風險。

6、優化方法四:“多異步”


經過前面不懈的努力,初步打造了一個比較好的技術根基,好馬配好鞍,好車配風帆,怎么就把領先優勢拱手送與特斯拉了。

用戶欲壑難平,資源供不應求,靠“術”并無法優雅的解決。跳出來從產品角度去觀察,還有些什么能夠觸動我們思考的深度呢。根據不同的需求和使用場景,用有損服務的價值觀去權衡取舍,用完美的精神追求不完美,此乃道的層面。

所謂大道至簡,完美之道,不在無可添加,而在無可刪減。通過多異步和各類緩存機制,提供區分網絡、區分業務場景下的差異化服務,是我們孜孜以求的大“道”。

下面通過一些實踐案例的總結,來探索簡潔優雅的弱聯網體驗改善之道(開始肆無忌憚的吹噓了)。

① 網絡交互可否延后

微博客戶端某個版本啟動時,從閃屏加載到timeline界面需要6秒+。這樣的體驗是無法接受的,與用戶2秒以內的等待容忍度是背道而馳的。從技術角度去分析,很容易發現問題,諸如我們在啟動時有10+個并發的網絡請求(因為是HTTP短鏈接,意味著10+個并發的網絡鏈接)、閃屏加載、主UI創建、本地配置加載、本地持久化數據加載至Cache等等程序行為,優化的目標很自然就集中在網絡請求和本地配置、持久化數據加載上。

梳理并發網絡請求,可以從以下三個方面考察:

  • 1) 哪些請求是要求實時拉取的,比如timeline & 提及 & 私信的數字、身份校驗;
  • 2) 哪些請求是可以異步拉取的,比如timeline、用戶Profile、云端配置、雙向收聽列表、閃屏配置、timeline分組列表、相冊tag列表等;
  • 3) 哪些請求是可以精簡或合并的,比如timeline & 提及 & 私信的數字與身份校驗合并。

此時,取舍就非常簡單和清晰了,啟動時1~2個網絡請求足夠應對。所做的僅僅是把一些請求延后發起,這是一種異步機制。

在移動APP里面還有大量類似的場景,比如用戶更新了APP的某個設置項或者自己Profile的某個字段,是停在界面上轉菊花等網絡交互返回后再提示結果,亦或是把界面交互馬上還給用戶,延后異步向服務器提交用戶請求,這里面的價值取向不同,“快”感也便不同。

② 網絡內容可否預先加載

微博客戶端在timeline刷新時,用戶向上快速滑屏,到達一個邏輯分頁(比如30條微博消息)時,有兩個取舍,一是提前預加載下個分頁內容并自動拼接,給用戶無縫滑動的體驗;二是等到用戶滑動到達分頁臨界點時現場轉菊花,卡不卡看當時的網絡狀況。實踐中選擇了方案一。用戶在滑動瀏覽第一個邏輯分頁時,APP就利用這個時間窗主動預先拉取下一個邏輯分頁的內容,使得用戶能享受一個順暢的“刷”的體驗。

所做的僅僅是把一個請求提前發起了,這也是一種異步機制。思考的要點是:

  • 1) 預先加載的內容是用戶預期的嗎,預先加載和自動下載之間,失之毫厘謬以千里;
  • 2) 預先加載的內容對用戶移動設備的資源(比如流量、電量等)和后端服務器的資源(比如帶寬、存儲、CPU等)消耗要做好估算和判斷,體貼和惡意之間,也就一步之遙;
  • 3) 預先加載區分輕重數據,輕數據可以不區分網絡狀況,重數據考慮僅限優質網絡下執行,最好這些策略云端可以控制;
  • 4) 預先通過網絡拉取加載或存儲的過程中,不要打攪用戶的正常使用。

在移動APP中,預加載有大量的實踐,比較典型的就是升級提醒,大家都采用了先下載好升級包,再提示用戶有新版本的策略,讓你順暢到底。

③ 用戶體驗可否降級

微博客戶端在香港公共WIFI下刷新timeline總是失敗,通過后臺用戶接入請求和響應日志分析,判斷是香港IDC到香港公共WIFI的匯接口帶寬窄、時延大,此時該如何應對。

從前面探討的TCP/IP網絡知識,可以知道,在一個窄帶寬高時延網絡中,吞吐量BDP必然很小,也就是說單位大小的數據傳輸所需的時間會很長。如果按照通常一次下發一個邏輯分頁timeline數據的策略,那么從服務器到客戶端傳輸,整個數據需要拆分成多個TCP數據報文,在緩慢的傳輸過程中,可能一個數據報文還未傳輸完成,客戶端的鏈路就已經超時了。

如果在弱網絡(需要在應用層有測速機制,類似TCP/IP的RTT機制,測速時機可以是拉取微博消息數字時)下,把邏輯分頁的微博消息數由30調整為5會如何,如果方案成立,用戶刷微博的體驗是不是會下降,因為滑動一屏就要做一次網絡交互,即便是配合預加載,也可能因為網絡太慢,操控太快而又見菊花。外團在香港實測了這個版本,感嘆,終于可以刷了。

在饑渴難耐和美酒佳肴之間,似乎還有很多不同層級的體驗。聊勝于無,這個詞很精準的表述了服務分層,降級取舍的重要性。思考的要點是:

  • 1) 產品的核心體驗是什么,即用戶最在乎的是什么,在做宏觀分層設計時要充分保障核心體驗;
  • 2) 每個產品交互界面中,什么數據是無法容忍短時間不一致的,即什么是用戶不能容忍的錯誤,在做微觀分層設計時要充分考慮正確性;
  • 3) 在宏觀和微觀分層的基礎上,開始設想在什么條件下,可以有什么樣的降級取舍,來保障可用,保障爽快的體驗;
  • 4) 分層不宜太多太細,大部分產品和場景,3層足矣。

在移動弱網絡條件下,處處可見降級取舍的案例。比如網絡條件不佳時,降低拉取縮略圖的規格,甚至干脆不自動拉取縮略圖等等,分層由心,降級有意。

④ 端和云孰輕孰重

移動APP時代,絕對的輕端重云或者輕云重端都是不可取的,只有端云有機的配合,才能在一個受限的網絡通道上做出更好的用戶體驗。正所謂東家之子,胖瘦有致。

比如移動網游APP,如取向選擇輕端重云,那么玩家的戰斗計算就會大量的通過網絡遞交給服務器處理并返回,卡頓家常便飯,操控感盡失。

比如微博客戶端,如果取向選擇重端輕云,微博timeline所有的消息都拉取元數據(比如微博正文包括文字、各類URL、話題、標簽、@、消息的父子關系、消息中用戶profile、關系鏈等等),由客戶端實時計算拼裝,不但客戶端用戶需要消耗大量流量計算量,而且給后端服務器帶來巨大的帶寬成本和計算壓力,如果過程中網絡狀況不佳,還會非常卡頓。

通過實踐總結,端和云孰輕孰重,取舍的關鍵是在數據計算規模可控和數據安全有保障的前提下:

  • 1) 減少網絡往復,要快;
  • 2) 減少網絡流量,要輕。

端云有機結合,可以很好的演繹機制與策略分離的設計思想,從而使系統具備足夠的柔韌性。

不得不再次特別提到的一點是,緩存技術是異步化的基礎,它滲透在性能和體驗提升的方方面面,從持久化的DB、文件,到短周期的內存數據結構,從業務邏輯數據,到TCP/IP協議棧,它無所不在。緩存涉及到數據結構組織和算法效能(耗時、命中率、內存使用率等)、持久化和啟動加載、更新、淘汰、清理方案等,有機會我們可以展開做專題的介紹。牢記一個字,緩存是讓用戶爽到極致的利器,但千萬別留下垃圾。

提倡多異步,實際上是要求團隊認真審視產品的核心能力是什么,深入思考和發現什么是用戶最關心的核心體驗,把有限的資源聚焦在它們身上。通過考察用戶使用產品時的心理模型,體驗和還原用戶使用場景,用追求完美的精神探索不完美之道。

互聯網服務核心價值觀之一“不要我等”,在移動互聯網時代仍應奉為圭臬,如何面對新的挑戰,需要更多的學習、思考、實踐和總結,這篇文章即是對過去實踐的總結,亦作為面對未來挑戰的思考基點。

老子曰過:上士聞道,勤而行之;中士聞道,若存若亡;下士聞道,大笑之。不笑不足以為道。求求你了,笑一個。

知易行難,故知行合一似(jiu)為扯蛋,那么我們就且扯且珍惜吧。

(上篇看了嗎?沒看請戳這里:《移動端IM開發者必讀(一):通俗易懂,理解移動網絡的“弱”和“慢”》)

附錄:更多計算機網絡方面的資料


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高性能網絡應用的理論探索
不為人知的網絡編程(一):淺析TCP協議中的疑難雜癥(上篇)
不為人知的網絡編程(二):淺析TCP協議中的疑難雜癥(下篇)
不為人知的網絡編程(三):關閉TCP連接時為什么會TIME_WAIT、CLOSE_WAIT
不為人知的網絡編程(四):深入研究分析TCP的異常關閉
不為人知的網絡編程(五):UDP的連接性和負載均衡
不為人知的網絡編程(六):深入地理解UDP協議并用好它
不為人知的網絡編程(七):如何讓不可靠的UDP變的可靠?
網絡編程懶人入門(一):快速理解網絡通信協議(上篇)
網絡編程懶人入門(二):快速理解網絡通信協議(下篇)
網絡編程懶人入門(三):快速理解TCP協議一篇就夠
網絡編程懶人入門(四):快速理解TCP和UDP的差異
網絡編程懶人入門(五):快速理解為什么說UDP有時比TCP更有優勢
技術掃盲:新一代基于UDP的低延時網絡傳輸層協議——QUIC詳解
讓互聯網更快:新一代QUIC協議在騰訊的技術實踐分享
現代移動端網絡短連接的優化手段總結:請求速度、弱網適應、安全保障
聊聊iOS中網絡編程長連接的那些事
移動端IM開發者必讀(一):通俗易懂,理解移動網絡的“弱”和“慢”
移動端IM開發者必讀(二):史上最全移動弱網絡優化方法總結
>> 更多同類文章 ……

即時通訊網 - 即時通訊開發者社區! 來源: - 即時通訊開發者社區!

上一篇:移動端IM開發者必讀(一):通俗易懂,理解移動網絡的“弱”和“慢”下一篇:請教關于WebSocket客戶端向服務端傳值的問題

本帖已收錄至以下技術專輯

推薦方案
評論 6
總結的這么全,看我的顫抖啊
簽名: 立秋了,離涼爽的天氣應該不遠了吧
這文章不服不行,滿滿的干貨
簽名: 周末了,可以浪了
學習了
太高深了啊
醍醐灌頂,牛叉
相當全面。
打賞樓主 ×
使用微信打賞! 使用支付寶打賞!

返回頂部
股票配资平台都找股牛网