偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

高并發(fā)場(chǎng)景下,TCP/UDP丟包的隱藏陷阱

網(wǎng)絡(luò) 網(wǎng)絡(luò)優(yōu)化
socket 是應(yīng)用程序與網(wǎng)絡(luò)之間的接口,合理設(shè)置 socket 參數(shù)可以顯著提升 UDP 傳輸?shù)姆€(wěn)定性。設(shè)置合適的 socket 接收緩沖區(qū)大小至關(guān)重要。

在網(wǎng)絡(luò)的世界里,網(wǎng)絡(luò)丟包就像一顆隨時(shí)可能引爆的炸彈,讓看似堅(jiān)固的網(wǎng)絡(luò)連接瞬間陷入混亂。大家想必都有過(guò)這樣的經(jīng)歷:滿心歡喜地加載網(wǎng)頁(yè),卻只等來(lái)一片空白;興致勃勃地玩在線游戲,角色卻突然卡頓,操作嚴(yán)重延遲;商務(wù)洽談的視頻會(huì)議中,聲音和畫(huà)面斷斷續(xù)續(xù),溝通變得異常艱難。這些糟糕體驗(yàn)的背后,往往是網(wǎng)絡(luò)丟包在作祟。

數(shù)據(jù)傳輸本應(yīng)如絲般順滑,可現(xiàn)實(shí)卻常因丟包變得磕磕絆絆。在復(fù)雜的網(wǎng)絡(luò)架構(gòu)中,從內(nèi)核調(diào)度,到網(wǎng)絡(luò)協(xié)議棧的層層處理,再到網(wǎng)卡與網(wǎng)線間的信號(hào)交互,任何一個(gè)環(huán)節(jié)出現(xiàn)故障,都可能導(dǎo)致丟包,就像一條環(huán)環(huán)相扣的精密鏈條,一旦有一環(huán)斷裂,整個(gè)傳輸過(guò)程就會(huì)受阻。今天,就讓我們一同深入網(wǎng)絡(luò)底層,從內(nèi)核的核心運(yùn)作,到網(wǎng)卡的物理收發(fā),沿著數(shù)據(jù)傳輸?shù)穆窂剑娌鸾饩W(wǎng)絡(luò)丟包的全鏈路,探尋其背后的真相與解決之道,為構(gòu)建穩(wěn)定高效的網(wǎng)絡(luò)連接筑牢根基。

Part1.TCP 協(xié)議丟包原因

盡管 TCP 能夠在不可靠的網(wǎng)絡(luò)環(huán)境下實(shí)現(xiàn)可靠傳輸,但數(shù)據(jù)掉包的情況依然可能發(fā)生。當(dāng)在通信過(guò)程中檢測(cè)到數(shù)據(jù)缺失或丟包時(shí),問(wèn)題最有可能出在數(shù)據(jù)的發(fā)送或接收環(huán)節(jié)。

舉例來(lái)說(shuō),當(dāng)服務(wù)端需要向客戶端傳輸大量數(shù)據(jù),并以高頻次調(diào)用 Send 函數(shù)進(jìn)行發(fā)送時(shí),Send 操作很容易出現(xiàn)異常。這些異??赡茉从诙鄠€(gè)方面,比如程序的處理邏輯存在缺陷,或是多線程環(huán)境下的同步機(jī)制不完善,亦或是發(fā)生了緩沖區(qū)溢出等情況。倘若程序沒(méi)有對(duì) Send 操作的失敗情況進(jìn)行妥善處理,客戶端實(shí)際接收到的數(shù)據(jù)量就會(huì)少于預(yù)期,進(jìn)而引發(fā)數(shù)據(jù)丟失和丟包問(wèn)題。

1.1應(yīng)用層程序處理不當(dāng)

在網(wǎng)絡(luò)通信中,應(yīng)用層程序就像是這場(chǎng)數(shù)據(jù)傳輸大戲的導(dǎo)演,它的一舉一動(dòng)都至關(guān)重要。如果導(dǎo)演 “指揮失誤”,就可能導(dǎo)致數(shù)據(jù)傳輸出現(xiàn)問(wèn)題,丟包也就隨之而來(lái)。比如,程序邏輯錯(cuò)誤就是一個(gè)常見(jiàn)的 “坑”。假設(shè)一個(gè)文件傳輸程序,在計(jì)算需要發(fā)送的數(shù)據(jù)量時(shí)出現(xiàn)了錯(cuò)誤,少算了一部分?jǐn)?shù)據(jù),那么這部分?jǐn)?shù)據(jù)就會(huì)被遺漏,接收方自然也就無(wú)法完整地收到文件,這就相當(dāng)于在數(shù)據(jù)傳輸?shù)奈枧_(tái)上,某些重要的 “演員” 被遺漏了。

多線程同步問(wèn)題也是導(dǎo)致丟包的一個(gè)重要因素。在多線程環(huán)境下,不同線程可能同時(shí)訪問(wèn)和修改共享資源,如果沒(méi)有正確的同步機(jī)制,就會(huì)出現(xiàn)數(shù)據(jù)競(jìng)爭(zhēng)和不一致的情況。想象一下,有多個(gè)線程同時(shí)向 TCP 連接中寫(xiě)入數(shù)據(jù),由于沒(méi)有協(xié)調(diào)好順序,可能會(huì)導(dǎo)致部分?jǐn)?shù)據(jù)被覆蓋或者丟失。就好像一場(chǎng)接力比賽,幾個(gè)運(yùn)動(dòng)員同時(shí)拿著接力棒往前跑,卻不知道該把接力棒交給誰(shuí),結(jié)果比賽就亂套了,數(shù)據(jù)傳輸也會(huì)出錯(cuò)。

緩沖區(qū)溢出更是一個(gè)危險(xiǎn)的 “陷阱”。當(dāng)應(yīng)用層程序向 TCP 發(fā)送緩沖區(qū)寫(xiě)入的數(shù)據(jù)量超過(guò)了緩沖區(qū)的容量時(shí),就會(huì)發(fā)生緩沖區(qū)溢出。這就好比一個(gè)杯子已經(jīng)裝滿了水,你還在不斷往里倒水,多余的水就會(huì)溢出來(lái),而溢出的數(shù)據(jù)就可能丟失。例如,在一個(gè)視頻直播應(yīng)用中,如果發(fā)送端的緩沖區(qū)設(shè)置過(guò)小,而視頻數(shù)據(jù)的產(chǎn)生速度又很快,就很容易導(dǎo)致緩沖區(qū)溢出,從而造成丟包,觀眾看到的視頻就會(huì)出現(xiàn)卡頓、花屏等現(xiàn)象。

使用TCP socket進(jìn)行網(wǎng)絡(luò)編程的時(shí)候,內(nèi)核都會(huì)分配一個(gè)發(fā)送緩沖區(qū)和一個(gè)接收緩沖區(qū)。

當(dāng)我們想要發(fā)一個(gè)數(shù)據(jù)包,會(huì)在代碼里執(zhí)行send(msg),這時(shí)候數(shù)據(jù)包并不是一把梭直接就走網(wǎng)卡飛出去的。而是將數(shù)據(jù)拷貝到內(nèi)核發(fā)送緩沖區(qū)。而接收緩沖區(qū)作用也類似,從外部網(wǎng)絡(luò)收到的數(shù)據(jù)包就暫存在這個(gè)地方,然后坐等用戶空間的應(yīng)用程序?qū)?shù)據(jù)包取走。

當(dāng)接受緩沖區(qū)滿了,它的TCP接收窗口會(huì)變?yōu)?,也就是所謂的零窗口,并且會(huì)通過(guò)數(shù)據(jù)包里的win=0,告訴發(fā)送端。一般這種情況下,發(fā)送端就該停止發(fā)消息了,但如果這時(shí)候確實(shí)還有數(shù)據(jù)發(fā)來(lái),就會(huì)發(fā)生丟包。

1.2網(wǎng)絡(luò)狀況不佳

網(wǎng)絡(luò)就像是數(shù)據(jù)傳輸?shù)母咚俟罚W(wǎng)絡(luò)狀況不佳就如同高速公路上出現(xiàn)了擁堵、事故或者路況變差等情況,這些都會(huì)嚴(yán)重影響數(shù)據(jù)的傳輸,導(dǎo)致 TCP 丟包。

網(wǎng)絡(luò)擁塞是導(dǎo)致丟包的一個(gè)常見(jiàn)原因。當(dāng)網(wǎng)絡(luò)中的數(shù)據(jù)流量過(guò)大,超過(guò)了網(wǎng)絡(luò)的承載能力時(shí),就會(huì)發(fā)生擁塞。想象一下,高速公路上突然涌入了大量的車輛,道路變得擁擠不堪,車輛行駛速度變慢,甚至停滯不前。在網(wǎng)絡(luò)中也是如此,當(dāng)數(shù)據(jù)包大量涌入路由器等網(wǎng)絡(luò)設(shè)備時(shí),設(shè)備的緩沖區(qū)會(huì)被填滿,新到達(dá)的數(shù)據(jù)包就會(huì)被丟棄。例如,在大型網(wǎng)絡(luò)購(gòu)物節(jié)期間,大量用戶同時(shí)訪問(wèn)電商網(wǎng)站,網(wǎng)絡(luò)流量劇增,就容易出現(xiàn)網(wǎng)絡(luò)擁塞,導(dǎo)致用戶在瀏覽商品、下單支付等過(guò)程中出現(xiàn)頁(yè)面加載緩慢、操作失敗等情況,這背后可能就是 TCP 丟包在作祟。

高延遲也會(huì)對(duì) TCP 傳輸產(chǎn)生負(fù)面影響。網(wǎng)絡(luò)延遲是指數(shù)據(jù)包從發(fā)送端到接收端所需要的時(shí)間。當(dāng)網(wǎng)絡(luò)延遲過(guò)高時(shí),TCP 的重傳機(jī)制可能會(huì)被頻繁觸發(fā)。比如,發(fā)送端發(fā)送一個(gè)數(shù)據(jù)包后,由于延遲過(guò)大,接收端不能及時(shí)確認(rèn)收到,發(fā)送端就會(huì)認(rèn)為數(shù)據(jù)包丟失,從而重新發(fā)送。如果這種情況反復(fù)發(fā)生,不僅會(huì)增加網(wǎng)絡(luò)負(fù)擔(dān),還可能導(dǎo)致部分?jǐn)?shù)據(jù)包因?yàn)橹貍鞒瑫r(shí)被丟棄。就像你寄一封重要的信件,對(duì)方很久都沒(méi)有收到,你只能不斷地重寄,而在這個(gè)過(guò)程中,信件可能會(huì)因?yàn)楦鞣N原因丟失。

鏈路故障則是更為嚴(yán)重的問(wèn)題。網(wǎng)絡(luò)鏈路就如同高速公路的路段,如果某段鏈路出現(xiàn)故障,比如光纖被切斷、網(wǎng)線損壞等,那么數(shù)據(jù)就無(wú)法通過(guò)這條鏈路傳輸,必然會(huì)導(dǎo)致丟包。例如,在城市建設(shè)過(guò)程中,如果施工不小心挖斷了光纖,那么依賴這條光纖傳輸數(shù)據(jù)的網(wǎng)絡(luò)服務(wù)就會(huì)中斷,TCP 連接也會(huì)因?yàn)闊o(wú)法傳輸數(shù)據(jù)而丟包。

1.3 TCP自身機(jī)制局限

盡管 TCP 協(xié)議設(shè)計(jì)了一系列精妙的機(jī)制來(lái)保證數(shù)據(jù)傳輸?shù)目煽啃?,但在一些極端情況下,這些機(jī)制也會(huì)存在局限性,從而導(dǎo)致丟包。

TCP 的重傳機(jī)制是保證數(shù)據(jù)可靠傳輸?shù)闹匾侄危⒎侨f(wàn)無(wú)一失。當(dāng)網(wǎng)絡(luò)出現(xiàn)嚴(yán)重?fù)砣蛘唛L(zhǎng)時(shí)間的高延遲時(shí),重傳機(jī)制可能會(huì)陷入困境。比如,發(fā)送端不斷重傳數(shù)據(jù)包,但由于網(wǎng)絡(luò)狀況太差,這些重傳的數(shù)據(jù)包依然無(wú)法成功到達(dá)接收端,而發(fā)送端又不能無(wú)限制地重傳下去,最終可能會(huì)因?yàn)橹貍鞒瑫r(shí),導(dǎo)致部分?jǐn)?shù)據(jù)包被丟棄。就像你不斷地給朋友打電話,但信號(hào)一直不好,對(duì)方始終聽(tīng)不到你的聲音,你打了幾次后,可能就會(huì)放棄,而這個(gè)電話就相當(dāng)于被 “丟棄” 了。

擁塞控制機(jī)制在應(yīng)對(duì)復(fù)雜網(wǎng)絡(luò)環(huán)境時(shí)也可能出現(xiàn)問(wèn)題。TCP 通過(guò)調(diào)整發(fā)送窗口的大小來(lái)控制數(shù)據(jù)發(fā)送速率,以避免網(wǎng)絡(luò)擁塞。然而,在某些情況下,擁塞控制的調(diào)整可能不夠及時(shí)或者不夠準(zhǔn)確。比如,當(dāng)網(wǎng)絡(luò)突然出現(xiàn)短暫的擁塞時(shí),TCP 可能會(huì)過(guò)度降低發(fā)送窗口大小,導(dǎo)致數(shù)據(jù)傳輸速率大幅下降。而當(dāng)網(wǎng)絡(luò)恢復(fù)正常后,窗口大小的增加又比較緩慢,這就使得在一段時(shí)間內(nèi),數(shù)據(jù)傳輸效率低下,甚至可能因?yàn)榘l(fā)送窗口過(guò)小,無(wú)法及時(shí)發(fā)送數(shù)據(jù),導(dǎo)致數(shù)據(jù)包在發(fā)送端積壓,最終被丟棄。就像開(kāi)車時(shí),遇到前方有點(diǎn)擁堵,你就急剎車,等擁堵緩解了,你又慢悠悠地加速,結(jié)果不僅浪費(fèi)了時(shí)間,還可能影響后面車輛的通行,在網(wǎng)絡(luò)中,這就表現(xiàn)為丟包。

1.4三次握手時(shí)丟包

這個(gè)主要是由用戶的listen的backlog參數(shù)決定的一個(gè)信息。其中的backlog表示可以有多少個(gè)連接完成三次握手而不執(zhí)行accept,如果大于該值,則三次握手不能完成,這是一個(gè)準(zhǔn)確值。相對(duì)來(lái)說(shuō)還有個(gè)大概值,這個(gè)值也是根據(jù)backlog參數(shù)計(jì)算得到,只是按照2的冪數(shù)取整了,例如backlog為5,該值可能為8。它用來(lái)控制一個(gè)套接口可以同時(shí)最多接收多少個(gè)連接請(qǐng)求,這個(gè)請(qǐng)求準(zhǔn)確的說(shuō)是第一次握手,這個(gè)數(shù)值其實(shí)是和accept的限量是獨(dú)立的。極端情況下,以listen參數(shù)為5說(shuō)明,第一次握手可以有8個(gè)完成,而三次握手可以有5個(gè)。

①listen之backlog參數(shù)處理

inet_listen -->>>sk->sk_max_ack_backlog = backlog;這里的數(shù)值是對(duì)于完成三次握手而沒(méi)有被accept的連接的限制。
inet_csk_listen_start--->>reqsk_queue_alloc
    for (lopt->max_qlen_log = 3;
         (1 << lopt->max_qlen_log) < nr_table_entries;
         lopt->max_qlen_log++);

該數(shù)值限制的是第一次握手的回應(yīng)數(shù)量。

②第一次握手處理

int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
    /* TW buckets are converted to open requests without
     * limitations, they conserve resources and peer is
     * evidently real one.
     */
    if (inet_csk_reqsk_queue_is_full(sk) && !isn) {這里判斷l(xiāng)isten中可以完成第一次握手的數(shù)量,如果大于限量,丟掉報(bào)文。
#ifdef CONFIG_SYN_COOKIES
        if (sysctl_tcp_syncookies) {
            want_cookie = 1;
        } else
#endif
        goto drop;
    }

    /* Accept backlog is full. If we have already queued enough
     * of warm entries in syn queue, drop request. It is better than
     * clogging syn queue with openreqs with exponentially increasing
     * timeout.
     */
    if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)這里的young表示系統(tǒng)中還沒(méi)有被重傳的sync回應(yīng)套接口。
        goto drop;
……
drop:
    return 0;

這里的連接丟掉并沒(méi)有記錄任何信息,所以我們并不知道系統(tǒng)拒絕了多少三次握手的第一次請(qǐng)求。

③第三次握手回應(yīng)時(shí)丟包

struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                  struct request_sock *req,
                  struct dst_entry *dst)
{
    struct inet_request_sock *ireq;
    struct inet_sock *newinet;
    struct tcp_sock *newtp;
    struct sock *newsk;
#ifdef CONFIG_TCP_MD5SIG
    struct tcp_md5sig_key *key;
#endif

    if (sk_acceptq_is_full(sk))
        goto exit_overflow;
……
exit_overflow:
    NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS);
exit:
    NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS);

此時(shí)該信息有記錄,可以通過(guò)/proc/net/snmp查看該信息。

Part2.UDP 協(xié)議丟包原因

UDP丟包主要存在于接收端無(wú)法及時(shí)處理對(duì)方發(fā)送的數(shù)據(jù),這些數(shù)據(jù)以報(bào)文的形式在系統(tǒng)中暫時(shí)存儲(chǔ),但是如果這些未接受的報(bào)文太多,操作系統(tǒng)就會(huì)將新到來(lái)的報(bào)文丟掉,從而避免一個(gè)套接口對(duì)整個(gè)系統(tǒng)資源耗光;這個(gè)邏輯和思路都比較簡(jiǎn)單,也是因?yàn)閁DP本身是一個(gè)相對(duì)比較簡(jiǎn)單的傳輸控制協(xié)議。

這里大致看一下相關(guān)代碼:

__udp4_lib_rcv--->>>udp_queue_rcv_skb
    if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {
        /* Note that an ENOMEM error is charged twice */
        if (rc == -ENOMEM)
            UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, up->pcflag);
        goto drop;
    }
而接收函數(shù)中處理為
int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
    int err = 0;
    int skb_len;

    /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
       number of warnings when compiling with -W --ANK
     */
    if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
        (unsigned)sk->sk_rcvbuf) {
        err = -ENOMEM;
        goto out;
    }

這里如果達(dá)到一個(gè)套接口的限量,則返回錯(cuò)誤,上層記錄到UDP丟包狀態(tài)中,這個(gè)狀態(tài)可以通過(guò)/proc/net/snmp文件查看,例如我的系統(tǒng):

Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors
Udp: 672 0 0 670 0 0

這個(gè)功能在2.6.17--2.6.21之間的一個(gè)版本添加,小于2.6.17的版本一定沒(méi)有。

2.1無(wú)連接與不可靠特性

UDP 作為一種無(wú)連接的傳輸協(xié)議,就像一位瀟灑的獨(dú)行俠,在數(shù)據(jù)傳輸時(shí)無(wú)需與接收方建立像 TCP 那樣的三次握手連接。它只管將數(shù)據(jù)包一股腦地發(fā)送出去,卻不關(guān)心對(duì)方是否能夠成功接收,也不會(huì)像 TCP 那樣對(duì)數(shù)據(jù)包進(jìn)行確認(rèn)和重傳。這就好比你給朋友寄信,不確認(rèn)朋友是否收到,也不考慮信件是否會(huì)在途中丟失。這種特性使得 UDP 在傳輸過(guò)程中缺乏對(duì)數(shù)據(jù)包的有效管控,一旦網(wǎng)絡(luò)出現(xiàn)波動(dòng),數(shù)據(jù)包就很容易迷失在網(wǎng)絡(luò)的茫茫海洋中,從而導(dǎo)致丟包。例如,在實(shí)時(shí)視頻會(huì)議中,如果使用 UDP 傳輸視頻數(shù)據(jù),當(dāng)網(wǎng)絡(luò)信號(hào)不穩(wěn)定時(shí),部分視頻數(shù)據(jù)包可能會(huì)丟失,導(dǎo)致畫(huà)面出現(xiàn)卡頓、馬賽克等現(xiàn)象。

2.2緩沖區(qū)相關(guān)問(wèn)題

UDP 的接收緩沖區(qū)就像是一個(gè)有限容量的小倉(cāng)庫(kù),用來(lái)暫存接收到的數(shù)據(jù)包。當(dāng)發(fā)送方發(fā)送數(shù)據(jù)的速度過(guò)快,或者接收方處理數(shù)據(jù)的速度過(guò)慢時(shí),就會(huì)導(dǎo)致接收緩沖區(qū)被迅速填滿。此時(shí),新來(lái)的數(shù)據(jù)包就無(wú)處可放,只能被無(wú)情地丟棄,就像小倉(cāng)庫(kù)裝滿了貨物,新到的貨物只能被扔在外面。

如果緩沖區(qū)本身的容量設(shè)置得過(guò)小,而要接收的數(shù)據(jù)量又較大,比如要接收一個(gè)大文件,每個(gè)數(shù)據(jù)包都像一個(gè)個(gè)小包裹,小倉(cāng)庫(kù)根本裝不下這么多包裹,那么就會(huì)有部分?jǐn)?shù)據(jù)包因?yàn)闊o(wú)法進(jìn)入緩沖區(qū)而丟失。就好比你用一個(gè)小袋子去裝大量的物品,物品肯定裝不下,只能散落一地。在一些監(jiān)控視頻傳輸場(chǎng)景中,如果 UDP 接收緩沖區(qū)設(shè)置過(guò)小,而監(jiān)控視頻的數(shù)據(jù)量又很大,就容易出現(xiàn)丟包現(xiàn)象,導(dǎo)致監(jiān)控畫(huà)面不完整。

2.3發(fā)送策略不當(dāng)

發(fā)送策略不當(dāng)也是導(dǎo)致 UDP 丟包的一個(gè)重要原因。如果發(fā)送的 UDP 包過(guò)大,超過(guò)了網(wǎng)絡(luò)的最大傳輸單元(MTU),數(shù)據(jù)包就需要在網(wǎng)絡(luò)層進(jìn)行分片處理。想象一下,你要把一個(gè)超大的箱子通過(guò)狹窄的通道,就必須把箱子拆開(kāi)分成幾個(gè)小部分才能通過(guò)。在網(wǎng)絡(luò)中,數(shù)據(jù)包分片后,每個(gè)分片都需要獨(dú)立傳輸并在接收端重新組裝。但在這個(gè)過(guò)程中,如果有任何一個(gè)分片丟失,整個(gè)數(shù)據(jù)包就無(wú)法正確組裝,從而導(dǎo)致丟包。比如,在一個(gè)基于 UDP 的文件傳輸應(yīng)用中,如果發(fā)送的文件數(shù)據(jù)包過(guò)大,經(jīng)過(guò)網(wǎng)絡(luò)傳輸時(shí)被分片,一旦某個(gè)分片在傳輸過(guò)程中丟失,接收端就無(wú)法完整地恢復(fù)文件,導(dǎo)致文件傳輸失敗。

發(fā)送頻率過(guò)快同樣會(huì)引發(fā)問(wèn)題。當(dāng)發(fā)送方以極高的頻率發(fā)送 UDP 包時(shí),就像機(jī)關(guān)槍連續(xù)掃射一樣,接收方可能來(lái)不及處理如此大量的數(shù)據(jù)。這會(huì)導(dǎo)致接收緩沖區(qū)迅速被填滿,進(jìn)而引發(fā)丟包。比如在實(shí)時(shí)游戲中,如果玩家的操作頻繁,游戲客戶端向服務(wù)器發(fā)送大量的 UDP 數(shù)據(jù)包,而服務(wù)器處理能力有限,就可能出現(xiàn)丟包,導(dǎo)致玩家的操作指令無(wú)法及時(shí)傳達(dá)給服務(wù)器,游戲出現(xiàn)卡頓、延遲等情況。

Part3.TCP 丟包解決方案

3.1優(yōu)化應(yīng)用層程序

要解決應(yīng)用層程序處理不當(dāng)導(dǎo)致的丟包問(wèn)題,首先需要對(duì)程序邏輯進(jìn)行全面審查和優(yōu)化。開(kāi)發(fā)人員應(yīng)仔細(xì)檢查代碼,確保數(shù)據(jù)發(fā)送和接收的邏輯正確無(wú)誤??梢允褂脝卧獪y(cè)試、集成測(cè)試等手段,對(duì)程序的關(guān)鍵功能進(jìn)行驗(yàn)證,及時(shí)發(fā)現(xiàn)并修復(fù)潛在的邏輯錯(cuò)誤。對(duì)于多線程同步問(wèn)題,可以采用鎖機(jī)制、信號(hào)量、條件變量等同步工具,確保不同線程在訪問(wèn)共享資源時(shí)的順序和安全性。比如,在 Java 中,可以使用synchronized關(guān)鍵字來(lái)實(shí)現(xiàn)線程同步,或者使用ReentrantLock類提供更靈活的鎖控制。

針對(duì)緩沖區(qū)溢出問(wèn)題,合理設(shè)置緩沖區(qū)大小至關(guān)重要??梢愿鶕?jù)應(yīng)用場(chǎng)景和數(shù)據(jù)量的預(yù)估,動(dòng)態(tài)調(diào)整緩沖區(qū)的大小。例如,在一個(gè)網(wǎng)絡(luò)爬蟲(chóng)程序中,根據(jù)目標(biāo)網(wǎng)站的頁(yè)面大小和下載頻率,設(shè)置合適的接收緩沖區(qū)大小,避免因?yàn)榫彌_區(qū)過(guò)小而導(dǎo)致數(shù)據(jù)丟失。同時(shí),要建立有效的緩沖區(qū)管理機(jī)制,及時(shí)清理已處理的數(shù)據(jù),釋放緩沖區(qū)空間。

3.2調(diào)整 TCP 參數(shù)

調(diào)整 TCP 參數(shù)是解決丟包問(wèn)題的重要手段之一。重傳次數(shù)和超時(shí)時(shí)間是兩個(gè)關(guān)鍵參數(shù)。在 Linux 系統(tǒng)中,可以通過(guò)修改/etc/sysctl.conf文件來(lái)調(diào)整相關(guān)參數(shù)。比如,增加重傳次數(shù)可以通過(guò)設(shè)置net.ipv4.tcp_retries2的值來(lái)實(shí)現(xiàn),默認(rèn)值可能是 15,根據(jù)網(wǎng)絡(luò)情況,可以適當(dāng)增大這個(gè)值,以提高在網(wǎng)絡(luò)不穩(wěn)定情況下的可靠性。而調(diào)整超時(shí)時(shí)間則可以通過(guò)修改net.ipv4.tcp_retries1(首次重傳超時(shí)時(shí)間)和net.ipv4.tcp_retries2(最大重傳超時(shí)時(shí)間)等參數(shù)來(lái)實(shí)現(xiàn)。選擇合適的擁塞控制算法也能有效提升網(wǎng)絡(luò)性能。

不同的擁塞控制算法適用于不同的網(wǎng)絡(luò)環(huán)境。Linux 內(nèi)核支持多種 TCP 擁塞控制算法,如 CUBIC、BBR 和 RENO。CUBIC 算法是 Linux 的默認(rèn)算法,它在大多數(shù)網(wǎng)絡(luò)環(huán)境下都能表現(xiàn)出較好的性能;BBR 算法則適合高帶寬、低延遲的網(wǎng)絡(luò)環(huán)境,它能夠更準(zhǔn)確地探測(cè)網(wǎng)絡(luò)帶寬和延遲,從而實(shí)現(xiàn)更高效的數(shù)據(jù)傳輸??梢酝ㄟ^(guò)sysctl命令來(lái)查看和設(shè)置當(dāng)前的擁塞控制算法,如sysctl net.ipv4.tcp_congestion_control查看當(dāng)前算法,sysctl -w net.ipv4.tcp_congestion_cnotallow=bbr將算法設(shè)置為 BBR。

⑴增加重傳次數(shù)和超時(shí)時(shí)間:可以通過(guò)調(diào)整內(nèi)核參數(shù)來(lái)增加 TCP 的重傳次數(shù)和超時(shí)時(shí)間,以提高在網(wǎng)絡(luò)不穩(wěn)定情況下的可靠性

# 增加重傳次數(shù)
sudo sysctl -w net.ipv4.tcp_retries2=15

# 增加超時(shí)時(shí)間
sudo sysctl -w net.ipv4.tcp_fin_timeout=30

⑵調(diào)整擁塞控制算法:選擇合適的擁塞控制算法可以改善網(wǎng)絡(luò)性能。Linux 提供了多種擁塞控制算法,如reno、cubic、bbr等

# 查看當(dāng)前使用的擁塞控制算法
sysctl net.ipv4.tcp_congestion_control

# 設(shè)置為 BBR( Bottleneck Bandwidth and RTT)
sudo sysctl -w net.ipv4.tcp_congestion_cnotallow=bbr

3.3網(wǎng)絡(luò)優(yōu)化措施

改善網(wǎng)絡(luò)帶寬是解決丟包問(wèn)題的根本方法之一。可以通過(guò)升級(jí)網(wǎng)絡(luò)設(shè)備、增加網(wǎng)絡(luò)線路帶寬等方式來(lái)實(shí)現(xiàn)。例如,將老舊的百兆路由器升級(jí)為千兆路由器,或者將網(wǎng)絡(luò)帶寬從 100Mbps 提升到 1000Mbps 甚至更高,這樣可以有效提高網(wǎng)絡(luò)的傳輸能力,減少因帶寬不足導(dǎo)致的丟包。減少網(wǎng)絡(luò)擁塞需要合理規(guī)劃網(wǎng)絡(luò)流量??梢圆捎?QoS(Quality of Service,服務(wù)質(zhì)量)策略,對(duì)不同類型的流量進(jìn)行分類和優(yōu)先級(jí)設(shè)置。

使用網(wǎng)絡(luò)監(jiān)控工具(如 Wireshark、tcpdump)來(lái)監(jiān)控和分析網(wǎng)絡(luò)流量,及時(shí)發(fā)現(xiàn)和解決問(wèn)題。

# 使用 tcpdump 抓包
sudo tcpdump -i eth0 -w capture.pcap

比如,將語(yǔ)音、視頻等實(shí)時(shí)性要求高的流量設(shè)置為高優(yōu)先級(jí),確保它們?cè)诰W(wǎng)絡(luò)擁塞時(shí)能夠優(yōu)先傳輸,而將文件下載、郵件收發(fā)等對(duì)實(shí)時(shí)性要求較低的流量設(shè)置為低優(yōu)先級(jí)。在企業(yè)網(wǎng)絡(luò)中,可以使用流量整形技術(shù),限制某些應(yīng)用程序的帶寬使用,避免個(gè)別應(yīng)用占用過(guò)多帶寬導(dǎo)致其他應(yīng)用丟包。優(yōu)化網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)也能減少丟包。合理布局網(wǎng)絡(luò)設(shè)備,減少網(wǎng)絡(luò)層次和跳數(shù),能夠降低網(wǎng)絡(luò)延遲和丟包率。例如,在一個(gè)大型園區(qū)網(wǎng)絡(luò)中,采用分層的網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu),核心層負(fù)責(zé)高速數(shù)據(jù)交換,匯聚層將多個(gè)接入層設(shè)備連接到核心層,接入層為用戶提供網(wǎng)絡(luò)接入。通過(guò)合理規(guī)劃各層設(shè)備的連接和配置,可以提高網(wǎng)絡(luò)的可靠性和性能,減少丟包現(xiàn)象的發(fā)生。

Part4.UDP 丟包解決方案全解析

4.1前向糾錯(cuò)碼(FEC)技術(shù)

FEC 技術(shù)就像是一位未雨綢繆的智者,在數(shù)據(jù)傳輸這場(chǎng)旅途中提前為可能出現(xiàn)的意外做好準(zhǔn)備。其基本原理是在發(fā)送端對(duì)原始數(shù)據(jù)進(jìn)行編碼,生成冗余數(shù)據(jù),然后將原始數(shù)據(jù)和冗余數(shù)據(jù)一起發(fā)送給接收端。就好比你要寄一份重要文件,為了防止文件在運(yùn)輸過(guò)程中丟失部分內(nèi)容,你多復(fù)印了幾份關(guān)鍵頁(yè)面一起寄過(guò)去。在接收端,如果部分?jǐn)?shù)據(jù)丟失,就可以通過(guò)解碼過(guò)程,利用冗余數(shù)據(jù)來(lái)恢復(fù)丟失的數(shù)據(jù)。

在實(shí)際應(yīng)用中,F(xiàn)EC 技術(shù)有多種編碼方式,如奇偶校驗(yàn)碼、循環(huán)冗余校驗(yàn)(CRC)等。奇偶校驗(yàn)碼通過(guò)在數(shù)據(jù)中添加一位校驗(yàn)位,使數(shù)據(jù)中 1 的個(gè)數(shù)為奇數(shù)或偶數(shù),接收端根據(jù)校驗(yàn)位來(lái)判斷數(shù)據(jù)是否出錯(cuò);CRC 則是通過(guò)特定的算法對(duì)數(shù)據(jù)進(jìn)行計(jì)算,生成一個(gè)校驗(yàn)和,接收端通過(guò)驗(yàn)證校驗(yàn)和來(lái)判斷數(shù)據(jù)的完整性。以視頻會(huì)議為例,華為基于 FEC 技術(shù),通過(guò)配置流策略的方式,對(duì)報(bào)文丟包進(jìn)行優(yōu)化。它通過(guò)流分類攔截指定數(shù)據(jù)流,增加攜帶校驗(yàn)信息的冗余包,并在接收端進(jìn)行校驗(yàn)。如果網(wǎng)絡(luò)中出現(xiàn)了丟包或者報(bào)文損傷,則通過(guò)冗余包還原報(bào)文。這種技術(shù)相比 TCP 的重傳機(jī)制,不需要對(duì)報(bào)文重傳,實(shí)時(shí)性高,而且使用 RS 算法,相比 XOR 算法可以還原分組內(nèi)的多個(gè)丟包,從而抵抗網(wǎng)絡(luò)突發(fā)丟包。

然而,F(xiàn)EC 技術(shù)并非十全十美。它增加了數(shù)據(jù)傳輸?shù)难舆t和開(kāi)銷,因?yàn)橐珊蛡鬏斎哂鄶?shù)據(jù),這可能會(huì)影響傳輸效率。就像多寄的那些文件會(huì)增加郵寄的成本和時(shí)間。所以在實(shí)際應(yīng)用中,需要根據(jù)具體情況,如網(wǎng)絡(luò)帶寬、延遲要求等,來(lái)謹(jǐn)慎選擇是否使用 FEC 技術(shù)。

4.2應(yīng)用層重傳機(jī)制

由于 UDP 本身不具備可靠的重傳機(jī)制,在應(yīng)用層實(shí)現(xiàn)重傳機(jī)制就成為了保障數(shù)據(jù)可靠傳輸?shù)闹匾侄?。這就好比你和朋友約定通過(guò)快遞寄東西,快遞不保證一定能送到,那你就只能自己想辦法,如果朋友沒(méi)收到,你就再寄一次。

在應(yīng)用層實(shí)現(xiàn)重傳機(jī)制,通常需要發(fā)送方在發(fā)送數(shù)據(jù)包時(shí),記錄下每個(gè)數(shù)據(jù)包的發(fā)送時(shí)間和編號(hào),并啟動(dòng)一個(gè)定時(shí)器。當(dāng)接收方收到數(shù)據(jù)包后,會(huì)向發(fā)送方發(fā)送確認(rèn)消息。如果發(fā)送方在定時(shí)器超時(shí)之前沒(méi)有收到確認(rèn)消息,就認(rèn)為數(shù)據(jù)包丟失,會(huì)重新發(fā)送該數(shù)據(jù)包。為了避免不必要的重傳,還可以設(shè)置重傳次數(shù)的上限,當(dāng)重傳次數(shù)達(dá)到上限后,就不再重傳,而是向應(yīng)用程序報(bào)告丟包情況。比如在一些基于 UDP 的游戲應(yīng)用中,當(dāng)玩家操作指令發(fā)送后,如果服務(wù)器沒(méi)有及時(shí)確認(rèn)收到,客戶端就會(huì)在一定時(shí)間后重發(fā)該指令,確保服務(wù)器能接收到玩家的操作。但重傳機(jī)制也會(huì)帶來(lái)一些問(wèn)題,如增加網(wǎng)絡(luò)流量和延遲,因?yàn)橹貍鞯臄?shù)據(jù)包會(huì)占用額外的網(wǎng)絡(luò)帶寬,而且重傳過(guò)程需要時(shí)間,可能會(huì)導(dǎo)致數(shù)據(jù)傳輸?shù)难舆t增加。所以在設(shè)計(jì)重傳機(jī)制時(shí),需要合理設(shè)置重傳超時(shí)時(shí)間和重傳次數(shù),平衡數(shù)據(jù)可靠性和傳輸效率之間的關(guān)系。

4.3優(yōu)化接收端處理

優(yōu)化接收端的處理方式可以有效減少 UDP 丟包的影響。當(dāng)接收端收到 UDP 包后,不要立即進(jìn)行復(fù)雜的處理,而是先將包存入一個(gè)緩沖區(qū),就像把收到的快遞先放在一個(gè)暫存區(qū),然后迅速返回繼續(xù)接收新的數(shù)據(jù)包。這樣可以避免因?yàn)樘幚懋?dāng)前數(shù)據(jù)包而導(dǎo)致新到達(dá)的數(shù)據(jù)包被丟棄,保證接收的連續(xù)性。然后,再?gòu)木彌_區(qū)中取出數(shù)據(jù)包進(jìn)行處理,處理的速度要盡可能快,以減少緩沖區(qū)的積壓。

為了進(jìn)一步提高接收效率,可以采用多線程或異步處理的方式。多線程處理就像是安排多個(gè)工作人員同時(shí)處理緩沖區(qū)中的數(shù)據(jù)包,每個(gè)線程負(fù)責(zé)一部分工作,這樣可以加快處理速度,減少數(shù)據(jù)包在緩沖區(qū)中的停留時(shí)間。異步處理則是讓數(shù)據(jù)包的接收和處理在不同的線程或任務(wù)中進(jìn)行,接收線程專注于接收數(shù)據(jù)包,處理線程在空閑時(shí)從緩沖區(qū)中取出數(shù)據(jù)包進(jìn)行處理,兩者互不干擾,提高了系統(tǒng)的并發(fā)性能。在一個(gè)實(shí)時(shí)音頻傳輸應(yīng)用中,接收端可以使用多線程處理音頻數(shù)據(jù)包,一個(gè)線程負(fù)責(zé)接收音頻數(shù)據(jù)并存入緩沖區(qū),其他線程從緩沖區(qū)中取出數(shù)據(jù)進(jìn)行解碼和播放,確保音頻的流暢播放,減少因?yàn)閬G包導(dǎo)致的音頻卡頓現(xiàn)象。

4.4合理設(shè)置 socket 參數(shù)

socket 是應(yīng)用程序與網(wǎng)絡(luò)之間的接口,合理設(shè)置 socket 參數(shù)可以顯著提升 UDP 傳輸?shù)姆€(wěn)定性。設(shè)置合適的 socket 接收緩沖區(qū)大小至關(guān)重要。如果緩沖區(qū)過(guò)小,當(dāng)大量數(shù)據(jù)包快速到達(dá)時(shí),緩沖區(qū)很容易被填滿,導(dǎo)致新到達(dá)的數(shù)據(jù)包被丟棄。就像一個(gè)小倉(cāng)庫(kù),放不下太多貨物,多余的貨物就只能被拒之門(mén)外。可以通過(guò) setsockopt 函數(shù)來(lái)設(shè)置接收緩沖區(qū)大小,在 Linux 系統(tǒng)中,可以先查看系統(tǒng)默認(rèn)的 UDP 接收緩沖區(qū)大小,如通過(guò)cat /proc/sys/net/core/rmem_default查看默認(rèn)值,然后根據(jù)實(shí)際需求進(jìn)行調(diào)整。如果應(yīng)用程序需要接收大量的 UDP 數(shù)據(jù),可以適當(dāng)增大緩沖區(qū)大小,如設(shè)置為setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &recv_size, sizeof(recv_size));,其中recv_size為設(shè)置的緩沖區(qū)大小。

調(diào)整發(fā)送策略也是優(yōu)化的關(guān)鍵。避免發(fā)送過(guò)大的 UDP 包,要根據(jù)網(wǎng)絡(luò)的 MTU(最大傳輸單元)來(lái)合理控制數(shù)據(jù)包的大小??梢栽诎l(fā)送前對(duì)數(shù)據(jù)進(jìn)行分片處理,將大數(shù)據(jù)包拆分成多個(gè)小數(shù)據(jù)包進(jìn)行發(fā)送,確保每個(gè)數(shù)據(jù)包都能順利通過(guò)網(wǎng)絡(luò)。要控制發(fā)送頻率,避免發(fā)送過(guò)快導(dǎo)致接收端處理不過(guò)來(lái)??梢圆捎昧髁靠刂扑惴?,根據(jù)接收端的反饋信息動(dòng)態(tài)調(diào)整發(fā)送速率,使發(fā)送速率與接收端的處理能力相匹配。在一個(gè)基于 UDP 的遠(yuǎn)程監(jiān)控系統(tǒng)中,合理設(shè)置 socket 參數(shù),控制好數(shù)據(jù)包大小和發(fā)送頻率,能夠有效減少丟包現(xiàn)象,保證監(jiān)控畫(huà)面的實(shí)時(shí)性和穩(wěn)定性。

責(zé)任編輯:武曉燕 來(lái)源: 深度Linux
相關(guān)推薦

2025-02-28 00:03:22

高并發(fā)TPS系統(tǒng)

2025-02-26 03:00:00

2018-07-27 10:56:10

2023-07-18 09:24:04

MySQL線程

2021-01-13 05:27:02

服務(wù)器性能高并發(fā)

2025-06-05 01:22:00

SpringGateway高并發(fā)

2025-05-26 02:11:00

2023-10-07 08:54:28

項(xiàng)目httpPost對(duì)象

2024-08-29 09:32:36

2025-01-27 00:40:41

2025-03-31 10:42:31

2025-02-14 03:00:00

2025-01-03 09:56:09

2025-07-01 07:21:15

2025-07-09 04:00:00

Kafka億級(jí)流量高并發(fā)

2023-08-16 11:39:19

高并發(fā)調(diào)優(yōu)

2019-08-15 07:43:38

TCP網(wǎng)絡(luò)協(xié)議丟包

2025-09-18 08:53:20

2025-09-22 08:26:37

2020-10-15 06:26:24

高并發(fā)場(chǎng)景冰河
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)