对于最新的稳定版本,请使用 Spring Framework 7.0.6!spring-doc.cadn.net.cn

性能

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

在消息应用程序中,消息通过通道进行异步执行,这些执行由线程池支持。配置此类应用程序需要了解通道和消息的流动。因此,建议回顾 消息的流动spring-doc.cadn.net.cn

显然,开始的地方是配置支持 clientInboundChannelclientOutboundChannel 的线程池。默认情况下,两者的配置都是可用处理器数量的两倍。spring-doc.cadn.net.cn

如果带注解的方法中消息的处理主要是CPU密集型的,那么clientInboundChannel的线程数应尽量接近处理器的数量。如果它们所做的工作更多是IO密集型的,并且需要在数据库或其他外部系统上进行阻塞或等待,线程池的大小可能需要增加。spring-doc.cadn.net.cn

ThreadPoolExecutor 有三个重要的属性:核心线程池大小、最大线程池大小以及用于存储没有可用线程的任务的队列容量。spring-doc.cadn.net.cn

一个常见的误解是,配置核心线程数(例如 10)和最大线程数(例如 20)会导致一个拥有 10 到 20 个线程的线程池。实际上,如果容量保持默认值 Integer.MAX_VALUE 不变,线程池永远不会超过核心线程数,因为所有额外的任务都会被排队。spring-doc.cadn.net.cn

查看 ThreadPoolExecutor 的 Javadoc 了解这些属性的工作方式并理解各种排队策略。spring-doc.cadn.net.cn

clientOutboundChannel 端,主要是向 WebSocket 客户端发送消息。如果客户端处于快速网络中,线程数量应保持接近可用处理器的数量。如果它们速度较慢或带宽较低,消耗消息所需的时间更长,并会给线程池带来负担。因此,增加线程池大小变得必要。spring-doc.cadn.net.cn

虽然clientInboundChannel的工作量可能可以预测 — 毕竟,它是基于应用程序所做的操作 — 但如何配置“clientOutboundChannel”则更难,因为它基于应用程序无法控制的因素。因此,还有两个额外的属性与消息的发送有关: sendTimeLimitsendBufferSizeLimit。您可以使用这些方法来配置发送操作允许花费的时间以及在向客户端发送消息时可以缓冲的数据量。spring-doc.cadn.net.cn

一般来说,任何时候只能使用一个线程向客户端发送消息。而所有其他消息则会被缓冲,你可以使用这些属性来决定发送消息允许花费多长时间以及在此期间可以缓冲多少数据。有关重要的额外细节,请参阅XML模式的javadoc和文档。spring-doc.cadn.net.cn

以下示例显示了一个可能的配置:spring-doc.cadn.net.cn

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

	@Override
	public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
		registration.setSendTimeLimit(15 * 1000).setSendBufferSizeLimit(512 * 1024);
	}

	// ...

}

以下示例展示了前面示例的XML配置等价写法:spring-doc.cadn.net.cn

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:websocket="http://www.springframework.org/schema/websocket"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/websocket
		https://www.springframework.org/schema/websocket/spring-websocket.xsd">

	<websocket:message-broker>
		<websocket:transport send-timeout="15000" send-buffer-size="524288" />
		<!-- ... -->
	</websocket:message-broker>

</beans>

您也可以使用先前展示的WebSocket传输配置来设定入站STOMP消息的最大允许尺寸。理论上,WebSocket消息的大小几乎可以不受限制。但在实际应用中,WebSocket服务器会施加限制——例如Tomcat限制为8K,Jetty限制为64K。因此,诸如stomp-js/stompjs等STOMP客户端会将超过16K的STOMP消息进行拆分,通过多个WebSocket消息发送,这要求服务器进行缓冲和重新组装。spring-doc.cadn.net.cn

Spring 的 STOMP-over-WebSocket 支持实现了这一点,因此应用程序可以配置 STOMP 消息的最大大小,而无需考虑特定于 WebSocket 服务器的消息大小。请记住,如果需要的话,WebSocket 消息大小会自动进行调整,以确保它们至少可以承载 16K 的 WebSocket 消息。spring-doc.cadn.net.cn

以下示例显示了一种可能的配置:spring-doc.cadn.net.cn

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

	@Override
	public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
		registration.setMessageSizeLimit(128 * 1024);
	}

	// ...

}

以下示例展示了前面示例的XML配置等价写法:spring-doc.cadn.net.cn

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:websocket="http://www.springframework.org/schema/websocket"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/websocket
		https://www.springframework.org/schema/websocket/spring-websocket.xsd">

	<websocket:message-broker>
		<websocket:transport message-size="131072" />
		<!-- ... -->
	</websocket:message-broker>

</beans>

关于扩展的一个重要点是使用多个应用程序实例。 目前,你无法通过简单的代理程序实现这一点。 但是,当你使用一个功能齐全的代理程序(例如 RabbitMQ)时,每个应用程序实例都会连接到代理程序,一个应用程序实例广播的消息可以通过代理程序传递给通过其他任何应用程序实例连接的 WebSocket 客户端。spring-doc.cadn.net.cn