Hi, everyone. My name is Vadim Axelrod, I'm a Java developer at EPAM, and today I'm going to show you an introduction to Reactive Programming and present Spring WebFlux - the reactive-stack web framework, as well as a comparison of Spring WebFlux perfomance over a Spring MVC. First of all, I'd like to say sorry in advance for my English. I'm not a native speaker, so in some situations I would take my time to think, and slow down, and speak, well, basically...
...like him. Okay, let's move on.
We will start with quick introduction of Spring WebFlux, followed by an overview of Reactive Programming as a paradigm and Project Reactor as its implementation in Java, then we'll scratch a surface of JVM Threads in Linux, take a good look at WebFlux and MVC thread models and finish with a demo application using both of them to proove today's point.
What point? My point for today is pretty simple. Spring WebFlux is better than Spring MVC. Why, you may ask? But, aside from jokes, WebFlux is better because of perfomance.
Okay, what is Spring WebFlux. I believe, everyone, who uses Java, have used Spring MVC at least once. The original web framework included in the Spring Framework, Spring Web MVC, was purpose-built for the Servlet API and Servlet containers. The reactive-stack web framework, Spring WebFlux, was added later in version 5.0. It is fully non-blocking, supports Reactive Streams back pressure, and runs on such servers as Netty, Undertow, and Servlet 3.1+ containers.
Just to recap, WebFlux is based on Reactive Programming paradigm. Let's start with the definition of Reactive Programming. The output of each command in the pipeline is connected via a pipe to the input of the next command. That is, each command reads the previous command’s output. This connection is performed before any redirections specified by command1.
Why do we need this after all? Because resources matters. Your application should not consume more, than you actually need, and Spring MVC paradighm can easily led you to do so. Resource consumption is the main advantage of Reactive Programming in general, and the main advantage of WebFlux over MVC in particular. Just to be clear. Reactive Programming does not "lighter", it does not use less resources that classic paradigm in total. Reactive Programming provides you ability to use the already allocated resources more efficient. Basically it means, that you haven't got a threads in your application which does nothing.
Modern applications can reach huge numbers of concurrent users, and, even though the capabilities of modern hardware have continued to improve, performance of modern software is still a key concern. There are, broadly, two ways one can improve a program’s performance: parallelize to use more threads and more hardware resources. seek more efficiency in how current resources are used. Usually, Java developers write programs by using blocking code. This practice is fine until there is a performance bottleneck. Then it is time to introduce additional threads, running similar blocking code. But this scaling in resource utilization can quickly introduce contention and concurrency problems. Worse still, blocking wastes resources. If you look closely, as soon as a program involves some latency (notably I/O, such as a database request or a network call), resources are wasted because threads (possibly many threads) now sit idle, waiting for data. So the parallelization approach is not a silver bullet. It is necessary to access the full power of the hardware, but it is also complex to reason about and susceptible to resource wasting.
As well as Agile Manifesto, for example, there is a Reactive Manifesto which stands for quality attributes, that proper reactive system should have. So, Reactive System should be responsive, resilient, elastic and message-driven. You can check out this manifesto as well as The Reactive Principles on the websites above.
Well, here comes the boring part. Reactive Programming is presented in Java by Reactive Streams as interfaces and Project Reactor as implementation.
Let's take a closer look on them. Just four of them.
Reactive Programming - signals. The interaction between the publisher and the subscriber is being controlled by so-called "signals", it is a simple calling of the methods.
Reactive Programming - signals. The interaction between the publisher and the subscriber is being controlled by so-called "signals", it is a simple calling of the methods.
How to use them in your application? Just like this. If your method should return a single response - use Mono, otherwise - use Flux.
How to use them. The main idea is, that nothing happens until you call subscribe(). No framework would somehow find and run your Mono's and Flux'es for you. You should call them by yourself, or, for example, in case of WebFlux, it would be done by web-server.
How to use them. The main idea is, that nothing happens until you call subscribe(). No framework would somehow find and run your Mono's and Flux'es for you. You should call them by yourself, or, for example, in case of WebFlux, it would be done by web-server.
How to use them. The main idea is, that nothing happens until you call subscribe(). No framework would somehow find and run your Mono's and Flux'es for you. You should call them by yourself, or, for example, in case of WebFlux, it would be done by web-server.
How to use them. The main idea is, that nothing happens until you call subscribe(). No framework would somehow find and run your Mono's and Flux'es for you. You should call them by yourself, or, for example, in case of WebFlux, it would be done by web-server.
The Rx family of reactive libraries distinguishes two broad categories of reactive sequences: hot and cold. This distinction mainly has to do with how the reactive stream reacts to subscribers: A Cold sequence starts anew for each Subscriber, including at the source of data. For example, if the source wraps an HTTP call, a new HTTP request is made for each subscription. A Hot sequence does not start from scratch for each Subscriber. Rather, late subscribers receive signals emitted after they subscribed. Note, however, that some hot reactive streams can cache or replay the history of emissions totally or partially. From a general perspective, a hot sequence can even emit when no subscriber is listening (an exception to the “nothing happens before you subscribe” rule).
Okay, let's move to the comparison. In order to effectively compare perfomance of these two frameworks, we should compare their basis. Tomcat versus Netty.
Okay, let's move to the comparison. In order to effectively compare perfomance of these two frameworks, we should compare their basis. Tomcat versus Netty.
https://docs.spring.io/spring-boot/docs/1.2.3.RELEASE/reference/html/howto-embedded-servlet-containers.html https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/mvc.html Tomcat uses Thread-per-request model, which means, that Now let’s understand thread per request model, consider a traditional spring web application with spring mvc deployed on servlet container such as Tomcat.
Going back to the main topic - WebFlux. Why is it bad to keep using Spring MVC. Let's focus on Thread models. Java thread creation is expensive because there is a fair bit of work involved: - A large block of memory has to be allocated and initialized for the thread stack. - System calls need to be made to create / register the native thread with the host OS. - Descriptors need to be created, initialized and added to JVM-internal data structures. - It is also expensive in the sense that the thread ties down resources as long as it is alive; e.g. the thread stack, any objects reachable from the stack, the JVM thread descriptors, the OS native thread descriptors. The costs of all of these things are platform specific, but they are not cheap on any Java platform I've ever come across. [Threads are expensive.](https://www.ibm.com/docs/en/sdk-java-technology/7.1?topic=tstt-understanding-java-native-thread-details-1)
It means, that a hundred concurrent users would use a hundred threads.
One of the big technical challenges encountered when switching from an imperative programming perspective to a reactive programming mindset lies in how you deal with threading. Contrary to what you might be used to, in reactive programming, you can use a Thread to process several asynchronous sequences that run at roughly the same time (actually, in non-blocking locksteps). The execution can also easily and often jump from one thread to another. This arrangement is especially hard for developers that use features dependent on the threading model being more “stable,” such as ThreadLocal. As it lets you associate data with a thread, it becomes tricky to use in a reactive context. As a result, libraries that rely on ThreadLocal at least introduce new challenges when used with Reactor. At worst, they work badly or even fail. Using the MDC of Logback to store and log correlation IDs is a prime example of such a situation. The usual workaround for ThreadLocal usage is to move the contextual data, C, along your business data, T, in the sequence, by using (for instance) Tuple2<T, C>. This does not look good and leaks an orthogonal concern (the contextual data) into your method and Flux signatures.
- http-nio-8081-Poller - The background thread that adds sockets to the Poller, checks the poller for triggered events and hands the associated socket off to an appropriate processor as events occur. - http-nio-8081-Acceptor - The background thread that listens for incoming TCP/IP connections and hands them off to an appropriate processor.