<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Jack Jiang

    我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
    posts - 503, comments - 13, trackbacks - 0, articles - 1

    本文由攜程技術(shù)團(tuán)隊(duì)Aaron分享,原題“干貨 | 攜程弱網(wǎng)識(shí)別技術(shù)探索”,下文進(jìn)行了排版和內(nèi)容優(yōu)化。

    1、引言

    網(wǎng)絡(luò)優(yōu)化一直是移動(dòng)互聯(lián)網(wǎng)時(shí)代的熱議話題,弱網(wǎng)識(shí)別作為移動(dòng)端弱網(wǎng)優(yōu)化的第一步,受到的關(guān)注和討論也是最多的。本文從方案設(shè)計(jì)、代碼開(kāi)發(fā)到技術(shù)落地,詳盡的分享了攜程在移動(dòng)端弱網(wǎng)識(shí)別方面的實(shí)踐經(jīng)驗(yàn),如果你也有類似需求,這篇文章會(huì)是一個(gè)不錯(cuò)的實(shí)操指南。

    2、本文作者

    Aaron:攜程移動(dòng)開(kāi)發(fā)專家,關(guān)注網(wǎng)絡(luò)優(yōu)化、移動(dòng)端性能優(yōu)化。

    3、系列文章

    1. 移動(dòng)端弱網(wǎng)優(yōu)化專題(一):通俗易懂,理解移動(dòng)網(wǎng)絡(luò)的“弱”和“慢”
    2. 移動(dòng)端弱網(wǎng)優(yōu)化專題(二):史上最全移動(dòng)弱網(wǎng)絡(luò)優(yōu)化方法總結(jié)
    3. 移動(dòng)端弱網(wǎng)優(yōu)化專題(三):現(xiàn)代移動(dòng)端網(wǎng)絡(luò)短連接的優(yōu)化手段總結(jié)
    4. 移動(dòng)端弱網(wǎng)優(yōu)化專題(四):百度APP網(wǎng)絡(luò)深度優(yōu)化實(shí)踐(DNS優(yōu)化篇)
    5. 移動(dòng)端弱網(wǎng)優(yōu)化專題(五):百度APP網(wǎng)絡(luò)深度優(yōu)化實(shí)踐(網(wǎng)絡(luò)連接優(yōu)化篇)
    6. 移動(dòng)端弱網(wǎng)優(yōu)化專題(六):百度APP網(wǎng)絡(luò)深度優(yōu)化實(shí)踐(移動(dòng)弱網(wǎng)優(yōu)化篇)
    7. 移動(dòng)端弱網(wǎng)優(yōu)化專題(七):愛(ài)奇藝APP網(wǎng)絡(luò)優(yōu)化實(shí)踐(網(wǎng)絡(luò)請(qǐng)求成功率優(yōu)化篇)
    8. 移動(dòng)端弱網(wǎng)優(yōu)化專題(八):美團(tuán)點(diǎn)評(píng)的網(wǎng)絡(luò)優(yōu)化實(shí)踐(大幅提升連接成功率、速度等)
    9. 移動(dòng)端弱網(wǎng)優(yōu)化專題(九):淘寶移動(dòng)端統(tǒng)一網(wǎng)絡(luò)庫(kù)的架構(gòu)演進(jìn)和弱網(wǎng)優(yōu)化實(shí)踐
    10. 移動(dòng)端弱網(wǎng)優(yōu)化專題(十):愛(ài)奇藝APP跨國(guó)弱網(wǎng)通信的優(yōu)化實(shí)踐
    11. 移動(dòng)端弱網(wǎng)優(yōu)化專題(十一):美圖APP的移動(dòng)端DNS優(yōu)化實(shí)踐
    12. 移動(dòng)端弱網(wǎng)優(yōu)化專題(十二):得物自研移動(dòng)端弱網(wǎng)診斷工具的技術(shù)實(shí)踐
    13. 移動(dòng)端弱網(wǎng)優(yōu)化專題(十三):得物移動(dòng)端常見(jiàn)白屏問(wèn)題優(yōu)化(網(wǎng)絡(luò)優(yōu)化篇)
    14. 移動(dòng)端弱網(wǎng)優(yōu)化專題(十四):攜程APP移動(dòng)網(wǎng)絡(luò)優(yōu)化實(shí)踐(弱網(wǎng)識(shí)別篇)》(* 本文

    4、技術(shù)背景

    自從2010年攜程推出”無(wú)線戰(zhàn)略“,并發(fā)布移動(dòng)端APP以來(lái),無(wú)線研發(fā)團(tuán)隊(duì)對(duì)于客戶端網(wǎng)絡(luò)性能的優(yōu)化就一直沒(méi)有停止過(guò)。經(jīng)過(guò)這十幾年持續(xù)不斷的優(yōu)化,目前攜程的端到端網(wǎng)絡(luò)性能已經(jīng)處于一個(gè)相當(dāng)不錯(cuò)的水平,大盤數(shù)據(jù)趨于穩(wěn)定,優(yōu)化也隨之進(jìn)入 ”深水區(qū)“,提升難度巨大。

    結(jié)合線上的一系列客訴反饋,我們發(fā)現(xiàn)即使大盤的數(shù)據(jù)再優(yōu)秀,用戶網(wǎng)絡(luò)表現(xiàn)不佳的個(gè)例case仍然層出不窮,排查后大部分被我們歸因到"弱網(wǎng)”。這部分“弱網(wǎng)”長(zhǎng)尾數(shù)據(jù)相比大盤均值仍有巨大的提升空間,如果可以針對(duì)性優(yōu)化的話,對(duì)于提升整體用戶體驗(yàn)和減少客訴都有非常明確的價(jià)值。

    既然要優(yōu)化“弱網(wǎng)”,那第一步一定是建立相應(yīng)的“弱網(wǎng)識(shí)別模型”,準(zhǔn)確識(shí)別出弱網(wǎng)場(chǎng)景,本文即探討攜程在弱網(wǎng)識(shí)別方面的技術(shù)探索,包含技術(shù)選型細(xì)節(jié)和關(guān)鍵的路徑思考,歡迎溝通交流。

    5、技術(shù)方案概覽

    如上圖所示,攜程弱網(wǎng)識(shí)別模型的整個(gè)工作流程由數(shù)據(jù)采集、數(shù)據(jù)處理、結(jié)果輸出三部分組成,接下來(lái)我們順著流程來(lái)逐個(gè)剖析相關(guān)細(xì)節(jié)。

    6、數(shù)據(jù)采集實(shí)現(xiàn)

    6.1 反映網(wǎng)絡(luò)質(zhì)量的指標(biāo)有哪些

    說(shuō)到可以客觀反映網(wǎng)絡(luò)質(zhì)量的指標(biāo),業(yè)內(nèi)定義清晰且獲得公認(rèn)的有如下這些:

    • 1)HttpRTTHttp請(qǐng)求一次網(wǎng)絡(luò)往返的耗時(shí),具體口徑是客戶端從開(kāi)始發(fā)送RequestHeader到收到ResponseHeader第一個(gè)字節(jié)的時(shí)間差;
    • 2)TransportRTT:網(wǎng)絡(luò)通道上一次數(shù)據(jù)往返的耗時(shí),具體口徑是客戶端從開(kāi)始發(fā)送數(shù)據(jù)到收到服務(wù)端返回?cái)?shù)據(jù)第一個(gè)字節(jié)的時(shí)間差,要減去服務(wù)處理的耗時(shí);
    • 3)ThroughPut:網(wǎng)絡(luò)吞吐量,是指定位時(shí)間內(nèi)網(wǎng)絡(luò)通道上下行的數(shù)據(jù)量,具體口徑是單位位時(shí)間內(nèi)上行或者下行的數(shù)據(jù)量除以單位時(shí)間,由于上行數(shù)據(jù)量受到業(yè)務(wù)因素的影響較大,我們一般僅關(guān)注下行;
    • 4)BandwidthDelayProduct:帶寬時(shí)延乘積,顧名思義是指網(wǎng)絡(luò)帶寬乘以網(wǎng)絡(luò)時(shí)延的結(jié)果,即當(dāng)前網(wǎng)絡(luò)通道里正在傳輸?shù)臄?shù)據(jù)總量,是一個(gè)復(fù)合指標(biāo),可以客觀反映當(dāng)前網(wǎng)絡(luò)承載數(shù)據(jù)的能力,計(jì)算方式是 ThroughPut * TransportRTT;
    • 5)SignalStrength:信號(hào)強(qiáng)度,移動(dòng)互聯(lián)網(wǎng)時(shí)代,設(shè)備依靠Wifi或者蜂窩數(shù)據(jù)接入互聯(lián)網(wǎng),信號(hào)強(qiáng)度會(huì)影響用戶的網(wǎng)絡(luò)表現(xiàn);
    • 6)NetworkSuccessRate:網(wǎng)絡(luò)成功率,剔除業(yè)務(wù)影響的純網(wǎng)絡(luò)行為成功率,與網(wǎng)絡(luò)質(zhì)量呈正相關(guān),包含建聯(lián)成功率、傳輸成功率等。

    6.2 哪些指標(biāo)作為模型輸入?為什么?

    對(duì)于網(wǎng)絡(luò)質(zhì)量識(shí)別,業(yè)內(nèi)做的比較早的是Google的NQE(Network Quality Estimator),國(guó)內(nèi)大多數(shù)網(wǎng)絡(luò)質(zhì)量識(shí)別方案也都參考了Google NQE,NQE中識(shí)別模型的輸入主要是HttpRTT、TransportRTT、DownstreamThroughput這三個(gè)指標(biāo)。

    對(duì)于HttpRTT、TransportRTT,在應(yīng)用層和傳輸層都有很多方式可以采集到,且口徑清晰,所以這兩個(gè)指標(biāo)被我們納入采集范圍。

    對(duì)于DownstreamThroughput,我們實(shí)踐過(guò)程中發(fā)現(xiàn),該指標(biāo)受到用戶行為的影響很大,當(dāng)用戶集中操作大量發(fā)送網(wǎng)絡(luò)請(qǐng)求的時(shí)候,該指標(biāo)就偏高,當(dāng)用戶停止操作閱讀數(shù)據(jù)時(shí),該指標(biāo)就會(huì)偏低甚至長(zhǎng)時(shí)間得不到更新,考慮到指標(biāo)的波動(dòng)性,我們不將此指標(biāo)納入采集范圍。

    既然DownstreamThroughput被排除在外,那由他參與計(jì)算的BandwidthDelayProduct也被我們排除。

    SignalStrength信號(hào)強(qiáng)度由于iOS無(wú)法準(zhǔn)確獲取,考慮到多端一致性,也被我們Pass。

    NetworkSuccessRate網(wǎng)絡(luò)成功率這個(gè)指標(biāo),可能很少被其他方案提及到,我們提出這個(gè)指標(biāo)并將他納入采集范圍的主要原因是,基于RTT的網(wǎng)絡(luò)識(shí)別模型,在遇到網(wǎng)絡(luò)波動(dòng)導(dǎo)致的用戶大面積請(qǐng)求失敗時(shí),無(wú)法獲取到有效的RTT值,導(dǎo)致識(shí)別的準(zhǔn)確性和實(shí)時(shí)性都收到影響,引入網(wǎng)絡(luò)成功率可以很好的彌補(bǔ)這個(gè)缺陷,最終線上生產(chǎn)環(huán)境驗(yàn)證也證明了該指標(biāo)的必要性。

    最終:攜程的網(wǎng)絡(luò)質(zhì)量識(shí)別模型采集HttpRTT、TransportRTT、NetworkSuccessRate作為輸入指標(biāo)。

    6.3 輸入的網(wǎng)絡(luò)指標(biāo)如何采集

    攜程的網(wǎng)絡(luò)請(qǐng)求,主要有Tcp代理通道、Quic代理通道、Http通道三種網(wǎng)絡(luò)通道。

    對(duì)于上述提到了三個(gè)輸入指標(biāo),我們從如下網(wǎng)絡(luò)行為中進(jìn)行數(shù)據(jù)采集:

    • 1)TransportRTT:通道心跳耗時(shí)、Tcp通道建聯(lián)耗時(shí)、Http通道建聯(lián)耗時(shí)(Tips:建聯(lián)耗時(shí)不涉及業(yè)務(wù)處理,近似于純網(wǎng)絡(luò)傳輸耗時(shí),所以我們把他作為TransportRTT;Quic建聯(lián)約等于Tls握手耗時(shí),且存在0RTT等特性干擾,所以不采用);
    • 2)HttpRTT:標(biāo)準(zhǔn)Http請(qǐng)求的responseHeader開(kāi)始接收時(shí)間減去RequestHeader的開(kāi)始發(fā)送時(shí)間、自定義網(wǎng)絡(luò)通道請(qǐng)求的開(kāi)始接收時(shí)間減去開(kāi)始發(fā)送時(shí)間;
    • 3)NetworkSuccessRate:Tcp建聯(lián)成功狀態(tài)、Quic建聯(lián)成功狀態(tài)、心跳成功狀態(tài)、Http請(qǐng)求是否完整接收到Response。

    對(duì)于自定義的Tcp、Quic代理通道,按照上述口徑在網(wǎng)絡(luò)通道相關(guān)狀態(tài)回調(diào)內(nèi)統(tǒng)計(jì)數(shù)據(jù)即可,自定義實(shí)現(xiàn)參考價(jià)值不大,這里就不過(guò)多贅述。

    對(duì)于標(biāo)準(zhǔn)的Http請(qǐng)求,我們可以通過(guò)獲取系統(tǒng)網(wǎng)絡(luò)框架返回的Metric信息或者監(jiān)聽(tīng)請(qǐng)求的狀態(tài)流轉(zhuǎn)來(lái)獲取網(wǎng)絡(luò)指標(biāo)。

    1)對(duì)于iOS端:

    iOS 10之后NSURLSession支持通過(guò)NSURLSessionTaskDelegate的協(xié)議方法URLSession:task:didFinishCollectingMetrics:獲取到請(qǐng)求的Metric信息,詳細(xì)信息見(jiàn)附錄。

    單次請(qǐng)求的Metric定義如下圖:

    解釋一下:

    • 1)TransportRTT = connectEnd - connectStart - secureConnectionEnd + secureConnectionStart;建聯(lián)耗時(shí)要減去Tls的耗時(shí),連接復(fù)用時(shí),相關(guān)字段為空值,不納入計(jì)算;
    • 2)HttpRTT = responseStart - requestStart;
    • 3)NetworkSuccessStatus = responseEnd 且沒(méi)有傳輸錯(cuò)誤;網(wǎng)絡(luò)成功率只關(guān)心傳輸是否成功,不需要關(guān)注Response的http狀態(tài)碼。

    2)對(duì)于Android端:

    系統(tǒng)網(wǎng)絡(luò)框架OkHttp支持添加EventListener來(lái)獲取Http請(qǐng)求的狀態(tài)流轉(zhuǎn)信息,可以在各狀態(tài)回調(diào)內(nèi)記錄時(shí)間戳來(lái)計(jì)算RTT,詳細(xì)信息見(jiàn)附錄。

    單次請(qǐng)求的Events定義如下圖:

    解釋一下:

    • 1)TransportRTT = connectEnd - connectStart - secureConnectEnd + secureConnectStart;
    • 2)HttpRTT = responseHeadersStart - requestHeadersStart;
    • 3)NetworkSuccessStatus = responseBodyEnd 且沒(méi)有傳輸錯(cuò)誤。

    依照上述方法收集到網(wǎng)絡(luò)數(shù)據(jù)后,我們把數(shù)據(jù)封裝成對(duì)應(yīng)的結(jié)構(gòu)體,注入識(shí)別模型,攜程對(duì)于網(wǎng)絡(luò)數(shù)據(jù)結(jié)構(gòu)體的定義如下,方便大家參考。

    typedef enum : int64_t {   

     

        NQEMetricsSourceTypeInvalid = 0, // 0

        NQEMetricsSourceTypeTcpConnect = 1 << 0, // 1

        NQEMetricsSourceTypeQuicConnect = 1 << 1, // 2

        NQEMetricsSourceTypeHttpRequest = 1 << 2, // 4

        NQEMetricsSourceTypeQuicRequest = 1 << 3, // 8

        NQEMetricsSourceTypeHeartBeat = 1 << 4, // 16

        ......

    } NQEMetricsSourceType;

     

    struct NQEMetrics {

     

        // 本次采集到的數(shù)據(jù)來(lái)源,可以是多個(gè)枚舉值的或值

        // 例如一次沒(méi)有連接復(fù)用http請(qǐng)求,source = TcpConnect|HttpRequest,同時(shí)存在transportRTT和httpRTT     NQEMetricsSourceType source;

        // 本次數(shù)據(jù)的成功狀態(tài),用作成功率計(jì)算

        bool isSuccessed;

        // httpRTT,可為空

        double httpRTTInSec;

        // transportRTT,可為空

        double transportRTTInSec;

        // 數(shù)據(jù)采集時(shí)間

        double occurrenceTimeInSec;

    };

    7、數(shù)據(jù)處理實(shí)現(xiàn)

    7.1數(shù)據(jù)過(guò)濾和滑動(dòng)窗口

    網(wǎng)絡(luò)數(shù)據(jù)采集后,注入到識(shí)別模型內(nèi),需要一個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)承載,我們采用的是隊(duì)列。

    進(jìn)入隊(duì)列前,我們需要先進(jìn)行數(shù)據(jù)過(guò)濾,篩選掉一些無(wú)效的數(shù)據(jù)。

    目前采用的篩選策略有如下這些:

    • 1)單條NQEMetrics數(shù)據(jù):在isSuccessed=true的情況下,httpRTT、transportRTT至少有一條不為空,否則為無(wú)效數(shù)據(jù);
    • 2)RTT必須大于最小閾值:用來(lái)過(guò)濾一些類似LocalHost請(qǐng)求的臟數(shù)據(jù),目前采用的閾值為10ms;
    • 3)RTT必須小于最大閾值:用來(lái)過(guò)濾前后臺(tái)切換進(jìn)程掛起導(dǎo)致的RTT數(shù)值偏大,目前采用的閾值為5mins。

    數(shù)據(jù)過(guò)濾后加入隊(duì)列,為了實(shí)時(shí)性和結(jié)果準(zhǔn)確性,我們處理數(shù)據(jù)時(shí),會(huì)根據(jù)兩個(gè)限制邏輯來(lái)確定一個(gè)具體的滑動(dòng)窗口,只讓窗口內(nèi)的數(shù)據(jù)參與計(jì)算。

    具體窗口限制邏輯如下:

    • 1)最小數(shù)量限制:當(dāng)窗口內(nèi)數(shù)據(jù)過(guò)少時(shí),會(huì)放大單條數(shù)據(jù)的影響,導(dǎo)致結(jié)果毛刺增多,所以我們限制最小計(jì)算窗口的數(shù)據(jù)條數(shù)為5;
    • 2)最大時(shí)間限制:為了數(shù)據(jù)實(shí)時(shí)性的考慮,比較舊的數(shù)據(jù)不參與計(jì)算,目前采用的閾值為5mins。

    每次計(jì)算網(wǎng)絡(luò)質(zhì)量時(shí),可以根據(jù)這兩個(gè)限制來(lái)確定計(jì)算窗口,窗口外的數(shù)據(jù)可以實(shí)時(shí)清理出隊(duì)列,減少內(nèi)存占用。

    上文提到的各種閾值設(shè)置,均可通過(guò)配置系統(tǒng)更新。

    7.2 動(dòng)態(tài)權(quán)重計(jì)算

    弱網(wǎng)識(shí)別模型的原理簡(jiǎn)單來(lái)說(shuō)就是將窗口內(nèi)的一組數(shù)據(jù)經(jīng)過(guò)一系列處理后,得出一個(gè)最終值,再用這個(gè)最終值與對(duì)應(yīng)的弱網(wǎng)閾值比較來(lái)得出是否是弱網(wǎng)。

    出于實(shí)時(shí)性的考慮,我們希望距離當(dāng)前時(shí)間越近的數(shù)據(jù)權(quán)重越高,所以要用到動(dòng)態(tài)權(quán)重的算法,這里我們比較推薦的是”半衰期動(dòng)態(tài)權(quán)重“和”反正切動(dòng)態(tài)權(quán)重“兩種算法。

    1)半衰期動(dòng)態(tài)權(quán)重:

    半衰期顧名思義,即每經(jīng)過(guò)一個(gè)固定的時(shí)間,權(quán)重降低為之前的一半。

    這里衰減幅度和周期都是可以自定義的,計(jì)算公式如下:

    每秒衰減因子 = pow(衰減幅度, 1.0 / 衰減周期);衰減幅度為浮點(diǎn)型,取值范圍 0~1,衰減周期為整形,單位為秒

    動(dòng)態(tài)權(quán)重 = pow(每秒衰減因子, abs(now - 數(shù)據(jù)采集時(shí)間))

    以衰減幅度為0.5,衰減周期為60秒為例,對(duì)應(yīng)的函數(shù)曲線如下:

    橫坐標(biāo)為數(shù)據(jù)采集時(shí)間距今的時(shí)間差,縱坐標(biāo)為權(quán)重,從圖上可以清晰看到,隨著時(shí)間差增大,權(quán)重?zé)o限趨近于0。

    半衰期動(dòng)態(tài)權(quán)重也是Google NQE采用的權(quán)重計(jì)算方案,Google采用的周期是每60秒降低50%,相關(guān)代碼詳見(jiàn)附錄。

    部分核心代碼如下:

    double GetWeightMultiplierPerSecond(

        const std::map<std::string, std::string>& params) {

      // Default value of the half life (in seconds) for computing time weighted

      // percentiles. Every half life, the weight of all observations reduces by

      // half. Lowering the half life would reduce the weight of older values

      // faster.

      int half_life_seconds = 60;

      int32_t variations_value = 0;

      auto it = params.find("HalfLifeSeconds");

      if (it != params.end() && base::StringToInt(it->second, &variations_value) &&

          variations_value >= 1) {

        half_life_seconds = variations_value;

      }

      DCHECK_GT(half_life_seconds, 0);

      return pow(0.5, 1.0 / half_life_seconds);

    }

     

    void ObservationBuffer::ComputeWeightedObservations(

        const base::TimeTicks& begin_timestamp,

        int32_t current_signal_strength,

        std::vector<WeightedObservation>* weighted_observations,

        double* total_weight) const {

     

        base::TimeDelta time_since_sample_taken = now - observation.timestamp();

        double time_weight =

            pow(weight_multiplier_per_second_, time_since_sample_taken.InSeconds());

    }

    2)反正切動(dòng)態(tài)權(quán)重:

    y=arctan(x)反正切函數(shù)在第一象限的取值范圍為0~Pi/2,我們將arctan(x)取反,向上平移Pi/2,然后除以Pi/2,函數(shù)曲線即可在第一象限隨著x增大y的取值從1趨近于0。

    我們還可以使用一個(gè)斜率系數(shù)來(lái)控制權(quán)重降低的趨勢(shì)快慢,公式推導(dǎo)過(guò)程如下:

    動(dòng)態(tài)權(quán)重 = (Pi / 2  - arctan(abs(now - 數(shù)據(jù)采集時(shí)間) * 斜率系數(shù))) / (Pi / 2) = 1 - arctan(abs(now - 數(shù)據(jù)采集時(shí)間) * 斜率系數(shù))  / Pi * 2;斜率系數(shù)為浮點(diǎn)型,取值范圍為0~1,系數(shù)越小,權(quán)重降低的越緩慢。

    以斜率系數(shù)為1/20為例,對(duì)應(yīng)的函數(shù)曲線如下:

    和前文的半衰期動(dòng)態(tài)權(quán)重相同,橫坐標(biāo)為數(shù)據(jù)采集時(shí)間距今的時(shí)間差,縱坐標(biāo)為權(quán)重,隨著時(shí)間差增大,權(quán)重趨近于0,兩種動(dòng)態(tài)權(quán)重算法效果類似。

    反正切動(dòng)態(tài)權(quán)重的實(shí)現(xiàn)代碼如下:

    static double _nqe_getWeight(double targetTime) {

        ……

        double interval = now - targetTime;

        /// 曲率系數(shù),數(shù)值越小權(quán)重降低的越緩慢

        double rate = 20.0 / 1;

        return 1.0 - atan(interval * rate) / M_PI_2;

    }

    從上圖的代碼實(shí)現(xiàn)可以看出,反正切相關(guān)的代碼實(shí)現(xiàn)要簡(jiǎn)單很多,但是由于存在推導(dǎo)過(guò)程,所以理解起來(lái)比較困難,代碼維護(hù)成本較高(數(shù)學(xué)功底對(duì)于程序員來(lái)說(shuō)也是非常重要的),大家可以酌情自行選擇。

    攜程最終采用的也是半衰期動(dòng)態(tài)權(quán)重的方案,出于實(shí)時(shí)性考慮,最終線上驗(yàn)證后采用的衰減幅度為0.3,衰減幅度為60秒,供參考。

    7.3 RTT指標(biāo)加權(quán)中值計(jì)算

    在確定了單條數(shù)據(jù)的權(quán)重之后,對(duì)于RTT的數(shù)值計(jì)算,我們第一個(gè)想到的是加權(quán)平均,但是加權(quán)平均很容易收到高權(quán)重臟數(shù)據(jù)的影響,準(zhǔn)確性堪憂,所以我們改用了“加權(quán)中值”。

    加權(quán)中值的計(jì)算方式是,將窗口內(nèi)的數(shù)據(jù)按照數(shù)值大小升序排列,然后從頭遍歷數(shù)據(jù),累加權(quán)重大于等于總權(quán)重的一半時(shí),停止遍歷,當(dāng)前遍歷到的數(shù)值即為最終的加權(quán)中值。

    NQE對(duì)于TransportRTT和HttpRTT處理,也是使用的這種方式,相關(guān)代碼詳見(jiàn)附錄。

    部分核心代碼如下:

    std::optional<int32_t> ObservationBuffer::GetPercentile(

        base::TimeTicks begin_timestamp,

        int32_t current_signal_strength,

        int percentile,

        size_t* observations_count) const {

     

    ……

      // 此處的percentile值為50,即取中值

      double desired_weight = percentile / 100.0 * total_weight;

      double cumulative_weight_seen_so_far = 0.0;

      for (const auto& weighted_observation : weighted_observations) {

        cumulative_weight_seen_so_far += weighted_observation.weight;

        if (cumulative_weight_seen_so_far >= desired_weight)

          return weighted_observation.value;

      }

      // Computation may reach here due to floating point errors. This may happen

      // if |percentile| was 100 (or close to 100), and |desired_weight| was

      // slightly larger than |total_weight| (due to floating point errors).

      // In this case, we return the highest |value| among all observations.

      // This is same as value of the last observation in the sorted vector.

      return weighted_observations.at(weighted_observations.size() - 1).value;

    }

    7.4 成功率指標(biāo)加權(quán)平均計(jì)算

    對(duì)于成功率,我們的NQEMetrics結(jié)構(gòu)體內(nèi)定義了單次成功狀態(tài)isSuccessed,單條數(shù)據(jù)的加權(quán)成功率為 (NQEMetrics.isSuccessed ? 1 : 0) * weight,整體的加權(quán)成功率為加權(quán)成功率總和除以總權(quán)重。

    相關(guān)代碼實(shí)現(xiàn)如下:

    extern double _calculateSuccessRateByWeight(const vector &metrics, uint64_t types, const shared_ptr<NQEConfig> config) {

        ……

        uint64_t totalValidCount = 0;

        double totalWeights = 0.0;

        double totalSuccessRate = 0.0;

     

        for (const auto& m : metrics) {

            /// 過(guò)濾需要的數(shù)據(jù)

            if ((m.source & types) == 0) {

                continue;

            }

            /// 累計(jì)總權(quán)重和總成功率

            totalValidCount++;

            totalWeights += m.weight;

            totalSuccessRate += (m.isSuccessed ? 1 : 0) * m.weight;

        }

     

        /// 數(shù)據(jù)不足

        if (totalValidCount < config->minValidWindowSize) {

            return NQE_INVALID_RATE_VALUE;

        }

        if (totalWeights <= 0.0) {

            return NQE_INVALID_RATE_VALUE;

        }

     

        return totalSuccessRate / totalWeights;

    }

    7.5 引入成功率趨勢(shì)提高實(shí)時(shí)性

    網(wǎng)絡(luò)質(zhì)量識(shí)別不僅需要準(zhǔn)確,實(shí)時(shí)性也非常重要,在網(wǎng)絡(luò)質(zhì)量切換時(shí)模型識(shí)別的時(shí)間越短越好。前文已經(jīng)提到了TransportRTT、HttpRTT、NetworkSuccessRate三個(gè)核心指標(biāo)的計(jì)算,但是在線上實(shí)際驗(yàn)證的過(guò)程中,我們發(fā)現(xiàn)在網(wǎng)絡(luò)完全不可用成功率跌0后,識(shí)別模型對(duì)于網(wǎng)絡(luò)狀態(tài)的恢復(fù)感知很慢,原因是成功率的攀升需要較長(zhǎng)的時(shí)間。

    針對(duì)這個(gè)極端的case,我們引入了一個(gè)“成功率趨勢(shì)”的新指標(biāo),來(lái)優(yōu)化模型的實(shí)時(shí)性,在成功率未達(dá)閾值當(dāng)時(shí)有明顯趨勢(shì)時(shí),提前切換網(wǎng)絡(luò)質(zhì)量狀態(tài)。成功率趨勢(shì)是指一段時(shí)間內(nèi)成功率連續(xù)上升或者下降的幅度,浮點(diǎn)類型,取值范圍-1 ~ +1

    成功率趨勢(shì)初始值為0,計(jì)算方式如下:

    1)在每次更新成功率時(shí),計(jì)算更新前后成功率的差值:

    如果差值為正,則成功率向好:

    • 1)如果當(dāng)前成功率趨勢(shì)值為正,則向好趨勢(shì)持續(xù),成功率趨勢(shì)加上當(dāng)前差值;
    • 2)如果當(dāng)前成功率趨勢(shì)值為負(fù),則成功率趨勢(shì)由壞轉(zhuǎn)好,成功率趨勢(shì)重置為當(dāng)前差值。

    如果差值為負(fù),則成功率向壞:

    • 1)如果當(dāng)前成功率趨勢(shì)值為正,則成功率趨勢(shì)由好轉(zhuǎn)壞,成功率趨勢(shì)重置為當(dāng)前差值;
    • 2)如果當(dāng)前成功率趨勢(shì)值為負(fù),則向壞趨勢(shì)持續(xù),成功率趨勢(shì)加上當(dāng)前差值(負(fù)值)。

    2)當(dāng)然還需要過(guò)濾一些毛刺數(shù)據(jù),避免趨勢(shì)變化過(guò)頻:

    具體代碼實(shí)現(xiàn)如下:

    void NQE::_updateSuccessRateTrend() {

        auto oldRate;

        auto newRate;

     

        if (oldRate < 0 || newRate < 0) {

            _successRateContinuousDiff = 0;

            return;

        }

        auto diff = newRate - oldRate;

        /// 數(shù)據(jù)錯(cuò)誤,不做處理

        if (abs(diff) > 1) {

            _successRateContinuousDiff = 0;

            return;

        }

        /// diff小于0.01,作為毛刺處理,不影響趨勢(shì)變化

        if (abs(diff) < 0.01) {

            _successRateContinuousDiff += diff;

            return;

        }

        /// 計(jì)算連續(xù)diff

        if (diff > 0 && _successRateContinuousDiff > 0) {

            _successRateContinuousDiff += diff;

        } else if (diff < 0 && _successRateContinuousDiff < 0) {

            _successRateContinuousDiff += diff;

        } else {

            _successRateContinuousDiff = diff;

        }

    }

    在網(wǎng)絡(luò)成功率和成功率趨勢(shì)的加持下,我們的識(shí)別模型實(shí)時(shí)性大幅度提升。我們控制相同請(qǐng)求頻率和請(qǐng)求數(shù)據(jù)量,線下模擬弱網(wǎng)切換進(jìn)行測(cè)試。

    測(cè)試結(jié)果如下:

    • 1)單RTT識(shí)別模型:網(wǎng)絡(luò)質(zhì)量切換后識(shí)別較慢,且存在連續(xù)切換場(chǎng)景識(shí)別不出弱網(wǎng)的情況;
    • 2)RTT+成功率模型:切換識(shí)別速度較單RTT模型提升約50%,成功率跌0后的Bad切Good識(shí)別明顯較慢;
    • 3)RTT+成功率+成功率趨勢(shì)模型:切換識(shí)別速度較單RTT模型提升約70%,Bad切Good識(shí)別速度明顯提升。

    所以,最終攜程弱網(wǎng)識(shí)別模型計(jì)算的指標(biāo)有TransportRTT、HttpRTT、NetworkSuccessRate、SuccessRateTrend(成功率趨勢(shì))四個(gè)。

    8、結(jié)果輸出

    8.1 網(wǎng)絡(luò)質(zhì)量定義

    識(shí)別模型對(duì)外輸出的是一個(gè)網(wǎng)絡(luò)質(zhì)量的枚舉值,Google NQE對(duì)于網(wǎng)絡(luò)質(zhì)量的定義如下,源碼詳見(jiàn)附錄。

    enum EffectiveConnectionType {

      // Effective connection type reported when the network quality is unknown.

      EFFECTIVE_CONNECTION_TYPE_UNKNOWN = 0,

     

      // Effective connection type reported when the Internet is unreachable

      // because the device does not have a connection (as reported by underlying

      // platform APIs). Note that due to rare but  potential bugs in the platform

      // APIs, it is possible that effective connection type is reported as

      // EFFECTIVE_CONNECTION_TYPE_OFFLINE. Callers must use caution when using

      // acting on this.

      EFFECTIVE_CONNECTION_TYPE_OFFLINE,

     

      // Effective connection type reported when the network has the quality of a

      // poor 2G connection.

      EFFECTIVE_CONNECTION_TYPE_SLOW_2G,

     

      // Effective connection type reported when the network has the quality of a

      // faster 2G connection.

      EFFECTIVE_CONNECTION_TYPE_2G,

     

      // Effective connection type reported when the network has the quality of a 3G

      // connection.

      EFFECTIVE_CONNECTION_TYPE_3G,

     

      // Effective connection type reported when the network has the quality of a 4G

      // connection.

      EFFECTIVE_CONNECTION_TYPE_4G,

     

      // Last value of the effective connection type. This value is unused.

      EFFECTIVE_CONNECTION_TYPE_LAST,

    };

    Google枚舉定義的最大問(wèn)題是理解成本比較高,其他開(kāi)發(fā)同學(xué)看到這個(gè)所謂的“3G”、“4G”,他依然不知道網(wǎng)絡(luò)是好是壞,是不是他認(rèn)為的“弱網(wǎng)”。

    所以我們?cè)诙x接口的時(shí)候,對(duì)于枚舉的設(shè)計(jì)考慮最多的就是理解成本,結(jié)合開(kāi)發(fā)同學(xué)最想知道的“是不是弱網(wǎng)”。

    我們的接口定義如下:

    typedef enum : int64_t {

        /// 未知狀態(tài),初始狀態(tài)或者無(wú)有效計(jì)算窗口時(shí)會(huì)進(jìn)入此狀態(tài)

        NetworkQualityTypeUnknown = 0,

        /// 離線狀態(tài),網(wǎng)絡(luò)不可用

        NetworkQualityTypeOffline = 1,

        /// 弱網(wǎng)狀態(tài)

        NetworkQualityTypeBad = 2,

        /// 正常網(wǎng)絡(luò)狀態(tài)

        NetworkQualityTypeGood = 3

    } NetworkQualityType;

    這樣是不是看起來(lái)簡(jiǎn)單明了多了,我們接下來(lái)就講講怎么計(jì)算得出這幾個(gè)枚舉的結(jié)果。

    8.2 網(wǎng)絡(luò)質(zhì)量計(jì)算方式

    NetworkQualityTypeUnknown 是在初始化或者網(wǎng)絡(luò)切換后的一段時(shí)間內(nèi),數(shù)據(jù)不足無(wú)法得出網(wǎng)絡(luò)質(zhì)量,會(huì)進(jìn)入此狀態(tài)。

    NetworkQualityTypeOffline 的觸發(fā)條件很單一,就是操作系統(tǒng)識(shí)別到無(wú)網(wǎng)絡(luò)連接,具體的獲取方式由各平臺(tái)自行實(shí)現(xiàn),例如iOS可以通過(guò)Reachability獲取,官方Demo詳見(jiàn)附錄6。

    NetworkQualityTypeBad 也就是我們最核心的“弱網(wǎng)”狀態(tài),計(jì)算方式是上文提到的TransportRTT、HttpRTT兩個(gè)指標(biāo)任一指標(biāo)觸發(fā)弱網(wǎng)閾值,或者NetworkSuccessRate和SuccessRateTrend同時(shí)滿足弱網(wǎng)閾值。

    NetworkQualityTypeGood 是指正常的網(wǎng)絡(luò)質(zhì)量狀態(tài),上述三種網(wǎng)絡(luò)質(zhì)量類型講完后,這個(gè)類型就簡(jiǎn)單了,即非上述三種情況的場(chǎng)景,歸類到Good,這也是設(shè)計(jì)上占比最高的網(wǎng)絡(luò)質(zhì)量類型。

    識(shí)別模型的運(yùn)轉(zhuǎn)流程如下:

    解釋一下:

    • 1)數(shù)據(jù)隊(duì)列在初始化和網(wǎng)絡(luò)連接狀態(tài)變化兩個(gè)時(shí)機(jī)會(huì)被重置,充值后網(wǎng)絡(luò)質(zhì)量類型進(jìn)入 NetworkQualityTypeUnknown;
    • 2)網(wǎng)絡(luò)連接狀態(tài)進(jìn)入無(wú)連接狀態(tài)時(shí),數(shù)據(jù)隊(duì)列被清空,網(wǎng)絡(luò)質(zhì)量類型直接進(jìn)入 NetworkQualityTypeOffline,在網(wǎng)絡(luò)類型變?yōu)榭捎妙愋颓埃瑪?shù)據(jù)隊(duì)列不接受數(shù)據(jù)注入,且不進(jìn)行計(jì)算;
    • 3)數(shù)據(jù)隊(duì)列的數(shù)據(jù)變化觸發(fā)質(zhì)量計(jì)算,出于資源開(kāi)銷考慮,要限制計(jì)算的頻次,我們采用計(jì)算間隔和新增數(shù)據(jù)量?jī)蓚€(gè)閾值限制,計(jì)算間隔大于60s或者新增數(shù)據(jù)量超過(guò)10條才會(huì)觸發(fā)計(jì)算;同時(shí)也暴露了對(duì)外接口,業(yè)務(wù)可按需強(qiáng)制刷新計(jì)算結(jié)果;
    • 4)關(guān)于主動(dòng)網(wǎng)絡(luò)探測(cè),可結(jié)合自身的業(yè)務(wù)需求按需實(shí)現(xiàn),目前攜程的APP在使用時(shí)網(wǎng)絡(luò)數(shù)據(jù)更新比較頻繁,無(wú)需補(bǔ)充主動(dòng)探測(cè)數(shù)據(jù)。

    8.3 弱網(wǎng)閾值制定

    模型核心的計(jì)算邏輯,就是將加工后得到的各網(wǎng)絡(luò)指標(biāo)與對(duì)應(yīng)的弱網(wǎng)閾值進(jìn)行對(duì)比,從而獲得是否進(jìn)入弱網(wǎng)的結(jié)果。

    關(guān)于弱網(wǎng)閾值的制定上,我們經(jīng)歷了如下兩個(gè)階段:

    1)第一階段:

    主要參考NQE EFFECTIVE_CONNECTION_TYPE_2G 的閾值定義:

    • 1)HttpRTT > 1726ms;
    • 2)TransportRTT > 1531ms;
    • 3)成功率按照內(nèi)部討論的預(yù)期設(shè)置為 NetworkSuccessRate < 90%;
    • 4)成功率趨勢(shì)閾值設(shè)置為 SuccessRateTrend < 0.1,即成功率連續(xù)向好增加超過(guò)10pp,即使成功率小于90%,也從Bad切換為Good,這個(gè)指標(biāo)主要是為了提升Bad切Good的速度。

    2)第二階段:

    我們通過(guò)線上的網(wǎng)絡(luò)質(zhì)量分布監(jiān)控,和一些具體case的分析,不斷迭代我們的閾值,我們需要制定一個(gè)識(shí)別準(zhǔn)確率的指標(biāo)來(lái)指引閾值的調(diào)整工作,達(dá)到邏輯準(zhǔn)確與自洽。

    理論上:我們希望識(shí)別模型的入?yún)⑴c當(dāng)下計(jì)算出的網(wǎng)絡(luò)質(zhì)量類型所匹配,例如當(dāng)前注入NQEMetrics數(shù)據(jù)的HttpRTT <= 1726ms ,那我們預(yù)期當(dāng)前計(jì)算出的網(wǎng)絡(luò)質(zhì)量類型就是Good。但是弱網(wǎng)的決策邏輯是相對(duì)復(fù)雜的,需要考慮到各種因素,以

    下兩點(diǎn)會(huì)造成弱網(wǎng)狀態(tài)下的入?yún)?shù)據(jù)不一定符合弱網(wǎng)閾值定義:

    • 1)弱網(wǎng)的計(jì)算是對(duì)過(guò)去已經(jīng)發(fā)生網(wǎng)絡(luò)行為的分析,具有一定的滯后性,所以在識(shí)別結(jié)果切換附近,必然有部分的原數(shù)據(jù)已經(jīng)滿足下一階段的網(wǎng)絡(luò)質(zhì)量定義;
    • 2)弱網(wǎng)的決策是對(duì)多個(gè)指標(biāo)的復(fù)合計(jì)算,所以在識(shí)別到弱網(wǎng)狀態(tài)時(shí),不一定所有的指標(biāo)原數(shù)據(jù)都符合弱網(wǎng)定義,比如由HttpRTT觸發(fā)弱網(wǎng)時(shí),當(dāng)前的TransportRTT數(shù)據(jù)可能表現(xiàn)良好。

    終上兩點(diǎn)原因,弱網(wǎng)分類下必然有一定的非弱網(wǎng)數(shù)據(jù),這里的誤差數(shù)據(jù)占比與識(shí)別準(zhǔn)確率負(fù)相關(guān),誤差數(shù)據(jù)占比越低,識(shí)別準(zhǔn)確率越高。所以想到這里,我們的模型識(shí)別準(zhǔn)確率的指標(biāo)計(jì)算口徑就有了:

    模型弱網(wǎng)識(shí)別準(zhǔn)確性 = 100% - 弱網(wǎng)狀態(tài)下不符合弱網(wǎng)閾值定義原數(shù)據(jù)占比

    有了這個(gè)指標(biāo)指引,我們?cè)谀P蜕暇€后進(jìn)行了數(shù)個(gè)版本的數(shù)據(jù)統(tǒng)計(jì),通過(guò)各指標(biāo)閾值的微調(diào)和case by case解決異常場(chǎng)景,誤差數(shù)據(jù)從剛上線的15%+降低到10%以下,即模型識(shí)別準(zhǔn)確率優(yōu)化至90%以上。

    最終攜程90%準(zhǔn)確率的模型對(duì)應(yīng)的弱網(wǎng)閾值如下(不同業(yè)務(wù)場(chǎng)景的網(wǎng)絡(luò)請(qǐng)求差別較大,僅供大家參考):

    • 1)HttpRTT > 1220ms;這個(gè)值是線上HttpRTT的TP98值,與弱網(wǎng)占比相近;
    • 2)TransportRTT > 520ms;同線上TP98值;
    • 3)NetworkSuccessRate < 90%;
    • 4)SuccessRateTrend < 0.2;之前的0.1導(dǎo)致模型的結(jié)果切換過(guò)于頻繁,最終調(diào)整到了0.2。

    Tips:對(duì)于類似攜程這種自定義的弱網(wǎng)識(shí)別模型,弱網(wǎng)標(biāo)準(zhǔn)也是考慮業(yè)務(wù)現(xiàn)狀的定制標(biāo)準(zhǔn),所以不需要太多和外部的弱網(wǎng)標(biāo)準(zhǔn)對(duì)齊,重點(diǎn)是自洽和符合業(yè)務(wù)預(yù)期。

    9、落地效果

    考慮到識(shí)別模型要支持多平臺(tái)(iOS、Android、Harmony等),所以我們?cè)谝婚_(kāi)始實(shí)現(xiàn)方案時(shí)就采用了C++作為開(kāi)發(fā)語(yǔ)言,天然支持了多平臺(tái),各平臺(tái)只需要實(shí)現(xiàn)上層數(shù)據(jù)采集和注入模型的少量邏輯即可完成模型的接入。相同的代碼實(shí)現(xiàn)和弱網(wǎng)標(biāo)準(zhǔn),也方便我們?cè)诓煌钠脚_(tái)間直接對(duì)標(biāo)數(shù)據(jù),發(fā)現(xiàn)各平臺(tái)的問(wèn)題針對(duì)性優(yōu)化。

    目前攜程的網(wǎng)絡(luò)質(zhì)量識(shí)別模型,已經(jīng)在iOS、Android平臺(tái)完成接入并大面積投產(chǎn),網(wǎng)絡(luò)質(zhì)量數(shù)據(jù)與集團(tuán)的APM監(jiān)控平臺(tái)打通,形成了攜程官方統(tǒng)一的網(wǎng)絡(luò)質(zhì)量標(biāo)準(zhǔn),在網(wǎng)絡(luò)排障、框架網(wǎng)絡(luò)優(yōu)化、業(yè)務(wù)網(wǎng)絡(luò)優(yōu)化等多種場(chǎng)景下扮演重要角色,弱網(wǎng)優(yōu)化相關(guān)的內(nèi)容我們會(huì)在后面相關(guān)的專題內(nèi)繼續(xù)分享,此處不再贅述。

    最終網(wǎng)絡(luò)質(zhì)量相關(guān)的分布數(shù)據(jù)如下(數(shù)據(jù)為實(shí)驗(yàn)采集,不代表攜程真實(shí)業(yè)務(wù)情況,僅參考)。

    網(wǎng)絡(luò)質(zhì)量分布:

    各網(wǎng)絡(luò)質(zhì)量下對(duì)應(yīng)的請(qǐng)求性能數(shù)據(jù):

    10、未來(lái)展望

    網(wǎng)絡(luò)質(zhì)量識(shí)別模型的完成只是我們網(wǎng)絡(luò)優(yōu)化的開(kāi)始,后續(xù)還有很多的工作需要我們繼續(xù)努力。

    未來(lái)一段時(shí)間我們會(huì)從以下幾個(gè)方面繼續(xù)推進(jìn):

    1)持續(xù)推進(jìn)各平臺(tái)、各獨(dú)立APP的網(wǎng)絡(luò)質(zhì)量識(shí)別模型接入,完成攜程終端全平臺(tái)的網(wǎng)絡(luò)質(zhì)量模型覆蓋。

    2)做好識(shí)別模型的防劣化工作,解決各業(yè)務(wù)場(chǎng)景的bad case,堅(jiān)守現(xiàn)階段識(shí)別準(zhǔn)確率和實(shí)時(shí)性的標(biāo)準(zhǔn)水位。

    3)推出攜程內(nèi)部的“網(wǎng)絡(luò)性能白皮書”,從APP、系統(tǒng)平臺(tái)、網(wǎng)絡(luò)質(zhì)量、成功率、全鏈路耗時(shí)等各維度解析公司內(nèi)部各業(yè)務(wù)線的網(wǎng)絡(luò)表現(xiàn),形成內(nèi)部的網(wǎng)絡(luò)性能數(shù)據(jù)基線,為業(yè)務(wù)優(yōu)化提供參考。

    4)借助現(xiàn)有的弱網(wǎng)標(biāo)準(zhǔn)和識(shí)別能力,從網(wǎng)絡(luò)框架側(cè)和業(yè)務(wù)側(cè)兩個(gè)不同的角度進(jìn)行弱網(wǎng)優(yōu)化,提高整體網(wǎng)絡(luò)表現(xiàn);當(dāng)下海外市場(chǎng)是業(yè)務(wù)發(fā)力的重點(diǎn),海外場(chǎng)景的網(wǎng)絡(luò)表現(xiàn)也明顯弱于國(guó)內(nèi),我們會(huì)針對(duì)海外場(chǎng)景從弱網(wǎng)的角度進(jìn)行重點(diǎn)優(yōu)化。

    攜程目前已經(jīng)針對(duì)弱網(wǎng)場(chǎng)景推出了一系列優(yōu)化策略,部分策略已經(jīng)取得非常不錯(cuò)的收益,后續(xù)我們會(huì)繼續(xù)推進(jìn),也會(huì)持續(xù)分享輸出。

    11、參考資料

    [1] TCP/IP詳解 - 第17章·TCP:傳輸控制協(xié)議

    [2] 快速理解TCP協(xié)議一篇就夠

    [3] 新手入門一篇就夠:從零開(kāi)發(fā)移動(dòng)端IM

    [3] 騰訊原創(chuàng)分享(二):如何大幅壓縮移動(dòng)網(wǎng)絡(luò)下APP的流量消耗(上篇)

    [4] 深入淺出,全面理解HTTP協(xié)議

    [5] 快速讀懂Http/3協(xié)議,一篇就夠!

    [6] 技術(shù)掃盲:新一代基于UDP的低延時(shí)網(wǎng)絡(luò)傳輸層協(xié)議——QUIC詳解

    [7] 冰山之下,一次網(wǎng)絡(luò)請(qǐng)求背后的技術(shù)秘密

    [8] 通俗易懂,理解移動(dòng)網(wǎng)絡(luò)的“弱”和“慢”

    [9] 史上最全移動(dòng)弱網(wǎng)絡(luò)優(yōu)化方法總結(jié)

    [10] 愛(ài)奇藝APP網(wǎng)絡(luò)優(yōu)化實(shí)踐(網(wǎng)絡(luò)請(qǐng)求成功率優(yōu)化篇)

    [11] 美團(tuán)點(diǎn)評(píng)的網(wǎng)絡(luò)優(yōu)化實(shí)踐(大幅提升連接成功率、速度等)

    [12] 淘寶移動(dòng)端統(tǒng)一網(wǎng)絡(luò)庫(kù)的架構(gòu)演進(jìn)和弱網(wǎng)優(yōu)化實(shí)踐

    [13] 愛(ài)奇藝APP跨國(guó)弱網(wǎng)通信的優(yōu)化實(shí)踐

    [14] 得物自研移動(dòng)端弱網(wǎng)診斷工具的技術(shù)實(shí)踐


    (本文已同步發(fā)布于:http://www.52im.net/thread-4737-1-1.html



    作者:Jack Jiang (點(diǎn)擊作者姓名進(jìn)入Github)
    出處:http://www.52im.net/space-uid-1.html
    交流:歡迎加入即時(shí)通訊開(kāi)發(fā)交流群 215891622
    討論:http://www.52im.net/
    Jack Jiang同時(shí)是【原創(chuàng)Java Swing外觀工程BeautyEye】【輕量級(jí)移動(dòng)端即時(shí)通訊框架MobileIMSDK】的作者,可前往下載交流。
    本博文 歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明出處(也可前往 我的52im.net 找到我)。


    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    Jack Jiang的 Mail: jb2011@163.com, 聯(lián)系QQ: 413980957, 微信: hellojackjiang
    主站蜘蛛池模板: 一区二区免费在线观看| 国产产在线精品亚洲AAVV| 亚洲精品福利网站| 亚洲短视频在线观看| 亚洲AV无码片一区二区三区 | 亚洲AV无码国产丝袜在线观看| 国产亚洲福利精品一区| 亚洲国产精品自在在线观看| 亚洲小视频在线观看| 亚洲成av人片在线天堂无| 黄色一级毛片免费看| 在线观看免费无码视频| 24小时免费看片| 青草草在线视频永久免费| 亚洲国产午夜福利在线播放| 国产AV无码专区亚洲AV毛网站 | 一本一道dvd在线观看免费视频| 青青操在线免费观看| 免费毛片a在线观看67194| 国产又粗又长又硬免费视频| 亚洲一区无码精品色| 亚洲国产精品久久久久久| 国产亚洲视频在线观看网址| 成年黄网站色大免费全看| 国产免费观看黄AV片| 亚洲精品无码成人AAA片| 亚洲精品国产高清在线观看| 久久国产色AV免费观看| 免费高清在线影片一区| 亚洲宅男永久在线| 久久亚洲精品高潮综合色a片| 91精品免费不卡在线观看| 亚洲欧洲自拍拍偷精品 美利坚| 亚洲无mate20pro麻豆| 成年网在线观看免费观看网址| 免费观看的毛片大全| 亚洲国产女人aaa毛片在线| 三年片在线观看免费观看大全中国| 在线A级毛片无码免费真人 | 久久久久久a亚洲欧洲AV| 亚洲欧美日韩一区二区三区在线|