spring - DefaultSubscriptionRegistry不适应高并发和异常情况

标签 spring stomp spring-websocket

我使用spring websocket和stomp开发了一个聊天系统。最近发现,有时很多线程(超过400个)被阻塞在 DefaultSubscriptionRegistry$DestinationCache$1 :

"http-nio-8686-exec-41" #3822 daemon prio=5 os_prio=0 tid=0x00007f26bc021000 nid=0x8c7a waiting for monitor entry [0x00007f2837af7000]
   java.lang.Thread.State: BLOCKED (on object monitor)
at org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry$DestinationCache.getSubscriptions(DefaultSubscriptionRegistry.java:269)
    - waiting to lock <0x00000004c6969f98> (a org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry$DestinationCache$1)
    at org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry.findSubscriptionsInternal(DefaultSubscriptionRegistry.java:184)
    at org.springframework.messaging.simp.broker.AbstractSubscriptionRegistry.findSubscriptions(AbstractSubscriptionRegistry.java:116)
    at org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler.sendMessageToSubscribers(SimpleBrokerMessageHandler.java:328)
    at org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler.handleMessageInternal(SimpleBrokerMessageHandler.java:260)
    at org.springframework.messaging.simp.broker.AbstractBrokerMessageHandler.handleMessage(AbstractBrokerMessageHandler.java:238)
    at org.springframework.messaging.support.ExecutorSubscribableChannel$SendTask.run(ExecutorSubscribableChannel.java:135)
    at org.springframework.messaging.support.ExecutorSubscribableChannel.sendInternal(ExecutorSubscribableChannel.java:91)
    at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:117)
    at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:104)
    at org.springframework.messaging.simp.SimpMessagingTemplate.sendInternal(SimpMessagingTemplate.java:184)
    at org.springframework.messaging.simp.SimpMessagingTemplate.doSend(SimpMessagingTemplate.java:159)
    at org.springframework.messaging.simp.SimpMessagingTemplate.doSend(SimpMessagingTemplate.java:47)

我认为DestinationCache.getSubscriptions当在 this.accessCache 中找不到目的地时将阻止通过使用synchronized (this.updateCache) .

某些情况会导致许多线程在此函数上阻塞。

其中一个是模式目标,它不在 accessCache 中。

另一种情况是用户和目的地太多,但是cacheLimit=1024默认情况下,因此某些内容将从缓存中删除。

另一种情况是网络不好或者其他一些事情,这使得许多或所有websocket立即断开连接,但是消息通过SimpMessagingTemplate.convertAndSend来发送。 ,那么线程将被阻塞在 DestinationCache.getSubscriptions因为没有找到目的地。

我想知道是否有更好的方法避免阻塞?

最佳答案

今天我也发现了同样的问题。看来增加cacheLimit是个好方法。

One is pattern destination

用户可以通过模式订阅目的地,但是当您向目的地发送消息时,目的地的名称是已知的。 IE。 getSubscriptions(...) 接受不是模式的 destination 参数。

因此,再次增加 cacheLimit 应该足以解决线程阻塞问题。

不幸的是,在 Spring WS XML 配置中不可能为 simple-broker 指定 cacheLimit。可以将以下内容添加到 XML 中以绕过它:

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler#0" />
    <property name="targetMethod" value="setCacheLimit" />
    <property name="arguments" value="8096"/>
</bean>

关于spring - DefaultSubscriptionRegistry不适应高并发和异常情况,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49891002/

相关文章:

java - 如何将二进制消息作为输入流进行处理?

java - 如何让 RESTEasy 理解静态资源?

java - 我们给 spring 注解起个名字是有原因的吗?

spring - 403禁止Spring Boot Web套接字调用

javascript - 通过 STOMP 复制事件 Socket.io 和 Node.js

ruby - 在 ruby​​ 中使用 ActiveMQ + activemessaging gem 的问题

java.lang.IllegalStateException : The remote endpoint was in state [TEXT_PARTIAL_WRITING] which is an invalid state for called method

spring - 带注释的 PRIVATE 方法的 AspectJ 切入点

java - 两个@RequestMapping注解的区别

node.js - 从 STOMP/AMQP 中选择哪一个?