性能

在性能方面没有一劳永逸的解决方案。许多因素会影响性能,包括消息的大小和数量、应用程序方法是否执行需要阻塞的工作以及外部因素(例如网络速度和其他问题)。本节的目标是概述可用的配置选项,并就如何进行扩展提供一些思考。

在消息传递应用程序中,消息通过通道传递以进行异步执行,这些通道由线程池支持。配置此类应用程序需要对通道和消息流有充分的了解。因此,建议查阅 消息流

显而易见的起点是配置支持 clientInboundChannelclientOutboundChannel 的线程池。默认情况下,两者都配置为可用处理器数量的两倍。

如果注解方法中的消息处理主要是 CPU 密集型的,则 clientInboundChannel 的线程数应保持接近处理器数量。如果它们执行的工作更多是 IO 密集型的,并且需要阻塞或等待数据库或其他外部系统,则可能需要增加线程池大小。

ThreadPoolExecutor 有三个重要属性:核心线程池大小、最大线程池大小以及用于存储没有可用线程的任务的队列容量。 一个常见的困惑是,配置核心池大小(例如 10)和最大池大小(例如 20)会导致一个包含 10 到 20 个线程的线程池。 事实上,如果容量保持其默认值 Integer.MAX_VALUE,线程池永远不会超过核心池大小,因为所有额外的任务都已排队。 请参阅 ThreadPoolExecutor 的 javadoc 以了解这些属性如何工作并理解各种排队策略。

clientOutboundChannel 侧,一切都与向 WebSocket 客户端发送消息有关。如果客户端在快速网络上,线程数应保持接近可用处理器数量。如果它们速度慢或带宽低,它们需要更长时间来消费消息,并给线程池带来负担。因此,增加线程池大小变得必要。

虽然 clientInboundChannel 的工作负载是可以预测的——毕竟,它基于应用程序所做的事情——但如何配置 "clientOutboundChannel" 却更难,因为它基于应用程序无法控制的因素。因此,还有两个与消息发送相关的属性:sendTimeLimitsendBufferSizeLimit。您可以使用这些方法来配置允许发送操作花费的时间以及向客户端发送消息时可以缓冲的数据量。

一般的想法是,在任何给定时间,只能使用一个线程向客户端发送消息。与此同时,所有额外的消息都会被缓冲,您可以使用这些属性来决定允许发送消息花费多长时间以及在此期间可以缓冲多少数据。请参阅 javadoc 和 XML 模式文档以获取重要的额外详细信息。

以下示例显示了可能的配置:

您还可以使用前面所示的 WebSocket 传输配置来配置传入 STOMP 消息的最大允许大小。理论上,WebSocket 消息的大小几乎可以是无限的。实际上,WebSocket 服务器会施加限制——例如,Tomcat 上为 8K,Jetty 上为 64K。因此,像 stomp-js/stompjs 等 STOMP 客户端会将较大的 STOMP 消息在 16K 边界处拆分,并将其作为多个 WebSocket 消息发送,这需要服务器缓冲和重新组装。

Spring 的 STOMP-over-WebSocket 支持会执行此操作,因此应用程序可以配置 STOMP 消息的最大大小,而无需考虑 WebSocket 服务器特定的消息大小。请记住,WebSocket 消息大小会自动调整(如有必要),以确保它们至少可以承载 16K WebSocket 消息。

以下示例显示了一种可能的配置:

关于扩展的一个重要点涉及使用多个应用程序实例。目前,您无法通过简单代理实现这一点。 但是,当您使用功能齐全的代理(例如 RabbitMQ)时,每个应用程序实例都会连接到代理,并且从一个应用程序实例广播的消息可以通过代理广播到通过任何其他应用程序实例连接的 WebSocket 客户端。