性能

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

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

显而易见的起点是配置支持 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 客户端。