深度優(yōu)化iOS網(wǎng)絡(luò)模塊

轉(zhuǎn)載自:深度優(yōu)化iOS網(wǎng)絡(luò)模塊

幾乎每一個講究的iOS項目都會有一個「網(wǎng)絡(luò)模塊」,大部分的網(wǎng)絡(luò)請求都是通過HTTP完成,使用成熟的第三方庫諸如AFNetworking很容易搭建一個功能簡易的網(wǎng)絡(luò)模塊。但這一模塊要優(yōu)化好卻沒那么簡單,是個曠日持久的工作,筆者根據(jù)自己多年的“填坑”經(jīng)驗,總結(jié)一下深度優(yōu)化iOS項目網(wǎng)絡(luò)模塊的方方面面,也給自己做下知識梳理。

預(yù)熱

網(wǎng)絡(luò)模塊的接口設(shè)計不在本文討論之列,設(shè)計思路有些偏個人口味,我只探討一些可以深度優(yōu)化的硬性指標。在開始討論優(yōu)化之前,需要讀者對網(wǎng)絡(luò)方面的理論基礎(chǔ)知識有一定的掌握。讀過TCP/IP協(xié)議詳解,RFC文檔就更佳。優(yōu)化的東西對知識的深度和廣度都有相當?shù)囊?,各項目場景不一樣,依葫蘆畫瓢很可能會導致更多的問題,“優(yōu)化”是個危險活。

關(guān)于HTTP推薦大家先閱讀下我之前的一篇總結(jié)性文章,涉及到的知識細節(jié)比較多,一一疏通之后再繼續(xù)下面的閱讀。

在開始優(yōu)化之前,我們先建立樣例代碼,這樣討論起來才能有的放矢。假設(shè)我們定義這樣兩個請求類:

@interface PPRequestManager : NSObject
 
@end
 
@implementation PPRequestManager
 
@end
@interface PPRequest : NSObject
 
@end
 
@implementation PPRequest
 
@end

一個Manager負責管理Request,一個Request基類處理公共邏輯。

優(yōu)化清單
DNS映射

無論是HTTP還是Socket長連接,第一步都是DNS解析。域名根據(jù)層級「主機名.次級域名.頂級域名.根域名」去解析,每一級緩存生命周期不同。在iOS設(shè)備上幾乎每次斷網(wǎng)重連,重啟設(shè)備都會使DNS緩存失效,觸發(fā)重新查詢。這一步的優(yōu)化對請求的延遲來說至關(guān)重要,具體優(yōu)化手段可參考我之前一篇關(guān)于DNS映射的文章,配有可用的demo代碼,這里就不復述了。

請求壓縮

DNS查詢之后是TCP握手建立連接,并發(fā)送請求數(shù)據(jù)。對于TCP來說,單個IP包大小受限于MSS值,大部分用戶所處網(wǎng)絡(luò)環(huán)境下每個包的大小約在1.5KB,新建立的HTTP連接由于TCP的slow start特性,會導致本地的部分IP包本臨時緩存,從而增加了整體request的延遲。所以我們應(yīng)該盡可能嘗試去壓縮我們的網(wǎng)絡(luò)請求業(yè)務(wù)數(shù)據(jù),減少一個Request的IP包數(shù)量,或許可以讓用戶少經(jīng)歷一個RTT,降低請求延遲的用戶感知。

請求合并

對于非關(guān)鍵性的業(yè)務(wù)數(shù)據(jù),或者對實時性要求不高的請求來說,通過合并請求的方式可以減少和服務(wù)器交互的次數(shù),一則降低服務(wù)器壓力,二則合并之后再壓縮能節(jié)約客戶端的流量。這類請求一般見于打點SDK,crash日志收集等非業(yè)務(wù)型請求。

請求的安全性

請求的網(wǎng)絡(luò)安全是個容易被忽視的話題,關(guān)于安全我之前也寫過一篇比較詳細的文章,建議細讀再配合使用HTTPS來做到基本的網(wǎng)絡(luò)安全,這里也不再細述了。

合理的并發(fā)數(shù)

有些業(yè)務(wù)場景會出現(xiàn)多個Request集中產(chǎn)生的情況,此時我們需要設(shè)置一個合理的并發(fā)數(shù)。并發(fā)數(shù)如果太小,會導致“劣質(zhì)”的請求block住“優(yōu)質(zhì)”的請求。如果并發(fā)數(shù)太大,帶寬有限的場景下,會增加請求的整體延遲,請求數(shù)量對于HTTP的影響我在之前的文章中也詳細的介紹過了。

可靠性保障

可靠性保障也是個容易被忽視的方面,在深入探討之前,可以先將Request按業(yè)務(wù)屬性分類。

第一類:關(guān)鍵核心的業(yè)務(wù)數(shù)據(jù),期望能100%送達服務(wù)器。

第二類:重要內(nèi)容請求,需要較高的請求成功率。

第三類:一般性內(nèi)容請求,對成功率無要求。

之所以要將請求分為三類,是要在可靠性保障上做區(qū)分。理論上我們應(yīng)該盡可能讓所有的請求成功率達到最高,但客戶端的流量,帶寬,手機電量,服務(wù)器的壓力等都是有限的資源,所以我們采取的策略是只對關(guān)鍵性的網(wǎng)絡(luò)請求做高強度的可靠性保障。

第一類請求類似大家用微信時發(fā)送的消息,消息數(shù)據(jù)一旦從輸入框發(fā)出,從用戶來的角度感知這個消息數(shù)據(jù)是一定會到達對方的。如果網(wǎng)絡(luò)環(huán)境差,網(wǎng)絡(luò)模塊會自動在后頭悄悄重試,一段時間后仍無法成功就通過產(chǎn)品交互的方式告知用戶發(fā)送失敗了,即使失敗,請求的數(shù)據(jù)(消息本身)一直存在客戶端。

對于這類請求的處理方式第一步不是通過網(wǎng)絡(luò)發(fā)送,而是持久化到Database當中。一旦入了DB,即使斷網(wǎng),斷電,重啟,請求數(shù)據(jù)依然還在,只需在App重啟的時候還原請求數(shù)據(jù),再次發(fā)送即可。我們用代碼來進一步闡釋。

//定義請求可靠性類型
typedef enum : NSUInteger {
    PPRequestReliability_PersistentToDB,
    PPRequestReliability_Retry,
    PPRequestReliability_Normal,
} PPRequestReliability;
 
//增加持久化接口
@interface PPRequest : NSObject
 
@property (nonatomic, assign) PPRequestReliability    reliability;
 
@property (nonatomic, strong) NSNumber*               rowID;
 
@property (nonatomic, strong) NSNumber*               reliabilityStatus;
 
- (PPRequestRecord*)serializeToRecord;
 
- (PPRequest*)deserializeFromRecord:(PPRequestRecord*)record;
 
@end

第一類請求是PPRequestReliability_PersistentToDB,新增了rowID用作存儲DB時的唯一標識,reliabilityStatus表示請求的當前狀態(tài)(成功 or 失敗 or 取消 or 進行中),我們再看下發(fā)送請求的流程。

@implementation PPRequestManager
 
- (void)sendRequest:(PPRequest*)req withDelegate:(id)delegate
{
    if (req.reliability == PPRequestReliability_PersistentToDB) {
     
        PPRequestRecord* record = [req serializeToRecord];
         
        //save record to database
    }
     
    //send request
}
 
- (void)onRequestSucceed:(PPRequest*)req
{
    //add to resend queue
     
    [_resendQueue addObject:req];
     
    //remove from db
}
 
- (void)onRequestFail:(PPRequest*)req
{
    //add to resend queue
     
    [_resendQueue addObject:req];
}
@end

如果判斷為第一類請求,第一步我們先將請求持久化到DB當中。

第二步發(fā)送請求,如果請求失敗則將請求加入重試隊列,成功則從重試隊列中移除。重試隊列背后也需要一套通用機制,比如多久重試一次,重試幾次之后放棄。

遇到最惡劣的場景,請求發(fā)送失敗之后,App被kill。我們需要在App重啟之后從DB當中重新load所有失敗的請求再次重試。

- (void)resendPreviousFailedRequest
{
    //load from db
    //send requests
}

通過上述幾步基本上可以使請求的可靠性得到極大的保障。但100%是無法實現(xiàn)的理想,失敗的時候用戶重裝App,所有持久化的數(shù)據(jù)丟失,請求數(shù)據(jù)也就丟了,不過這種極端的場景非常少。

第二類請求的可靠性為PPRequestReliability_Retry,這類請求的例子可以是我們App啟動時用戶看到的首頁,首頁的內(nèi)容從服務(wù)器獲取,如果第一次請求就失敗體驗較差,這種場景下我們應(yīng)該允許請求有機會多試幾次,增加一個retryCount即可。

//PPRequest.h
@property (nonatomic, assign) int                     retryCount;

一般3次的重試基本可以排除網(wǎng)絡(luò)抖動的情況。三次失敗之后即可認為請求失敗,通過產(chǎn)品交互告知用戶。

第三類請求的重要性最低,比如進入Controller的UV采集打點。這類請求只需要做一次,即使失敗也不會對產(chǎn)品體驗產(chǎn)生什么負面影響。

多通道

現(xiàn)在不少有技術(shù)條件的團隊都有自己的tcp長連接通道,技術(shù)再硬點的甚至配有UDP通道,UDP在丟包率高的網(wǎng)絡(luò)環(huán)境下能極大的提高請求成功的概率。如果能同時具備HTTP,TCP,UDP三條網(wǎng)絡(luò)通道,在某些場景下,如果不考慮流量(比如wifi),可以針對某個網(wǎng)絡(luò)請求,兩通道或者三通道齊發(fā),對請求成功的速度和可靠性有明顯的療效,不過客戶端和服務(wù)器都需要針對業(yè)務(wù)場景做去重。我工作過的一個IM App在發(fā)送消息的時候,就是Socket配合HTTP雙通道工作。UDP在VOIP服務(wù)當中使用較多,不過據(jù)說淘寶這類大廠也部分啟用了UDP。

網(wǎng)絡(luò)環(huán)境監(jiān)控

現(xiàn)在網(wǎng)絡(luò)環(huán)境雖然越來越好,Wifi,4G,3G在一二線城市都有很好的普及,但還是有不少場景會導致網(wǎng)絡(luò)狀態(tài)突然變差,比如進電梯,做火車,人多的集會場所,從公司回家4G切Wifi等等,這些場景在生活當中并不少見,健壯的網(wǎng)絡(luò)模塊需要仔細的檢測網(wǎng)絡(luò)的變化,針對性的做請求重試。

請求成功率監(jiān)控

網(wǎng)絡(luò)模塊應(yīng)該能監(jiān)控當前App的網(wǎng)絡(luò)請求成功率,對于失敗率較高的請求,帶上業(yè)務(wù)數(shù)據(jù),手機網(wǎng)絡(luò)環(huán)境,系統(tǒng)參數(shù)等等,在用戶不活躍的時候能打包上報給server端,一則能找出更多需要優(yōu)化的業(yè)務(wù)場景,二則能實時監(jiān)控server端的健康狀態(tài),三則能從數(shù)據(jù)層面精確判斷每一次網(wǎng)絡(luò)優(yōu)化是否有成效。

以上是做項目當中容易遇到的優(yōu)化點,有些方面只是提到,要實際操作深入優(yōu)化還有很多可以細說,后續(xù)如果想到更多再補充。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)載自:深度優(yōu)化iOS網(wǎng)絡(luò)模塊 幾乎每一個講究的iOS項目都會有一個「網(wǎng)絡(luò)模塊」,大部分的網(wǎng)絡(luò)請求都是通過HTTP...
    路漫漫其修遠兮Wzt閱讀 1,024評論 1 1
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,545評論 19 139
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時...
    歐辰_OSR閱讀 30,225評論 8 265
  • 看了Joy一篇關(guān)于網(wǎng)絡(luò)部分優(yōu)化的文章,總結(jié)一下,方便以后查閱使用 目前客戶端存在的網(wǎng)絡(luò)問題主要有下面幾方面: 1....
    SpursGo閱讀 3,782評論 1 5
  • 又是一年蘭香四溢時 仿佛聽到你在說 姐 這盆花很美 我說 真的 好美 好香 我已聞到了滿屋的蘭香 …… 幼年的生活...
    美臣姜閱讀 742評論 1 3

友情鏈接更多精彩內(nèi)容