Skip to content

Commit 5dbcd76

Browse files
committed
Add doc section on configuration and performance
Issue: SPR-11450
1 parent fd17518 commit 5dbcd76

File tree

1 file changed

+164
-1
lines changed

1 file changed

+164
-1
lines changed

src/asciidoc/index.adoc

Lines changed: 164 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37665,7 +37665,7 @@ sections <<websocket-stomp-handle-broker-relay-configure>> and
3766537665
<<websocket-stomp-handle-user>> for more information on authentication.
3766637666

3766737667

37668-
[[websocket-stomp-handle]]
37668+
[[websocket-stomp-message-flow]]
3766937669
==== Flow of Messages
3767037670

3767137671
When a STOMP endpoint is configured, the Spring application becomes the broker to
@@ -38047,6 +38047,169 @@ for purging inactive destinations.
3804738047

3804838048

3804938049

38050+
38051+
[[websocket-stomp-configuration-performance]]
38052+
==== Configuration and Performance
38053+
38054+
There is no silver bullet when it comes to performance. Many factors may
38055+
affect it including the size of messages, the volume, whether application
38056+
methods perform work that requires blocking, as well as external factors
38057+
such as network speed and others. The goal of this section is to provide
38058+
an overview of the available configuration options along with some thoughts
38059+
on how to reason about scaling.
38060+
38061+
In a messaging application messages are passed through channels for asynchronous
38062+
executions backed by thread pools. Configuring such an application requires
38063+
good knowledge of the channels and the flow of messages. Therefore it is
38064+
recommended to review <<websocket-stomp-message-flow>>.
38065+
38066+
The obvious place to start is to configure the thread pools backing the
38067+
`"clientInboundChannel"` and the `"clientOutboundChannel"`. By default both
38068+
are configured at twice the number of available processors.
38069+
38070+
If the handling of messages in annotated methods is mainly CPU bound then the
38071+
number of threads for the `"clientInboundChannel"` should remain close to the
38072+
number of processors. If the work they do is more IO bound and requires blocking
38073+
or waiting on a database or other external system then the thread pool size
38074+
will need to be increased.
38075+
38076+
[NOTE]
38077+
====
38078+
`ThreadPoolExecutor` has 3 important properties. Those are the core and
38079+
the max thread pool size as well as the capacity for the queue to store
38080+
tasks for which there are no available threads.
38081+
38082+
A common point of confusion is that configuring the core pool size (e.g. 10)
38083+
and max pool size (e.g. 20) results in a thread pool with 10 to 20 threads.
38084+
In fact if the capacity is left at its default value of Integer.MAX_VALUE
38085+
then the thread pool will never increase beyond the core pool size since
38086+
all additional tasks will be queued.
38087+
38088+
Please review the Javadoc of `ThreadPoolExecutor` to learn how these
38089+
properties work and understand the various queuing strategies.
38090+
====
38091+
38092+
On the `"clientOutboundChannel"` side it is all about sending messages to WebSocket
38093+
clients. If clients are on a fast network then the number of threads should
38094+
remain close to the number of available processors. If they are slow or on
38095+
low bandwith they will take longer to consume messages and put a burden on the
38096+
thread pool. Therefore increasing the thread pool size will be necessary.
38097+
38098+
While the workload for the "clientInboundChannel" is possible to predict --
38099+
after all it is based on what the application does -- how to configure the
38100+
"clientOutboundChannel" is harder as it is based on factors beyond
38101+
the control of the application. For this reason there are two additional
38102+
properties related to the sending of messages. Those are the `"sendTimeLimit"`
38103+
and the `"sendBufferSizeLimit"`. Those are used to configure how long a
38104+
send is allowed to take and how much data can be buffered when sending
38105+
messages to a client.
38106+
38107+
The general idea is that at any given time only a single thread may be used
38108+
to send to a client. All additional messages meanwhile get buffered and you
38109+
can use these properties to decide how long sending a message is allowed to
38110+
take and how much data can be buffered in the mean time. Please review the
38111+
Javadoc of XML schema for this configuration for important additional details.
38112+
38113+
Here is example configuration:
38114+
38115+
[source,java,indent=0]
38116+
[subs="verbatim,quotes"]
38117+
----
38118+
@Configuration
38119+
@EnableWebSocketMessageBroker
38120+
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
38121+
38122+
@Override
38123+
public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
38124+
registration.setSendTimeLimit(15 * 1000).setSendBufferSizeLimit(512 * 1024);
38125+
}
38126+
38127+
// ...
38128+
38129+
}
38130+
----
38131+
38132+
[source,xml,indent=0]
38133+
[subs="verbatim,quotes,attributes"]
38134+
----
38135+
<beans xmlns="http://www.springframework.org/schema/beans"
38136+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
38137+
xmlns:websocket="http://www.springframework.org/schema/websocket"
38138+
xsi:schemaLocation="
38139+
http://www.springframework.org/schema/beans
38140+
http://www.springframework.org/schema/beans/spring-beans.xsd
38141+
http://www.springframework.org/schema/websocket
38142+
http://www.springframework.org/schema/websocket/spring-websocket-4.0.xsd">
38143+
38144+
<websocket:message-broker>
38145+
<websocket:transport send-timeout="15000" send-buffer-size="524288" />
38146+
<!-- ... -->
38147+
</websocket:message-broker>
38148+
38149+
</beans>
38150+
----
38151+
38152+
The WebSocket transport configuration shown above can also be used to configure the
38153+
maximum allowed size for incoming STOMP messages. Although in theory a WebSocket
38154+
message can be almost unlimited in size, in pracitce WebSocket servers impose
38155+
limits. For example 8K on Tomcat and 64K on Jetty. For this reason STOMP clients
38156+
such as stomp.js split larger STOMP messages at 16K boundaries and send them as
38157+
multiple WebSocket messages thus requiring the server to buffer and re-assemble.
38158+
38159+
Spring's STOMP over WebSocket support does this so applications can configure the
38160+
maximum size for STOMP messages irrespective of WebSocket server specific message
38161+
sizes. Do keep in mind that the WebSocket message size will be automatically
38162+
adjusted if necessary to ensure they can carry 16K WebSocket messages at a
38163+
minimum.
38164+
38165+
Here is example configuration:
38166+
38167+
[source,java,indent=0]
38168+
[subs="verbatim,quotes"]
38169+
----
38170+
@Configuration
38171+
@EnableWebSocketMessageBroker
38172+
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
38173+
38174+
@Override
38175+
public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
38176+
registration.setMessageSizeLimit(128 * 1024);
38177+
}
38178+
38179+
// ...
38180+
38181+
}
38182+
----
38183+
38184+
[source,xml,indent=0]
38185+
[subs="verbatim,quotes,attributes"]
38186+
----
38187+
<beans xmlns="http://www.springframework.org/schema/beans"
38188+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
38189+
xmlns:websocket="http://www.springframework.org/schema/websocket"
38190+
xsi:schemaLocation="
38191+
http://www.springframework.org/schema/beans
38192+
http://www.springframework.org/schema/beans/spring-beans.xsd
38193+
http://www.springframework.org/schema/websocket
38194+
http://www.springframework.org/schema/websocket/spring-websocket-4.0.xsd">
38195+
38196+
<websocket:message-broker>
38197+
<websocket:transport message-size="131072" />
38198+
<!-- ... -->
38199+
</websocket:message-broker>
38200+
38201+
</beans>
38202+
----
38203+
38204+
An important point about scaling is using multiple application instances.
38205+
Currently this is not possible to do that with the simple broker.
38206+
However when using a full-featured broker such as RabbitMQ, each application
38207+
instance connects to the broker and messages broadcast from one application
38208+
instance are broadcast to WebSocket clients connected through all
38209+
application instances.
38210+
38211+
38212+
3805038213
[[websocket-stomp-testing]]
3805138214
==== Testing Annotated Controller Methods
3805238215

0 commit comments

Comments
 (0)