跳到主要内容

性能

ChatGPT-4o-mini 中英对照 Performance

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

在一个消息应用程序中,消息通过通道传递,以便进行由线程池支持的异步执行。配置这样的应用程序需要对通道和消息流有良好的了解。因此,建议查看 Flow of Messages

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

如果注释方法中消息的处理主要是 CPU 绑定的,那么 clientInboundChannel 的线程数量应该保持接近处理器的数量。如果它们所做的工作更多是 IO 绑定,并且需要在数据库或其他外部系统上阻塞或等待,则线程池的大小可能需要增加。

备注

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

一个常见的混淆点是,配置核心池大小(例如,10)和最大池大小(例如,20)会导致线程池具有 10 到 20 个线程。实际上,如果容量保持在默认值 Integer.MAX_VALUE,线程池永远不会超过核心池大小,因为所有额外的任务都会被排队。

请参阅 ThreadPoolExecutor 的 javadoc 以了解这些属性是如何工作的,并理解各种排队策略。

clientOutboundChannel 方面,主要是向 WebSocket 客户端发送消息。如果客户端处于快速网络中,线程数量应保持接近可用处理器的数量。如果它们的网络较慢或带宽较低,处理消息所需的时间会更长,从而对线程池造成负担。因此,增加线程池的大小变得必要。

虽然 clientInboundChannel 的工作负载是可以预测的 —— 毕竟,它是基于应用程序的行为 —— 但配置 "clientOutboundChannel" 更加困难,因为它基于超出应用程序控制的因素。因此,有两个额外的属性与消息发送相关:sendTimeLimitsendBufferSizeLimit。您可以使用这些方法来配置发送允许花费多长时间以及在向客户端发送消息时可以缓冲多少数据。

一般来说,在任何给定的时间,只能使用单个线程向客户端发送消息。与此同时,所有额外的消息都会被缓冲,您可以利用这些属性来决定发送消息允许花费多长时间,以及在此期间可以缓冲多少数据。有关重要的附加细节,请参见 javadoc 和 XML 架构的文档。

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

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {

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

// ...

}
java

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

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

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

@Configuration
@EnableWebSocketMessageBroker
public class MessageSizeLimitWebSocketConfiguration implements WebSocketMessageBrokerConfigurer {

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

// ...

}
java

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