V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
feng32
V2EX  ›  程序员

基于 TCP 实现极简的业务流控

  •  
  •   feng32 · Jun 14, 2020 · 3753 views
    This topic created in 2155 days ago, the information mentioned may be changed or developed.
    假设有一系列实时数据 (Message 结构) 要通过 TCP 发送

    我们要实现: TCP 传输通畅的时候,按照预定速率发送; TCP 阻塞 (但是连接没有断开) 时,可以丢掉一些 Message

    我想到的一个非常简单的方法是:把 TCP 发送缓冲区调大点,然后调用 send 时,如果能把 Message 一次性填进去,就填进去,否则就把 Message 整个丢掉

    问题来了:这个方案可实施吗?如何让 send api 工作在原子的、非阻塞模式?
    24 replies    2020-06-15 07:34:24 +08:00
    ho121
        1
    ho121  
       Jun 14, 2020 via Android
    udp 不好么
    catror
        2
    catror  
       Jun 14, 2020 via Android
    可以,不过当前消息有部分填进去的话,你只能丢后面的消息。
    gamexg
        3
    gamexg  
       Jun 14, 2020 via Android   ❤️ 2
    增加一个队列
    开一个线程,从队列取消息写入 tcp 连接
    其他线程发消息都是发送到队列,队列满了就丢弃。
    rrfeng
        4
    rrfeng  
       Jun 14, 2020 via Android
    还是从业务层实现比较好。
    xuanbg
        5
    xuanbg  
       Jun 14, 2020
    不好,传输层不应该干涉 /影响业务层的逻辑
    feng32
        6
    feng32  
    OP
       Jun 14, 2020
    @ho121 UDP 长度不够

    如果消息比较短,UDP 就完全没问题了
    feng32
        7
    feng32  
    OP
       Jun 14, 2020
    @catror 要避免的,就是 “只填消息的一部分进去”
    catror
        8
    catror  
       Jun 14, 2020 via Android   ❤️ 1
    @feng32 所以我说只能丢后面的消息,填了一部分的消息剩余部分你要发完。对于你来说,丢当前这条和丢下一条并没有区别。
    Vegetable
        9
    Vegetable  
       Jun 14, 2020
    说的好像很复杂,其实逻辑抽象一下很简单,就是发送消息的时候判断是否要丢弃下一条消息。
    如果所谓阻塞是通过前 N 条消息判断的:当前时间距离之前 N 条消息开始发送的时间已经超过了 t,则认为当前网络阻塞,判断下一条消息是否可以丢弃,可以丢弃则丢弃。

    这么抽象一下之后,就和使用什么协议没有关系了。
    optional
        10
    optional  
       Jun 14, 2020 via iPhone
    debug 的时候要死人。
    feng32
        11
    feng32  
    OP
       Jun 14, 2020
    @catror 假设生产的速率是一定的,在 3F 的解法中:

    每次生产出一个 Messsage (onNewMessage),就调用一次 queue.push() 方法实现原子操作;另一个线程从 queue 中不断读取数据并发送

    在 8F 的解法中:

    每次生产一个 Message (onNewMessage),就调用 send() 方法把这个 Message 整个发出去,如果需要等待,就一直阻塞在那里;这时因为发生了阻塞,实际上也就不会有新的 Message 产生

    本质上,前者是 “生产不阻塞” 模式,后者是 “阻塞生产” 模式

    我想了一下,对我的实际场景,两者都是可以的。但是 8F 的解法对生产的逻辑有一个要求:生产者要能感知到阻塞的发生,在阻塞结束后,测量一下阻塞了多少时间,然后下次生产新的实时数据,而不因为阻塞导致后续生产的数据实时性发生整体偏移
    reus
        12
    reus  
       Jun 14, 2020
    TCP 是可靠传输,除非你断开连接,否则不可能实现“丢 message”

    再说了,协议实现怎么知道什么是“message”? TCP 是流式传输,传输层也不可能引入这个概念

    没有哪个 socket 实现提供缓冲区的控制,所以你这纯粹是空想

    允许丢弃的当然用 UDP,自己切帧再组合就是了,不存在什么“长度不够”

    想那么多,难道不会写个 demo 验证自己的想法?如果没有验证的能力,那还是多学习,少思考比较好。
    jedihy
        13
    jedihy  
       Jun 14, 2020 via iPhone
    缓冲区大小和网络拥塞不拥塞有什么关系
    feng32
        14
    feng32  
    OP
       Jun 14, 2020
    @jedihy 在原方案下,即能够知道缓冲区能不能再放下一个 Message,而此时原本最多只有 64K 缓冲区,一个 Message 都放不下,那就肯定不行了

    但是如果采用 3F / 8F 的方案,就没有这个问题了
    feng32
        15
    feng32  
    OP
       Jun 14, 2020
    @reus 标题里已经提到了,这里要做的是业务层的流控,传输层用的是 TCP

    3F / 8F 已经给出比较好的解法了,3F 是一个解法,8F 是一个绕过的思路
    feng32
        16
    feng32  
    OP
       Jun 14, 2020
    @reus 我刚才查了一下,还真有这个方法,我原本以为这种功能应该不存在的

    https://stackoverflow.com/questions/38359272/linux-sockets-how-to-get-number-of-bytes-packets-in-sending-buffer

    所以这就是第三个解法了 :)
    GeruzoniAnsasu
        17
    GeruzoniAnsasu  
       Jun 14, 2020
    “业务流控” 跟 tcp 压根就没什么关系
    sujin190
        18
    sujin190  
       Jun 14, 2020
    如果你的意思是很多大 message 会占用很多传输时间,网络不好的时候会阻塞整体性能的话
    一般来说这种情况下用 tcp 的话,更常用的做法应该是大 message 使用单独连接发送,小消息使用一个连接,网络不好大消息超过一定时间无法传输完成直接关闭连接就是了,考虑到连接建立开销啥的,用连接池就行了吧
    不能开连接的话,那么应该是分小帧传输,加入优先级就行,大消息优先级比小消息优先级更低,这样也可以保证良好性能
    raynor2011
        19
    raynor2011  
       Jun 14, 2020 via Android
    接收方判断下消息发送接收时间就行了吧
    feng32
        20
    feng32  
    OP
       Jun 14, 2020 via Android
    @sujin190 实际上是类似视频直播的场景,已经卡了几帧了那就算了,下次继续发最新画面
    feng32
        21
    feng32  
    OP
       Jun 14, 2020 via Android
    与其重传过时的内容,选择跳帧
    momocraft
        22
    momocraft  
       Jun 14, 2020
    隐约读到 "粘包" 两个字
    araaaa
        23
    araaaa  
       Jun 15, 2020
    traffic shaping
    love
        24
    love  
       Jun 15, 2020 via Android
    通过实际发送消息速率动态调整发送间隔呢?
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   995 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 62ms · UTC 19:24 · PVG 03:24 · LAX 12:24 · JFK 15:24
    ♥ Do have faith in what you're doing.