一旦队列填满,WebSocket 异步发送可能会导致发送阻塞

Posted

技术标签:

【中文标题】一旦队列填满,WebSocket 异步发送可能会导致发送阻塞【英文标题】:WebSocket async send can result in blocked send once queue filled 【发布时间】:2014-10-08 19:03:41 【问题描述】:

我有一个非常简单的基于 Jetty 的 websockets 服务器,负责流式传输小的二进制消息以连接客户端。

为了避免服务器端出现任何阻塞,我使用了 sendBytesByFuture 方法。

将负载从 2 个客户端增加到 20 个后,它们停止接收任何数据。在故障排除过程中,我决定打开同步发送方法,最终得到了潜在的原因:

java.lang.IllegalStateException: Blocking message pending 10000 for BLOCKING
at org.eclipse.jetty.websocket.common.WebSocketRemoteEndpoint.lockMsg(WebSocketRemoteEndpoint.java:130)
at org.eclipse.jetty.websocket.common.WebSocketRemoteEndpoint.sendBytes(WebSocketRemoteEndpoint.java:244)

客户端在接收数据时不进行任何计算,因此他们可能不会是慢速加入者。

所以我想知道我能做些什么来解决这个问题? (使用 Jetty 9.2.3)

【问题讨论】:

这是使用 JSR-356 (javax.websocket) 还是原生 websocket api? 原生,随 Jetty 本身提供 【参考方案1】:

如果错误消息来自同步发送,那么您有多个线程试图在同一个 RemoteEndpoint 上发送消息 - 这是协议不允许的。一次只能发送 1 条消息。 (同步发送基本上没有队列)

如果错误消息来自异步发送,则意味着您有消息在等待发送的队列中,但您仍在尝试写入更多异步消息。

尽量不要同时混用同步和异步(很容易不小心把输出变成无效的协议流)

使用 Java 期货:

您需要使用在sendBytesByFuture()sendStringByFuture() 方法返回时提供的Future 对象来验证消息是否实际发送(可能是一个错误),如果足够的开始排队等待发送更多消息,直到远程端点可以赶上。

标准Future 行为和技术适用于此。

使用 Jetty 回调:

sendBytes(ByteBuffer,WriteCallback)sendString(String,WriteCallback) 方法中还有 WriteCallback 行为,它们会在成功/错误时调用您自己的代码,在此您可以围绕您发送的内容添加一些逻辑(限制它,发送它更慢,排队,过滤,丢弃一些消息,优先消息等任何你需要的)

使用拦截:

或者您可以使用阻塞发送来避免太多消息排队。

【讨论】:

其实我提到的异常是从同步方法中获得的。 我需要手动控制队列吗?我虽然那个码头会为我处理它。我错了吗? 顺便问一下,是否有可能以某种方式获取队列大小?

以上是关于一旦队列填满,WebSocket 异步发送可能会导致发送阻塞的主要内容,如果未能解决你的问题,请参考以下文章

Redis 实现 消息队列

使接收到的Websocket事件进行异步处理的最佳方法

如何使websocket同步

轮询,长轮询,websocket原理

如何从非异步方法发送 websocket 消息?

如何永远运行异步 websocket 客户端?