跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 基于 TCP 实现极简的业务流控
未分類
6 6 月 2020

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

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

資深大佬 : feng32 13

假设有一系列实时数据 (Message 结构) 要通过 TCP 发送

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

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

问题来了:这个方案可实施吗?如何让 send api 工作在原子的、非阻塞模式?

大佬有話說 (24)

  • 資深大佬 : ho121

    udp 不好么

  • 資深大佬 : catror

    可以,不过当前消息有部分填进去的话,你只能丢后面的消息。

  • 資深大佬 : gamexg

    增加一个队列
    开一个线程,从队列取消息写入 tcp 连接
    其他线程发消息都是发送到队列,队列满了就丢弃。

  • 資深大佬 : rrfeng

    还是从业务层实现比较好。

  • 資深大佬 : xuanbg

    不好,传输层不应该干涉 /影响业务层的逻辑

  • 主 資深大佬 : feng32

    @ho121 UDP 长度不够

    如果消息比较短,UDP 就完全没问题了

  • 主 資深大佬 : feng32

    @catror 要避免的,就是 “只填消息的一部分进去”

  • 資深大佬 : catror

    @feng32 所以我说只能丢后面的消息,填了一部分的消息剩余部分你要发完。对于你来说,丢当前这条和丢下一条并没有区别。

  • 資深大佬 : Vegetable

    说的好像很复杂,其实逻辑抽象一下很简单,就是发送消息的时候判断是否要丢弃下一条消息。
    如果所谓阻塞是通过前 N 条消息判断的:当前时间距离之前 N 条消息开始发送的时间已经超过了 t,则认为当前网络阻塞,判断下一条消息是否可以丢弃,可以丢弃则丢弃。

    这么抽象一下之后,就和使用什么协议没有关系了。

  • 資深大佬 : optional

    debug 的时候要死人。

  • 主 資深大佬 : feng32

    @catror 假设生产的速率是一定的,在 3F 的解法中:

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

    在 8F 的解法中:

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

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

    我想了一下,对我的实际场景,两者都是可以的。但是 8F 的解法对生产的逻辑有一个要求:生产者要能感知到阻塞的发生,在阻塞结束后,测量一下阻塞了多少时间,然后下次生产新的实时数据,而不因为阻塞导致后续生产的数据实时性发生整体偏移

  • 資深大佬 : reus

    TCP 是可靠传输,除非你断开连接,否则不可能实现“丢 message”

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

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

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

    想那么多,难道不会写个 demo 验证自己的想法?如果没有验证的能力,那还是多学习,少思考比较好。

  • 資深大佬 : jedihy

    缓冲区大小和网络拥塞不拥塞有什么关系

  • 主 資深大佬 : feng32

    @jedihy 在原方案下,即能够知道缓冲区能不能再放下一个 Message,而此时原本最多只有 64K 缓冲区,一个 Message 都放不下,那就肯定不行了

    但是如果采用 3F / 8F 的方案,就没有这个问题了

  • 主 資深大佬 : feng32

    @reus 标题里已经提到了,这里要做的是业务层的流控,传输层用的是 TCP

    3F / 8F 已经给出比较好的解法了,3F 是一个解法,8F 是一个绕过的思路

  • 主 資深大佬 : feng32

    @reus 我刚才查了一下,还真有这个方法,我原本以为这种功能应该不存在的

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

    所以这就是第三个解法了 🙂

  • 資深大佬 : GeruzoniAnsasu

    “业务流控” 跟 tcp 压根就没什么关系

  • 資深大佬 : sujin190

    如果你的意思是很多大 message 会占用很多传输时间,网络不好的时候会阻塞整体性能的话
    一般来说这种情况下用 tcp 的话,更常用的做法应该是大 message 使用单独连接发送,小消息使用一个连接,网络不好大消息超过一定时间无法传输完成直接关闭连接就是了,考虑到连接建立开销啥的,用连接池就行了吧
    不能开连接的话,那么应该是分小帧传输,加入优先级就行,大消息优先级比小消息优先级更低,这样也可以保证良好性能

  • 資深大佬 : raynor2011

    接收方判断下消息发送接收时间就行了吧

  • 主 資深大佬 : feng32

    @sujin190 实际上是类似视频直播的场景,已经卡了几帧了那就算了,下次继续发最新画面

  • 主 資深大佬 : feng32

    与其重传过时的内容,选择跳帧

  • 資深大佬 : momocraft

    隐约读到 “粘包” 两个字

  • 資深大佬 : araaaa

    traffic shaping

  • 資深大佬 : love

    通过实际发送消息速率动态调整发送间隔呢?

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具