Threading model of Spring WebFlux and Reactor

Florian Beaufumé picture Florian Beaufumé · Jul 10, 2017 · Viewed 18k times · Source

Currently experimenting reactive programming with Spring 5.0.0.RC2, Reactor 3.1.0.M2 and Spring Boot 2.0.0.M2.

Wondering about the concurrency and threading model used by WebFlux and Reactor to properly code the application and handle the mutable state.

The Reactor doc states that the library is considered concurrency agnostic and mentions the Scheduler abstraction. The WebFlux doc does not give information.

Yet when using WebFlux through Spring Boot, a threading model is defined.

From my experimentations here is what I got:

  • The model is neither 1 event thread, nor 1 event thread + workers
  • Several thread pools are used
  • "reactor-http-nio-3" threads: probably one per core, handle the incoming HTTP requests
  • "Thread-7" threads: used by async requests to MongoDB or HTTP resources
  • "parallel-1" threads: one per core, created by Schedulers.parallel() from Reactor, used by delay operators and such
  • Shared mutable state must be synchronized by the application
  • ThreadLocal (for application state, MDC logging, etc) are not request scoped, so are not very interesting

Is this correct ? What is the concurrency and threading model of WebFlux: for example what are the default thread pools?

Thank you for the information

Answer

metaphori picture metaphori · Jun 2, 2018

After the question, the present documentation does provide some clues about the concurrency model and the threads one could expect (but I still think that clearer/better descriptions of what happens under-the-scene from a multi-threading perspective would be highly appreciated by Spring newcomers).

It discusses the difference between Spring MVC and Spring WebFlux (1-thread-per-request model vs. event-loop):

In Spring MVC, and servlet applications in general, it is assumed that applications may block the current thread, e.g. for remote calls, and for this reason servlet containers use a large thread pool, to absorb potential blocking during request handling.

In Spring WebFlux, and non-blocking servers in general, it is assumed that applications will not block, and therefore non-blocking servers use a small, fixed-size thread pool (event loop workers) to handle requests. Invoking a Blocking API

But notice that Spring MVC apps can also introduce some asynchronicity (cf., Servlet 3 Async). And I suggest this presentation for a discussion wrt Servlet 3.1 NIO and WebFlux.

Back to the docs: it also suggests that, when working with reactive streams, you have some control:

What if you do need to use a blocking library?

Both Reactor and RxJava provide the publishOn operator to continue processing on a different thread.

(For more details on this, refer to scheduling in Reactor)

It also discusses the threads you may expect in WebFlux applications (bold is mine):

Threading Model

What threads should you expect to see on a server running with Spring WebFlux?

  • On a "vanilla" Spring WebFlux server (e.g. no data access, nor other optional dependencies), you can expect one thread for the server, and several others for request processing (typically as many as the number of CPU cores). Servlet containers, however, may start with more threads (e.g. 10 on Tomcat), in support of both servlet, blocking I/O and servlet 3.1, non-blocking I/O usage.
  • The reactive WebClient operates in event loop style. So you’ll see a small, fixed number of processing threads related to that, e.g. "reactor-http-nio-" with the Reactor Netty connector. However if Reactor Netty is used for both client and server, the two will share event loop resources by default.
  • Reactor and RxJava provide thread pool abstractions, called Schedulers, to use with the publishOn operator that is used to switch processing to a different thread pool. The schedulers have names that suggest a specific concurrency strategy, e.g. "parallel" for CPU-bound work with a limited number of threads, or "elastic" for I/O-bound work with a large number of threads. If you see such threads it means some code is using a specific thread pool Scheduler strategy.
  • Data access libraries and other 3rd party dependencies may also create and use threads of their own.

In part, you can configure the details of the threading model via configuration

To configure the threading model for a server, you’ll need to use server-specific config APIs, or if using Spring Boot, check the Spring Boot configuration options for each server. The WebClient can be configured directly. For all other libraries, refer to their respective documentation.

Moreover, as e.g. the discussion Default number of threads in Spring boot 2.0 reactive webflux configuration highlights,

The default number of threads for request handling is determined by the underlying web server; by default, Spring Boot 2.0 is using Reactor Netty, which is using Netty's defaults

it is a matter of default components and their defaults (and overall configuration, including that injected transparently through annotations) -- which may also change across versions of Spring/Boot and corresponding dependencies. Said that, your guesses seem correct.