本文接上篇《移動端IM開發者必讀(一):通俗易懂,理解移動網絡的「弱」和「慢」》,關於移動網絡的主要特性,在上篇中已進行過詳細地闡述,本文將針對上篇中提到的特性,結合咱們的實踐經驗,總結了四個方法來追求極致的「爽快」:快鏈路、輕往復、強監控、多異步,從理論講到實踐、從技術講到產品,理論聯繫實際,觸類旁通,但願給您帶來啓發。
若是您還未閱讀完上篇《移動端IM開發者必讀(一):通俗易懂,理解移動網絡的「弱」和「慢」》,建議您先行讀完後再續本文。
本篇的目的,就是但願以通俗易懂的語言,幫助移動端IM開發者更好地針對性優化移動網絡的各類特性,使得開發出的功能給用戶帶來更好的使用體驗。
本文乃全網同類文章中,惟一內容最全、「糞」量最重者,請作好心理準備耐心讀下去,不要辜負做者已打上石膏的雙手和用廢的鍵盤。
另外,《現代移動端網絡短鏈接的優化手段總結:請求速度、弱網適應、安全保障》這篇文章也提到了本文所闡述的相關內容,強烈建議閱讀。php
學習交流:html
- 即時通信開發交流3羣:185926912[推薦]前端
- 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM》程序員
(本文同步發佈於:http://www.52im.net/thread-1588-1-1.html)算法
▼ 本文是《移動端IM開發者必讀》系列文章的第2篇:
編程
若是您是IM開發初學者,強烈建議首先閱讀《新手入門一篇就夠:從零開發移動端IM》。後端
1)關於網絡通訊的基礎文章:
緩存
2)涉及移動端網絡特性的文章:
安全
咱們須要有一條(相對)快速、(相對)順暢、(相對)穩定的網絡通道承載業務數據的傳輸,這條路的最好是傳輸快、不擁堵、帶寬大、收費少。生活中作個類比,咱們計劃驅車從深圳到廣州,若是想固然走廣深高速十之八九要杯具,首先這個高速略顯破敗更像省道,路況不佳不敢提速;其次這條路上的車時常如過江之鯽,若是身材很差操控不便,根本就快不起來;最後雙向六車道雖然勉強能夠接受,但收費竟然比廣深沿江高速雙向八車道還貴;正確的選路方案目前看是走沿江高速,雖然可能要多跑一段里程,可是通行更暢快。
實際上,真實狀況要更復雜,就如同上篇中【圖二 有線互聯網和移動互聯網網絡質量差別】所示(就是下圖),漫漫征途中經常會在高速、國道、省道、田間小道上切換。
<ignore_js_op>
服務器
純技術活,直接上建議得了,每一個子項爭取能大體有個背景交待,若是沒說清楚,能夠先看看如下資料:
《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位窗口大小(見下圖),還有咱們前面提到的流量控制機制和滑動窗口的概念,大幕徐徐拉開,主角紛紛粉墨登場。在正式詳細介紹以前,按照傳統,咱們仍是先站在豬場老闆的角度看一下,讀緩衝區就比如買家用來囤貨的臨時豬圈,若是貨到了買家使用部門來不及處理,就先在這裏臨時囤着,寫緩衝區就比如養豬場根據訂單裝好車準備發貨,若是買家說我如今能夠收貨即可速度發出,有點明白了吧。
<ignore_js_op>
④ 調大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時表示啓用該選項:
以上參數中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了。
① 就快接入
在客戶端接入服務器調度策略的演化過程當中,咱們最先採用了「就近接入」的策略,在距離客戶端更近的地方部署服務器或使用CDN,指望經過減小RTT來提升網絡交互響應性能。這個策略在國內的落地執行還須要加一個前綴:「分省分運營商」,這就給廣大負責IDC建設的同窗帶來了巨大的精神和肉體折磨。
在持續運營的過程當中,根據觀察到的數據,發現並不是物理距離最近的就是最快的。回憶一下前面談到的吞吐量指標BDP,它與鏈路帶寬和RTT成正比關係,而RTT是受物理距離、網絡擁塞程度、IDC吞吐量、跨網時延等諸多因素綜合影響的,單純的就近顯然不夠精細了。
「就快接入」在「就近接入」策略的基礎上改善提高,它利用客戶端測速和報告機制,經過後臺大數據分析,造成與客戶端接入IP按就快原則匹配接入服務器的經驗調度策略庫,令客戶端總能優先選擇到最快的服務器接入點。
有關就快接入的更詳細方案,請參見:《海量之道系列文章之弱聯網優化(五)》一文的「3.1.2節」。
② 去DNS的IP直連
DNS不但須要1個RTT的時間消耗,並且移動網絡下的DNS還存在不少其它問題:
綜上就是在前述就快接入小節中,接入調度FSM會優先使用動態服務器列表的緣由。
③ 網絡可達性探測
在鏈接創建過程當中若是出現鏈接失敗的現象,而終端系統提供的網絡狀態接口反饋網絡可用時,咱們須要作網絡可達性探測(即向預埋的URL或者IP地址發起鏈接嘗試),以區別網絡異常和接入服務異常的狀況,爲定位問題,優化後臺接入調度作數據支持。
探測數據能夠異步報告到服務器,至少應該包含如下字段:
鏈路就是運肥豬的高速路,就快接入是選路,鏈路管理就是如何高效的使用這條路。下面是一些實踐總結:
① 鏈路複用
咱們在開篇討論無線網絡爲何慢的時候,提到了連接創建時三次握手的成本,在無線網絡高時延、頻抖動、窄帶寬的環境下,用戶使用趨於碎片化、高頻度,且請求響應又一次性往返居多、較頻繁發起等特徵,建鏈成本顯得尤爲顯著。
所以,咱們建議在鏈路建立後能夠保持一段時間,好比HTTP短連接能夠經過HTTP Keep-Alive,私有協議能夠經過心跳等方式來保持鏈路。
具體要點建議以下:
② 區分網絡類型的超時管理
在不一樣的網絡類型時,咱們的鏈路超時管理要作精細化的區別對待。鏈路管理中共有三類超時,分別是鏈接超時、IO超時和任務超時。
咱們有一些經驗建議,提出來共同探討:
超時時間宜短不宜長,在一個合理的時間內令當前鏈路因超時失效,從而驅動調度FSM狀態的快速變遷,效率要比癡癡的等待高得多,同時,在用戶側也能獲得一個較好的正反饋。
各種超時參數最好能作到雲端可配可控。
③ 優質網絡下的併發鏈路
當咱們在4G、WIFI(要區分是WIFI路由器仍是手機熱點)等網絡條件較優時,對於請求隊列積壓任務較多或者有重數據(富媒體等下載類數據)請求時,能夠考慮併發多個鏈路並行執行。
對於單一重數據任務的多連接併發協同而言,須要服務器支持斷點續傳,客戶端支持任務協同調度;
④ 輕重鏈路分離
輕重鏈路分離,也能夠說是信令和數據分離,目的是隔離網絡通信的過程,避免重數據通信延遲而阻塞了輕數據的交互。在用戶角度看來就是信息在異步加載,控制指令響應反饋及時。
移動端大部分都是HTTP短連接模式工做,輕重數據的目標URL自己就不一樣,比較自然的能夠達到分離的要求,可是仍是要特別作出強調,是由於實踐中有些輕數據協議設計裏面還會攜帶相似頭像、驗證碼等的實體數據。
⑤ 長連接
長連接對於提高應用網絡交互的及時性大有裨益,一方面用戶使用時,節省了三次握手的時間等待,響應快捷;另外一方面服務器具有了實時推送能力,不但能夠及時提示用戶重要信息,並且能經過推拉結合的異步方案,更好的提高用戶體驗。
長連接的維護包括連接管理、連接超時管理、任務隊列管理等部分,設計實施複雜度相對高一些,尤爲是在移動網絡環境下。爲了保持鏈路還須要作心跳機制(從另一個角度看,這也是針對簡單信息一個不錯的PULL/PUSH時機,,但需注意數據傳輸要夠輕,好比控制在0.5KB之內),而心跳機制是引入長連接方案複雜度的一個重要方面,移動網絡鏈路環境複雜,國內網關五花八門,鏈路超時配置各有千秋,心跳時長選擇學問比較大,不但要區分網絡類型,還得區分不一樣運營商甚至不一樣省市,歷史上曾經實踐了2分鐘的心跳間隔,最近比較多的產品實踐選擇4.5分鐘的心跳間隔。並且長連接除了給移動網絡尤爲是空中信道帶來負擔外,移動設備自身的電量和流量也會有較大的消耗,同時還帶來後端帶寬和服務器投入增長。
因此,除了一些粘性和活躍度很高、對信息到達實時性要求很高的通信類APP外,建議謹慎使用長連接,或能夠考慮採用下面的方式:
有關Android的推送問題,能夠參考:
《應用保活終極總結(三):Android6.0及以上的保活實踐(被殺復活篇)》
《Android進程保活詳解:一篇文章解決你的全部疑問》
《Android端消息推送總結:實現原理、心跳保活、遇到的問題等》
《深刻的聊聊Android消息推送這件小事》
《爲什麼基於TCP協議的移動端IM仍然須要心跳保活機制?》
《微信團隊原創分享:Android版微信後臺保活實戰分享(網絡保活篇)》
《移動端IM實踐:實現Android版微信的智能心跳機制》
《移動端IM實踐:WhatsApp、Line、微信的心跳策略分析》)
⑥ 當心重試
自動重試是致使後臺雪崩的重要因素之一。在移動網絡不穩定的條件下,大量及時的重試不但不能達到預期,反而無謂的消耗移動設備的電量甚至流量。
所以,咱們在重試前要有一些差別化的考慮:
每一個目標服務器地址的重試次數、重試總時限和重試時間間隔最好能作到雲端可配可控。
特別須要提出的一點是,移動APP採用HTTP短連接模式實現CS交互時,普遍的使用了系統原生組件或者開源組件,這些友好的模塊把超時和重試都封裝起來,其缺省值是否適合本身的業務特色,須要多多關注。使用前,最好能知其然更知其因此然。
⑦ 及時反饋
透明和尊重,會帶來信任和默契,家庭如此、團隊如此、用戶亦如此。此地無銀三百兩和裝傻充愣也許短暫取巧,拉長時間軸來看,確定要付出慘重的代價。及時和真誠的告知情況,贏得諒解和信任,小付出,大回報,試過都知道。
當發現由於網絡不存在或者其它屬於移動端設備鏈路的異常時,應該及時和顯著的提示用戶,讓用戶注意到當前有諸如網絡不存在、FREE WIFI接入認證頁面需確認等等問題,使用戶能夠及時處理或理解問題狀態。
當發現是服務器問題時,應及時、顯著和真誠的告知用戶,爭取用戶的諒解。
網絡異常提示或服務器故障通告等信息的呈現要作到一目瞭然,無二義和二次交互。
基於一個快速和高效管理的鏈路之上,作好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能按需使用網絡,不但簡化了鏈路管理,並且節省了電量和流量。
④ 斷點續傳
一方面,在討論鏈路管理時,咱們建議了優質網絡下的併發鏈路來完成同一個重數據拉取任務。這就會涉及到任務的拆分和並行執行,基礎是後臺能支持斷點續傳。
另一方面,從客戶端的角度而言,移動網絡的不穩定特色,可能會形成某個重數據拉取任務忽然失敗,不管是自動重試仍是用戶驅動的重試,若是能從上次失效的上下文繼續任務,會有省時間、省電量和省流量的效果,想一想也會以爲十分美好。
「技」止此爾。強調網絡交互的「少」,更應強調網絡交互的「簡」。
咱們在一條高時延易抖動的通道上取得效率優點的關鍵因素就是減小在其上的往復交互,最好是老死不相往來(過激),而且這些往復中交換的數據要儘可能的簡潔、輕巧,輕車簡從。這個概念是否是有點像多幹多錯,少幹少錯,不幹沒錯。
把咱們實踐過的主要手段提出來探討:
① 協議二進制化
二進制比較緊湊,可是可讀性差,也所以造成可維護性和可擴展性差、調測不便的不良印象。這也形成了大量可見字符集協議的出現。計算機是0和1的世界,她們是程序猿的水和電,任何一個整不明白,就無法愉快的生活了。
② 高效協議
高效的協議能夠從兩個層面去理解,一是應用層標準協議框架,二是基於其上封裝的業務層協議框架,有時候也能夠根據須要直接在TCP之上把這兩個層面合併,造成純粹的業務層私有協議框架。不過,爲了簡化網絡模塊的通信機制和一些通用性、兼容性考慮,目前大多數狀況下,咱們都會選擇基於HTTP這個應用層標準協議框架之上承載業務層協議框架。下面咱們針對上述兩個層面展開探討。
首先是應用層的標準協議優化:好比HTTP/1.1的Pipeline、WebSocket(在HTML5中增長)、SPDY(由Google提出)、HTTP/2等,其中特別須要關注的是處在試驗階段的SPDY和草案階段的HTTP/2。
SPDY是Google爲了規避HTTP/1.1暨之前版本的侷限性開展的試驗性研究,主要包括如下四點:
HTTP/2由標準化組織來制定,是基於SPDY的試驗成果開展的HTTP協議升級標準化工做,有興趣瞭解詳細狀況能夠參考HTTP/2的DRAFT文檔。
其次是業務層的協議框架優化:它能夠從三個方面考察
可能會有同窗強調協議調測時的可閱讀、可理解,既然讀懂01世界應該是程序員的基本修養,這一項可能就沒那麼重要了。
高效的業務層協議框架從分佈式系統早期表明Corba的年代就有不少不錯的實踐項目,目前最流行的開源組件應屬ProtoBuf,能夠學習借鑑。
正所謂異曲同工、心有靈犀、不謀而合,英雄所見略同......,說來講去,高效協議的優化思路也都在鏈路複用、推拉結合、協議精簡、包壓縮等等奇技淫巧的範疇以內。
有關Protobuf等技術的詳細文章,請參見:
《Protobuf通訊協議詳解:代碼演示、詳細原理介紹等》
《如何選擇即時通信應用的數據傳輸格式》
《強列建議將Protobuf做爲你的即時通信應用數據傳輸格式》
《全方位評測:Protobuf性能到底有沒有比JSON快5倍?》
《移動端IM開發須要面對的技術問題(含通訊協議選擇)》
《簡述移動端IM開發的那些坑:架構設計、通訊協議和客戶端》
《理論聯繫實際:一套典型的IM通訊協議設計詳解》
《58到家實時消息系統的協議設計等技術實踐分享》
《技術掃盲:新一代基於UDP的低延時網絡傳輸層協議——QUIC詳解》
《金蝶隨手記團隊分享:還在用JSON? Protobuf讓數據傳輸更省更快(原理篇)》
《金蝶隨手記團隊分享:還在用JSON? Protobuf讓數據傳輸更省更快(實戰篇)》
③ 協議精簡
協議精簡的目的就是減小無謂的數據傳輸,提高網絡效能。俗話說「千里不捎針」,古人誠不我欺也。
咱們實踐總結如下三點供參考:
④ 協議合併
協議合併的目標是經過將多條交互指令歸併在一個網絡請求中,減小鏈路建立和數據往復,提高網絡效能。
把實戰總結的六點提出來供參考:
⑤ 增量技術
增量技術準確分類應該算是協議精簡的一個部分,它與業務特色結合的很是緊密,值得單獨討論一下。增量技術在CS數據流交互比較大的時候有充分發揮的空間,由於這個技術會帶來客戶端和服務器計算、存儲的架構複雜度,增長資源消耗,而且帶來許多保障數據一致性的挑戰,固然,咱們能夠設計的更輕巧,允許一些不一致。
咱們用一個案例來看看增量技術的運用。
在應用分發市場產品中,都有一個重要功能,叫更新提醒。它的實現原理很簡單,以Android設備爲例,客戶端把用戶移動設備上安裝的APP包名、APP名稱、APP簽名、APP版本號等信息發送到服務器,服務器根據這些信息在APP庫中查找相應APP是否有更新並推送到客戶端。這個過程很是簡單,但若是用戶手機上裝了50個APP,網絡上交互的數據流就很是客觀了,即浪費流量和電量,又形成用戶體驗的緩慢,顯得很笨重。
這個時候,增量技術就能夠派上用場了,好比下面的方案:
⑥ 包壓縮
前面精打細算完畢,終於輪到壓縮算法上場了。選擇什麼算法,中間有哪些實戰的總結,下面提出來一塊兒探討:
說到這,問題又來了,若是應用層標準協議框架作了壓縮,那麼基於其上封裝的業務層協議框架還須要壓縮嗎,壓縮技術到底哪家強?這個問題真很差回答,考慮到HTTP/2這樣的應用層標準協議框架定稿和普及尚需時日,建議在業務層協議框架中作壓縮機制。或者追求完美,根據後端應用層標準協議框架響應是否支持壓縮及在支持時的壓縮算法如何等信息,動態安排,總的原則就是一個字:只選對的,不選貴的。
可監方可控,咱們在端雲之間,要造成良好的關鍵運營數據的採集、彙總和分析機制,更須要設計雲端可控的配置和指令下發機制。
本篇重點討論與主題網絡方面相關關鍵指標的「監」和「控」。
以就快接入爲例來探討一下強監控能力的構建和使用:
經過數據分析,結合服務器自身的監控機制,能夠作到:
特別須要注意的是,客戶端數據報告必定要有數據篩選控制和信息過濾機制,涉及用戶隱私的敏感信息和使用記錄必須杜絕採樣上報。在咱們的日誌染色機制中要特別注意,爲了排查問題很可能把關鍵、敏感信息記錄報告到後端,引入安全風險。
通過前面不懈的努力,初步打造了一個比較好的技術根基,好馬配好鞍,好車配風帆,怎麼就把領先優點拱手送與特斯拉了。
用戶欲壑難平,資源供不該求,靠「術」並沒有法優雅的解決。跳出來從產品角度去觀察,還有些什麼可以觸動咱們思考的深度呢。根據不一樣的需求和使用場景,用有損服務的價值觀去權衡取捨,用完美的精神追求不完美,此乃道的層面。
所謂大道至簡,完美之道,不在無可添加,而在無可刪減。經過多異步和各種緩存機制,提供區分網絡、區分業務場景下的差別化服務,是咱們孜孜以求的大「道」。
下面經過一些實踐案例的總結,來探索簡潔優雅的弱聯網體驗改善之道(開始肆無忌憚的吹噓了)。
① 網絡交互能否延後
微博客戶端某個版本啓動時,從閃屏加載到timeline界面須要6秒+。這樣的體驗是沒法接受的,與用戶2秒之內的等待容忍度是背道而馳的。從技術角度去分析,很容易發現問題,諸如咱們在啓動時有10+個併發的網絡請求(由於是HTTP短連接,意味着10+個併發的網絡連接)、閃屏加載、主UI建立、本地配置加載、本地持久化數據加載至Cache等等程序行爲,優化的目標很天然就集中在網絡請求和本地配置、持久化數據加載上。
梳理併發網絡請求,能夠從如下三個方面考察:
此時,取捨就很是簡單和清晰了,啓動時1~2個網絡請求足夠應對。所作的僅僅是把一些請求延後發起,這是一種異步機制。
在移動APP裏面還有大量相似的場景,好比用戶更新了APP的某個設置項或者本身Profile的某個字段,是停在界面上轉菊花等網絡交互返回後再提示結果,亦或是把界面交互立刻還給用戶,延後異步向服務器提交用戶請求,這裏面的價值取向不一樣,「快」感也便不一樣。
② 網絡內容能否預先加載
微博客戶端在timeline刷新時,用戶向上快速滑屏,到達一個邏輯分頁(好比30條微博消息)時,有兩個取捨,一是提早預加載下個分頁內容並自動拼接,給用戶無縫滑動的體驗;二是等到用戶滑動到達分頁臨界點時現場轉菊花,卡不卡看當時的網絡情況。實踐中選擇了方案一。用戶在滑動瀏覽第一個邏輯分頁時,APP就利用這個時間窗主動預先拉取下一個邏輯分頁的內容,使得用戶能享受一個順暢的「刷」的體驗。
所作的僅僅是把一個請求提早發起了,這也是一種異步機制。思考的要點是:
在移動APP中,預加載有大量的實踐,比較典型的就是升級提醒,你們都採用了先下載好升級包,再提示用戶有新版本的策略,讓你順暢到底。
③ 用戶體驗能否降級
微博客戶端在香港公共WIFI下刷新timeline老是失敗,經過後臺用戶接入請求和響應日誌分析,判斷是香港IDC到香港公共WIFI的匯接口帶寬窄、時延大,此時該如何應對。
從前面探討的TCP/IP網絡知識,能夠知道,在一個窄帶寬高時延網絡中,吞吐量BDP必然很小,也就是說單位大小的數據傳輸所需的時間會很長。若是按照一般一次下發一個邏輯分頁timeline數據的策略,那麼從服務器到客戶端傳輸,整個數據須要拆分紅多個TCP數據報文,在緩慢的傳輸過程當中,可能一個數據報文還未傳輸完成,客戶端的鏈路就已經超時了。
若是在弱網絡(須要在應用層有測速機制,相似TCP/IP的RTT機制,測速時機能夠是拉取微博消息數字時)下,把邏輯分頁的微博消息數由30調整爲5會如何,若是方案成立,用戶刷微博的體驗是否是會降低,由於滑動一屏就要作一次網絡交互,即使是配合預加載,也可能由於網絡太慢,操控太快而又見菊花。外團在香港實測了這個版本,感嘆,終於能夠刷了。
在飢渴難耐和美酒佳餚之間,彷佛還有不少不一樣層級的體驗。聊勝於無,這個詞很精準的表述了服務分層,降級取捨的重要性。思考的要點是:
在移動弱網絡條件下,到處可見降級取捨的案例。好比網絡條件不佳時,下降拉取縮略圖的規格,甚至乾脆不自動拉取縮略圖等等,分層由心,降級有意。
④ 端和雲孰輕孰重
移動APP時代,絕對的輕端重雲或者輕雲重端都是不可取的,只有端雲有機的配合,才能在一個受限的網絡通道上作出更好的用戶體驗。正所謂東家之子,胖瘦有致。
好比移動網遊APP,如取向選擇輕端重雲,那麼玩家的戰鬥計算就會大量的經過網絡遞交給服務器處理並返回,卡頓屢見不鮮,操控感盡失。
好比微博客戶端,若是取向選擇重端輕雲,微博timeline全部的消息都拉取元數據(好比微博正文包括文字、各種URL、話題、標籤、@、消息的父子關係、消息中用戶profile、關係鏈等等),由客戶端實時計算拼裝,不但客戶端用戶須要消耗大量流量計算量,並且給後端服務器帶來巨大的帶寬成本和計算壓力,若是過程當中網絡情況不佳,還會很是卡頓。
經過實踐總結,端和雲孰輕孰重,取捨的關鍵是在數據計算規模可控和數據安全有保障的前提下:
端雲有機結合,能夠很好的演繹機制與策略分離的設計思想,從而使系統具有足夠的柔韌性。
不得再也不次特別提到的一點是,緩存技術是異步化的基礎,它滲透在性能和體驗提高的方方面面,從持久化的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開發者必讀(二):史上最全移動弱網絡優化方法總結》
>> 更多同類文章 ……
(本文同步發佈於:http://www.52im.net/thread-1588-1-1.html)