NodeJS WebSockets (ws) 模块是否实现背压?

Does NodeJS WebSockets (ws) module implement backpressure?

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

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

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

如果send()从不阻塞,如果数据一直排队又排队又排队……会怎样?它可以使用不断增加的无限量内存吗?

理想情况下,如果上次更新尚未完全发送,我想省略发送每分钟一次的更新。我可以使用 ws 模块实现吗?

I'm concerned of what happens when a connection to the client becomes inactive, for example due to network connection breaking in a way that doesn't send a TCP RST or FIN.

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

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

I'm somewhat surprised that the send() method is not called with the await keyword in an async method.

ws 早于 async/await 和承诺。我想象 API 最终会被改装,但它还没有发生。

Does the send() method just queue all data to be sent? What if the socket buffers become full, can send() block in a way that causes starvation of other clients than the blocked one?

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

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

有几种方法可以避免这个问题。 spring 需要注意的两个简单方法是:

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

  • 检查连接 SocketbufferSize 属性,然后再准备 send 连接上的数据。 bufferSize 指示当前在用户 space 中为该套接字缓冲的数据量。如果它不为零,则跳过该客户端的 send