Stack overflow: Threading model of Spring WebFlux and Reactor
Netty reactor thread modeling
Spring framework reference: webflux-concurrency-model
Spring MVC vs Spring WebFlux
-
Architecture diagram
image.png
Threading Model
-
For WebFlux Http request handling
- 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.
-
For MongoDB
- DB access and subsequent data operation via thread created from
NioEventLoopGroup
. -
NioEventLoopGroup
is created byMongoReactiveAutoConfiguration
and can be configured viaMongoClientSettings
- Thread number is defined in
MultithreadEventLoopGroup
:DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2))
- DB access and subsequent data operation via thread created from
Thread usage records in our server
Local Macbook pro 2015 15 inch', with 4 cores and 8 threads
Thread used in single call
-
Main
- Application startup -
reactor-http-nio-x
- Request handler & Response Handler for both Http and Websocket -
nioEventLoopGroup-2-y
- Reactive mongo repository
Thread used in concurrent calls from 100 users
Using Gatling to make 100 concurrent calls on the Http apis:
- /lexicons
- /lexicons/random
- /users
Using Gatling to make 20 concurrent calls on the Websocket apis:
- /join then send Command(REFRESH)
Thread used (Http and websocket have the same result):
- reactor-http-nio-x: 8 threads
- nioEventLoopGroup-x-y: 16 threads
Issue records
-
LexiconRepositoryCustom
should be implemented in a non-blocking way. Which means the syncronized data CURD with mongoTemplate should be deffered and dispatched to another thread. (Which thread pool?)
Solution: Replace MongoTemplate with ReactiveMongoTempate - All service executions are running on
nioEventLoopGroup-x-y
because they start with repository calls. Should we dispatch it back toctor-http-nio-x
?
Answer: No need. As long as it dose no block the nio threads.
网友评论