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

问题描述 投票:0回答:1

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

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

我有点惊讶的是,在send()方法中没有用await关键字调用async方法。 send()方法是否只排队要发送的所有数据?如果套接字缓冲区变满了,那么send()会阻塞导致其他客户端比被阻塞的客户端饥饿吗?

如果send()永远不会阻塞,那么如果数据排队并排队并排队等待会发生什么?它可以使用不断增加的无限量内存吗?

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

node.js websocket blocking backpressure ws
1个回答
1
投票

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

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

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

我有点惊讶的是,在async方法中没有使用await关键字调用send()方法。

ws早于异步/等待并承诺多年。我想这个API最终会被改装,但它还没有发生。

send()方法是否只排队要发送的所有数据?如果套接字缓冲区变满了,发送()阻塞会导致其他客户端比被阻塞的客户端更加饥饿吗?

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

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

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

  • send调用提供完成回调参数。该回调将被传递给Socket.write调用,当所有write的数据都被写入内核时,它将触发回调。如果您的服务器在回调触发之前不会向此客户端发送更多数据,则在该用户空间中为该连接缓冲的数据量将限制为接近最新send的大小。 (这不是那么大小,因为缓冲的数据将包括WebSocket框架,如果您的连接是加密的,则加上SSL框架和填充,除了传递给send的原始数据之外。)或者
  • 在准备关于该连接的bufferSize数据之前,检查连接的Socketsend属性。 bufferSize表示当前在该Socket的用户空间中缓冲的数据量。如果它不为零,则跳过该客户端的send
© www.soinside.com 2019 - 2024. All rights reserved.