效能

談到效能,沒有萬靈丹。許多因素會影響效能,包括訊息的大小和數量、應用程式方法是否執行需要封鎖的工作,以及外部因素(例如網路速度和其他問題)。本節的目標是概述可用的組態選項,並提供關於如何思考擴展的一些想法。

在訊息應用程式中,訊息會透過通道傳遞以進行非同步執行,這些執行由執行緒池支援。設定此類應用程式需要充分了解通道和訊息流。因此,建議您查看訊息流

首先,顯而易見的地方是設定支援 `clientInboundChannel` 和 `clientOutboundChannel` 的執行緒池。預設情況下,兩者都設定為可用處理器數量的兩倍。

如果註解方法中訊息的處理主要是 CPU 密集型,則 `clientInboundChannel` 的執行緒數量應保持接近處理器的數量。如果他們所做的工作更偏向 IO 密集型,並且需要封鎖或等待資料庫或其他外部系統,則可能需要增加執行緒池大小。

`ThreadPoolExecutor` 具有三個重要屬性:核心執行緒池大小、最大執行緒池大小,以及佇列的容量,用於儲存沒有可用執行緒的任務。

一個常見的混淆點是,設定核心池大小(例如 10)和最大池大小(例如 20)會導致執行緒池具有 10 到 20 個執行緒。事實上,如果容量保持預設值 Integer.MAX_VALUE,則執行緒池永遠不會超過核心池大小,因為所有額外的任務都會排隊。

請參閱 `ThreadPoolExecutor` 的 javadoc,以了解這些屬性如何運作並理解各種佇列策略。

在 `clientOutboundChannel` 方面,一切都關於將訊息傳送到 WebSocket 用戶端。如果用戶端位於快速網路上,則執行緒數量應保持接近可用處理器的數量。如果它們速度較慢或頻寬較低,則它們需要更長的時間來消耗訊息,並給執行緒池帶來負擔。因此,增加執行緒池大小變得必要。

雖然 `clientInboundChannel` 的工作負載可以預測 — 畢竟,它是基於應用程式所做的事情 — 但如何設定「clientOutboundChannel」更困難,因為它是基於應用程式無法控制的因素。因此,有兩個額外的屬性與訊息傳送有關:`sendTimeLimit` 和 `sendBufferSizeLimit`。您可以使用這些方法來設定允許傳送花費多長時間以及在向用戶端傳送訊息時可以緩衝多少資料。

一般概念是,在任何給定時間,只能使用單一執行緒傳送到用戶端。同時,所有額外的訊息都會被緩衝,您可以使用這些屬性來決定允許傳送訊息花費多長時間以及在此期間可以緩衝多少資料。有關重要的其他詳細資訊,請參閱 XML schema 的 javadoc 和文件。

以下範例顯示可能的組態

  • Java

  • Kotlin

  • Xml

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {

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

	// ...

}
@Configuration
@EnableWebSocketMessageBroker
class WebSocketConfiguration : WebSocketMessageBrokerConfigurer {

	override fun configureWebSocketTransport(registration: WebSocketTransportRegistration) {
		registration.setSendTimeLimit(15 * 1000).setSendBufferSizeLimit(512 * 1024)
	}

	// ...
}
<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 用戶端(例如`stomp-js/stompjs`和其他用戶端)會在 16K 邊界分割較大的 STOMP 訊息,並將其作為多個 WebSocket 訊息傳送,這需要伺服器緩衝和重新組裝。

Spring 的 STOMP-over-WebSocket 支援可以做到這一點,因此應用程式可以設定 STOMP 訊息的最大大小,而無需考慮 WebSocket 伺服器特定的訊息大小。請記住,如有必要,WebSocket 訊息大小會自動調整,以確保它們至少可以攜帶 16K WebSocket 訊息。

以下範例顯示一種可能的組態

  • Java

  • Kotlin

  • Xml

@Configuration
@EnableWebSocketMessageBroker
public class MessageSizeLimitWebSocketConfiguration implements WebSocketMessageBrokerConfigurer {

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

	// ...

}
@Configuration
@EnableWebSocketMessageBroker
class MessageSizeLimitWebSocketConfiguration : WebSocketMessageBrokerConfigurer {

	override fun configureWebSocketTransport(registration: WebSocketTransportRegistration) {
		registration.setMessageSizeLimit(128 * 1024)
	}

	// ...
}
<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>

關於擴展的一個重點是使用多個應用程式實例。目前,您無法使用簡單的 broker 執行此操作。但是,當您使用功能完整的 broker(例如 RabbitMQ)時,每個應用程式實例都會連線到 broker,並且從一個應用程式實例廣播的訊息可以透過 broker 廣播到透過任何其他應用程式實例連線的 WebSocket 用戶端。