一旦队列填满,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 异步发送可能会导致发送阻塞的主要内容,如果未能解决你的问题,请参考以下文章