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

时间:2019-03-15 17:57:49

标签: node.js websocket blocking backpressure ws

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

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

对于send()方法中未使用await关键字调用async方法,我感到有些惊讶。 send()方法是否只是将所有要发送的数据排队?如果套接字缓冲区已满,send()会以某种方式引起阻塞,而不是阻塞其他客户端吗?

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

理想情况下,如果最近一次更新没有完全发送,我想忽略每分钟发送一次更新。我可以使用ws模块来实现吗?

1 个答案:

答案 0 :(得分:1)

  

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

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

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

  

令我有些惊讶的是,send()方法没有与   异步方法中的await关键字。

ws早于async / await和诺言。我认为该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分别缓冲的,因此通常这种缓冲不会影响在连接到其他客户端的其他Socket上的传输。但是,Socket可以缓冲的数据量没有限制。在极端情况下,一个Socket的缓冲数据可能会消耗服务器进程的所有内存,并且由此导致的服务器崩溃将干扰向所有客户端的数据传递。

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

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

    < / li>
  • 在准备为该连接上的bufferSize数据之前,检查连接的Socket的{​​{1}}属性。 send指示该套接字当前在用户空间中缓冲的数据量。如果非零,请跳过该客户端的bufferSize