【问题标题】:Does NodeJS WebSockets (ws) module implement backpressure?NodeJS WebSockets (ws) 模块是否实现背压?
【发布时间】:2019-03-16 12:47:41
【问题描述】:

我正在使用 ws 模块在 NodeJS 上实现 WebSockets 服务器。服务器应每分钟向所有客户端发送一次更新。我已经实现了这个,但我担心它在客户端连接可能停止的情况下的功能。

我担心当与客户端的连接变为非活动状态时会发生什么,例如由于网络连接以不发送 TCP RST 或 FIN 的方式中断。

我有点惊讶send() 方法没有在async 方法中使用await 关键字调用。 send() 方法是否只是将所有要发送的数据排队?如果套接字缓冲区已满,send() 是否会以一种导致其他客户端饥饿而不是被阻塞客户端的方式阻塞?

如果send() 从不阻塞,那么如果数据排队、排队、排队……会发生什么?它可以使用不断增加的无限内存吗?

理想情况下,如果最后一次更新尚未完全发送,我想省略发送每分钟一次的更新。我可以通过ws 模块实现这一点吗?

【问题讨论】:

    标签: node.js websocket blocking backpressure ws


    【解决方案1】:

    我担心当与客户端的连接变为 不活动,例如由于网络连接以某种方式中断 不发送 TCP RST 或 FIN。

    如果连接以这种方式丢失(可能是由于客户端系统被关闭或物理断开),那么服务器上的 TCP 将检测到断开的连接,因为它不会收到已发送数据的确认。 TCP 可能需要几分钟才能放弃,但在这种情况下,这听起来不是什么大问题。

    最坏的情况是客户端系统保持连接但客户端进程停止从连接中读取数据。在这种情况下,发送的数据将在客户端累积,直到客户端的套接字接收缓冲区填满,然后发送的数据将在服务器累积——首先在内核套接字发送缓冲区中,然后在服务器进程内存中。

    我有点惊讶的是 send() 方法没有被调用 异步方法中的 await 关键字。

    ws 早于 async/await 和 promise 多年。我想 API 最终会被改造,但它还没有发生。

    send() 方法是否只是排队 所有要发送的数据?如果套接字缓冲区满了怎么办? send() 以一种导致其他客户端饥饿的方式阻塞 屏蔽了一个?

    WebSocket.send 最终调用内置的Net 模块的Socket.write。 (有关该调用,请参阅https://github.com/websockets/ws/blob/master/lib/sender.js 底部的sendFrame 函数,有关Socket 类的文档,请参阅https://nodejs.org/docs/latest-v8.x/api/net.html#net_class_net_socket。)

    Socket.write 如果内核不能立即接受数据,将在用户进程中缓冲数据。每个Socket 单独缓冲数据,因此这种缓冲通常不会影响连接到其他客户端的其他Sockets 上的传输。但是,Socket 将缓冲的数据量没有限制。在极端情况下,Socket 的缓冲数据可能会消耗所有服务器进程的内存,由此导致的服务器崩溃会干扰向所有客户端的数据传递。

    有几种方法可以避免这个问题。想到的两种简单方法是:

    • send 调用提供一个完成回调参数。该回调将传递给Socket.write 调用,当write 的所有数据都已写入内核时,它将触发回调。如果您的服务器在回调触发之前不向该客户端发送更多数据,则该连接在用户空间中缓冲的数据量将被限制为接近最新send 的大小。 (它不会精确到那个大小,因为缓冲的数据将包括 WebSocket 框架,加上 SSL 框架和填充,如果你的连接是加密的,在传递给 send 的原始数据之上。)或者

    • 在准备到该连接上的send 数据之前,检查连接的SocketbufferSize 属性。 bufferSize 表示当前在用户空间中为该 Socket 缓冲的数据量。如果它不为零,请跳过该客户端的 send

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-19
      • 2020-01-14
      • 2016-01-02
      • 2016-08-25
      相关资源
      最近更新 更多