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

时间:2018-04-18 04:05:06

标签: spring stomp spring-websocket

我开发了一个使用弹簧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.accessCachesynchronized (this.updateCache)中找不到目的地。

某些情况会导致此功能阻塞许多线程。

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

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

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

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

2 个答案:

答案 0 :(得分:0)

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

  

一个是模式目标

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

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

不幸的是,在春季WS XML配置中无法为cacheLimit指定simple-broker。可以向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>

答案 1 :(得分:0)

使用蚂蚁匹配器会导致synchronized块中的性能非常差。

您应该在不使用Ant Matcher的情况下实现类似于subscriptionRegistry的自定义DefaultSubscriptionRegistry