【问题标题】:Performance Issue with Spring Websocket, RabbitMQ and STOMPSpring Websocket、RabbitMQ 和 STOMP 的性能问题
【发布时间】:2024-04-15 03:10:01
【问题描述】:

我已经为一个性能问题苦苦挣扎了两个多月,但我无法解决它。因此,我想请教一下问题可能是什么。

问题

我们使用 Spring Websocket 开发一个应用程序,其中客户端订阅其用户队列 (/user/exchange/amq.direct/update) 以接收有关它们的更新。我设置了一个 JMeter 测试,它订阅用户队列并每 4 秒发送一条消息,会话长度为 12 分钟。当有大约 300 个线程在运行时(以大约 4500 个请求/分钟结束),服务器的响应时间急剧增加到 6 秒以上(我认为在我的 JMeter 测试中超时)。

测试在单独的机器上运行,应用程序在 Linux (Debian) 机器上运行,没有其他正在运行的应用程序。

我已经尝试过的

  • 将外部消息代理 (rabbitMQ) 与内部消息代理交换。有趣的是,使用内部代理我可以处理多达 2000 个线程,但我会进入相同的超时。
  • 我删除了所有业务逻辑,只发送一个简单的字符串作为 STOMP 消息
  • 我为ClientInboundChannelClientOutboundChannel 尝试了不同的配置
  • 我在WebSocketMessageBrokerConfigurer 中尝试了不同的SendBufferSizeLimit
  • 为了验证我没有网络问题,我确实测量了来自ClientInboundChannel 的传入消息的时间,直到它通过为它们实现ChannelInterceptorsClientOutboundChannel 中发送出去。这证实了答案确实需要超过 6 秒才能发出。
  • 在 websocket 的响应时间变得如此糟糕的时候(顺便说一句,这已经影响了新线程的 STOMP 连接调用)我对传统的 http 请求没有任何问题。
  • 我的飞行记录显示 CPU 没有问题,峰值仅为 40%,RAM 也远低于 1.5 GB 左右的阈值。
  • 我也看不到线程争用或热方法。
  • 我没有用完文件描述符。
  • 垃圾收集没问题。我在 7 分钟内只运行了 4 次,GC 时间在 200-300 毫秒左右

由于我已经在这个话题上工作了很长一段时间,我可能忘记了很多我也尝试过的东西,所以请不要犹豫,开始对话。

我希望你能给我更多的灵感去哪里寻找问题。

更新:

我发现我可以增加 SimpleMessageBroker 使用的 DefaultSubscriptionRegistry 的缓存限制。这导致使用该应用程序只需处理数千名用户。所以看起来这是 RabbitMQ 的问题。我确实使用PerfTest 工具测试了我们的 RabbitMQ,并且通过该测试我没有遇到任何问题。而且测试的不是使用STOMP插件,而是amqp。

那么 Spring Websocket 中的外部消息代理有类似的限制吗?

更新 2:

我能够使用示例应用程序重现该问题,您可以在 github 上找到该示例应用程序: https://github.com/mld-ger/spring-websocket-performance-issue

由于我认为这可能是 Spring 中的错误,我开了一张票:https://jira.spring.io/browse/SPR-16950

【问题讨论】:

    标签: java spring performance rabbitmq spring-websocket


    【解决方案1】:

    Flight Recorder 仅记录由监视器争用(synchronized 关键字)引起的延迟,这意味着其他延迟,例如由 java.util.concurrent.* 类引起的延迟,可能会被忽视。

    争用也可能短于 Flight Recorder 使用的默认 20 毫秒阈值。然而,这不太可能,因为由于线程调度,通常总会有一些异常值。

    如果不是由锁争用引起的,我的猜测是它与 I/O 相关。

    【讨论】: