V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
lrs
V2EX  ›  问与答

QUIC 协议基于 UDP, UDP 不可靠, QUIC 如何保证可靠性的呢

  •  1
     
  •   lrs · 2021-05-19 10:40:14 +08:00 · 6020 次点击
    这是一个创建于 1277 天前的主题,其中的信息可能已经有所发展或是发生改变。
    最近写代码练手,写一个网络发送文件的小程序,可选 TCP 或 UDP 为传输方案。写到 UDP 传输方案的时候发现丢包检测重传之类的逻辑越写越乱越写越复杂,于是准备看下 QUIC 怎么实现的。翻了翻 QUIC 的 RFC 文档,看的我头大。
    比较好奇的是,既然 UDP 会丢包,包含传输控制信息的包也是会丢的。控制信息要是丢了,岂不就是 hang 在那里了啊。如果采用超时机制来保证控制信息的重传,这效率(传输速度)就没法保证了。
    所以,QUIC 是如何做的呢
    31 条回复    2021-05-20 11:09:09 +08:00
    binux
        1
    binux  
       2021-05-19 10:44:18 +08:00 via Android
    你知道 TCP 是如何保证可靠性的吗?
    v2tudnew
        2
    v2tudnew  
       2021-05-19 11:09:21 +08:00
    QUIC 好像有类似 RAID5 的校验机制,会多发一些包以用于修复,而且会根据丢包率多发多少包的。非专业人士只是看过介绍。
    chenset
        3
    chenset  
       2021-05-19 11:18:41 +08:00
    也是类似 TCP 的 ack 机制, 不过 TCP 是网卡硬件实现的,几乎不消耗 CPU. QUIC 目前是软件实现的, CPU 性能消耗非常大.
    sujin190
        4
    sujin190  
       2021-05-19 11:27:37 +08:00   ❤️ 3
    tcp 的重传流控都已经搞了无数 paper 了,基础逻辑肯定是用超时、数据包到达顺序来做的,但是怎么做就不是一两句话说得清了,QUIC 用的还是这些重传流控方案,比如 CUBIC 或是 BBR,区别就是 QUIC 用户 http 这种短小数据量的可以不使用慢速开始,在现在网络较 http 请求传输量来说普遍十分高了,取消慢速开始可以显著提高初始传输速度和延迟

    而且流控方案被实现在了用户空间,那么你也可以依据请求的类型啥的选择或动态改变重传流控方式,比如可以给视频使用抗拥塞但是网页请求用低延时的重传流控方案,也可以在请求时协商使用啥重传流控方案,tcp 的重传流控被实现的内核,通过内核参数控制,完全不可控啊也是坑死人
    nicebird
        5
    nicebird  
       2021-05-19 11:42:00 +08:00
    重新实现一套 tcp 机制
    shyling
        6
    shyling  
       2021-05-19 11:43:35 +08:00
    重新实现 tcp
    ch2
        7
    ch2  
       2021-05-19 11:49:30 +08:00   ❤️ 1
    "如果采用超时机制来保证控制信息的重传,这效率(传输速度)就没法保证了"
    要不然你以为为什么网络不好的时候 tcp 下载文件会掉速?
    PeakFish
        8
    PeakFish  
       2021-05-19 12:01:05 +08:00
    谁告诉你 udp 不可靠了
    raaaaaar
        9
    raaaaaar  
       2021-05-19 12:09:34 +08:00 via Android
    des
        10
    des  
       2021-05-19 12:10:51 +08:00 via iPhone
    @chenset 没听说过网卡还干这活
    raaaaaar
        11
    raaaaaar  
       2021-05-19 12:11:29 +08:00 via Android
    TCP 就是用不可靠的底层协议,来实现可靠传输的
    lrs
        12
    lrs  
    OP
       2021-05-19 12:12:14 +08:00
    @binux 具体不是很了解。

    @v2tudnew 哦,就是冗余啊。感觉是在碰运气,因为不知道哪个会丢。

    @chenset
    @nicebird
    好的(笑哭) 这回复言简意赅,一下就看懂了。

    @sujin190 感谢花费篇幅解释。慢速开始是指 TCP 开始的几次握手吗?所以重点是流控方案,感觉要弄明白得花时间了。

    @ch2 明白了。细想之后我有了一个新疑问:正常网络里,如果忽略硬件产生的问题和人为的因素(比如 QOS ),是什么引起的丢包呢,也就是不可靠的源头是什么?
    ch2
        13
    ch2  
       2021-05-19 12:19:37 +08:00
    @lrs #12 就跟送快递一样,路上中间某一个路由器某一时刻需要发的包实在太多了,堵在上面来不及发出去,超时了。更深层次的原因是,网络拥堵情况是动态的,不能使用固定的发包速率,所以发包的人需要试探一个理论上的发送速率最大值
    zengming00
        14
    zengming00  
       2021-05-19 12:20:48 +08:00
    貌似单个包的大小如果小于 MTU 值还是比较可靠的
    v2tudnew
        15
    v2tudnew  
       2021-05-19 12:22:23 +08:00
    确实属于碰运气,谷歌的意思应该是减少延迟、额外开销之类的,然后加上校验降低重传率(这样就不用等超时了),我个外人感觉还是可以的,如果对 UDP 和 TCP 都一样 QOS 公正的话。
    caola
        16
    caola  
       2021-05-19 12:28:26 +08:00
    @lrs 现在 http/3 很快就要正式发布了,
    nginx 目前可以通过其官方的 h3 补丁来增加支持,go 语言有 quic-go 包
    至于如何实现的,建议你可以去查看源代码

    QUIC 以后会慢慢取代 TCP 的地位
    Tianao
        17
    Tianao  
       2021-05-19 12:29:43 +08:00 via iPhone
    TCP 协议基于 IP,IP 不可靠,TCP 如何保证可靠性的呢
    sujin190
        18
    sujin190  
       2021-05-19 14:20:01 +08:00   ❤️ 1
    @lrs #12 并不是,满开始是 tcp 连接不知道网络有多少带宽可用,所以握手成功后,先发几个包,成功受到确认没有丢包才会慢慢增加发包数量,通俗点就是连接探测可用带宽的过程,现在宽带、4g 、5g 带宽都很大,对于 http 这种大多数情况下不会发送大量数据造成持久性网络拥塞的,已经没啥必要做慢开始过程了
    robot1
        19
    robot1  
       2021-05-19 14:26:46 +08:00
    看 kcp 文档
    GuuJiang
        20
    GuuJiang  
       2021-05-19 16:31:21 +08:00 via iPhone
    @PeakFish ???
    jim9606
        21
    jim9606  
       2021-05-19 17:02:21 +08:00
    如果你只是搞上层应用,别自己写,直接搬别人的实现就是了。
    ( https://github.com/lucas-clemente/quic-go )

    真要深入研究这个你得先把 TCP 的设计搞清楚,这玩意往大的说,能写一本厚书了。
    wellsc
        22
    wellsc  
       2021-05-19 18:06:29 +08:00
    64 位 id + 重传
    tiddarabbit
        23
    tiddarabbit  
       2021-05-19 20:21:26 +08:00
    @chenset "TCP 是网卡硬件实现的,几乎不消耗 CPU" 😵😵😵😵😵
    Love4Taylor
        24
    Love4Taylor  
       2021-05-19 21:00:20 +08:00 via iPhone
    @des 他说的应该是 TCP 卸载
    msaionyc
        25
    msaionyc  
       2021-05-19 21:10:38 +08:00 via iPhone
    @PeakFish UDP 可靠吗
    joyqi
        26
    joyqi  
       2021-05-19 21:12:55 +08:00
    质不够量来凑
    chenset
        27
    chenset  
       2021-05-19 21:42:15 +08:00
    #3 严重错误, 请忽略
    ysc3839
        28
    ysc3839  
       2021-05-19 23:07:01 +08:00 via Android
    你是想自己实现一个 UDP 可靠传输协议吗?
    还是说只是希望自己写的小程序走 UDP 传输的同时保证可靠?
    如果是后者,建议使用 KCP 之类现成的协议。
    msg7086
        29
    msg7086  
       2021-05-20 05:09:04 +08:00   ❤️ 1
    @lrs #12 丢包的本源就是缓冲区满了。(这个在计算机网络课程里应该有讲到。)
    #13 的快递比喻基本是正确的,但是丢包一般是因为缓冲区满了。
    缓冲区就相当于快递集散点的仓库,短时间内快递多,可以先堆着慢慢送,但是如果遇到过节大甩卖,快递多到仓库都堆不下了,爆仓了,那么对于硬件设备来说就是直接丢弃掉了。
    因为丢弃的包不会有回传消息,所以在软件这边看来就是等待直到超时。
    因为超时对发送流量的影响更大,所以一般的流控会选择主动减速,空出缓冲区,保证发出去的包都不会因为爆仓而丢弃。但是这个减速的机制则需要微调个几十年。
    wanguorui123
        30
    wanguorui123  
       2021-05-20 07:29:31 +08:00 via iPhone
    纠错算法了解下
    lrs
        31
    lrs  
    OP
       2021-05-20 11:09:09 +08:00
    @PeakFish #8 我是在网上看的好多地方描述 UDP 的时候都写 unreliable

    @shyling #6
    @raaaaaar #11
    @v2tudnew #15
    @robot1 #19
    @jim9606 #21
    @wellsc #22
    @wanguorui123 #30
    好的,多谢指点

    @ch2 #13
    @sujin190 #18
    @msg7086 #29
    明白了,感谢解释

    @zengming00 #14 一般都是小于 MTU 的吧

    @caola #16 嗯,已经找了 quinn 的代码在看

    @Tianao #17 哈哈哈,不要这样造句啦

    @joyqi #26 嗯,然后凑也是有讲究

    @ysc3839 #28 只是写着玩儿,后来发现 UDP 做可靠性挺复杂,自己实现一个感觉不大现实,还没那么强做不到呐。多谢指点,我去找下 KCP 文档看看
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2838 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 09:34 · PVG 17:34 · LAX 01:34 · JFK 04:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.