My application is heavily relying on asynchronous web-services.
It is built with spring boot 1.5.x, which allows me to utilize standard Java 8 CompletableFuture<T> in order to produce deferred async responses. For more info see
https://nickebbitt.github.io/blog/2017/03/22/async-web-service-using-completable-future
Spring boot 2.0.x now comes with the starter pack that can utilize reactive paradigm. Spring WebFlux is the framework, which is implementing reactive HTTP.
Since I have my API implemented as described in the first paragraph, will I gain much by redoing my services to use non-blocking reactive approach? In a nutshell, I'll have non-blocking API as well, right?
Is there an example how to convert async API that is based on CompletableFuture<T> to Mono<T>\Flux<T>?
I was thinking to get rid of servlet-based server altogether (Jetty in my case) and go with Netty + Reactor.
Needless to say that I am new to the whole reactive paradigm.
I would like to hear your opinions.
I have two things to say:
Q: Is there an example how to convert async API that is based on CompletableFuture to Mono\Flux?
A:
1) You have to configure endpoint in a bit different way https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html
2) CompletableFuture to Mono\Flux example: Mono.fromFuture(...)
As for the question: "will I gain much by redoing my services to use non-blocking reactive approach". The general answer is provided in the documentation: https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-performance .. and it is no.
Performance has many characteristics and meanings. Reactive and non-blocking generally do not make applications run faster. They can, in some cases, (for example, if using the WebClient to run remote calls in parallel). On the whole, it requires more work to do things the non-blocking way and that can slightly increase the required processing time.
The key expected benefit of reactive and non-blocking is the ability to scale with a small, fixed number of threads and less memory. That makes applications more resilient under load, because they scale in a more predictable way. In order to observe those benefits, however, you need to have some latency (including a mix of slow and unpredictable network I/O). That is where the reactive stack begins to show its strengths, and the differences can be dramatic.
This is general answer, but the specifics will depend and you must measure and see. I would start by recreating a simple part of the application and checking the performance of both in an isolated environment.
Related
I'm trying to implement suppliers using Spring Cloud Function and Kafka. I need that one supplier should publish after every 10 secs and other should publish after every 30 secs. I could see from documentation, I can change delay using spring.cloud.stream.poller.fixed-delay property. Reference
But I need to set different delay for each topic. Is there any way to do it?
From the spring-cloud-function perspective there isn't any kind of polling as it is not the responsibility of the framework.
From the spring-cloud-stream perspective that uses spring-cloud-function indeed there is a mechanism that you have described. However, keep in mind that spring-cloud-stream is primarily designed to support concept of microservices (not your general messaging framework) and in microservices we embrace do one thing but do it well without affecting others approach. So having more then one supplier kind of goes against this model.
If you are building a general purpose messaging app, then i'd suggest to use Spring Integration framework which provides all the necessary hooks to accomplish what you need, but will require a bit more configuration details.
I am very new to reactive programming, and currently working on microservice where in spring mvc is used and Spring Data MongoDb for database connectivity.
As I am going through spring data mongo db docs, there is support for reactive repositories, reative template api etc.
So Is there going to be any downside if I choose to use reactive templates and repository with blocking nature ?
Ex.
reactiveMongoTemplate.add(entity).block()
reactiveMongoTemplate.update(id, entity).block()
Also is there any significant difference with using calls like above than using blocking repository and template api itself ?
The answer depends on which stack you use: Spring WebFlux or Spring Web MVC.
In case of Spring WebFlux the choice is obvious: you have to use ReactiveMongoTemplate and never call block on it, instead return Mono/Flux as you get it from the template.
In case of Spring Web MVC you are free to use both the regular blocking MongoTemplate and ReactiveMongoTemplate with block. Although, in most cases you should go with the good old MongoTemplate for sake of simplicity and performance. ReactiveMongoTemplate has some overhead compared to the blocking MongoTemplate because the reactive types Mono/Flux put some additional pressure on memory.
I can imagine one use case where ReactiveMongoTemplate can provide some advantage even in Spring MVC: when during one HTTP request you have to execute multiple Mono operations concurrently. If you used blocking MongoTemplate then you would need to set up a thread pool and delegate the query execution there. However, with ReactiveMongoTemplate you could use the many operators of Mono and Flux to accomplish this task without worrying about threads, thread pools and scaling issues.
In the traditional programming you usually own the thread that you're running on, in the reactive programming its not the case. This "underlying unit of execution" (cpu resources consumer if you wish) is not yours, but rather a "global" thing that currently happens to execute your task, but can switch to do other things really soon.
So when you block, you say to this "global unit of execution" like "hey, stop doing anything else, wait for me". In the traditional approach, its kind of ok, because you have a thread associated with the current request, other requests (or flows if your system is not web based) are supposed to be executed with other threads taken from a fairly large thread pool. In the reactive system however, its not the case since you're trying to utilize a small amount of these "global units of execution".
Ok, so if you block, the events all over the place will stop emitting and will get start to buffer. And this may lead to the whole system becoming unusable.
Let's imagine a scenario where there's an old app written using Servlet stack and you decide to migrate it to a Spring Webflux. Let's also say that first thing to migrate is RestTemplate to WebClient.
What would be preferred way of handling Mono or Flux that WebClient returns? Calling block seems okay solution since app uses RestTemplate which blocks anyway. subscribe should be a bit nicer since it has a callback, but maybe you have to wait to be able to continue. Also, with subscribe, do we need to handle a Disposable and, if yes, how, because I'm not sure where is the best place to call dispose on it?
And one more question regarding JDBC. How dangerous is to use Schedulers.boundedElastic()? From my understanding, having a separate thread pool should help especially if Netty is used. It's not ideal, but could it be a temporary solution until R2DBC drivers reach 1.0.0? What if app uses Tomcat? Is the situation better since Tomcat by default has more threads?
What would be preferred way of handling Mono or Flux that WebClient returns?
Given you're aiming to use Webflux, the ultimate preferred way is to deal with these publishers the entire way up your reactive chain. This means you won't end up calling subscribe on anything directly, because your controller will itself return a Mono (and everything, including the WebClient calls, will just be incorporated into that Mono via a series of reactive opreations in the chain.)
However, as you point out, you can't realistically migrate everything at once.
If it's only the WebClient that you're migrating for now, then just call block() to treat it the same way as your RestController. There's no advantage with calling subscribe() and then waiting for the subscription to complete - that's just a less obvious and more long-winded way of blocking.
Once you migrate more and more of your stack to reactive, you can do more and more in a reactive fashion, and then start to "move" your block() calls further up the chain as a result (until the block is at the controller level, and then you can just switch over to returning the Mono.)
Also, with subscribe, do we need to handle a Disposable
Only if you need to potentially cancel the subscriber (and it supports it.) This is quite a rare occurance in my experience.
And one more question regarding JDBC. How dangerous is to use Schedulers.boundedElastic()?
boundedElastic() is designed to be a wrapper for blocking IO, so there's nothing inherently wrong with using that on the reactor side. The only "danger" would be on the JDBC / app side as to if it fits your requirements:
It's capped at 10x the number of CPU cores
The number of "queued" tasks is capped at 100K
If you've got enough long running DB queries that this isn't enough, then you might consider using newBoundedElastic() instead and specifying the threadCap and queuedTaskCap manually.
What if app uses Tomcat? Is the situation better since Tomcat by default has more threads?
I wouldn't advise relying on it. Tomcat still uses one thread per request (even with Webflux), so the danger there is you end up blocking on a thread you shouldn't, and end up not realising and then relying on that behaviour (which would then all come tumbling down when you switched to Netty.)
Spring boot 2.1.5
Project Reactor 3.2.9
I am setting up a bunch of rest reactive APIs using the above-mentioned frameworks and I am running into an annoying problem with MDC (mapped diagnostic context). My applications are in JAVA.
MDC relies on thread locals to store the current query's mapped context to put in the logs. That system, obviously, is not perfect and contradicts the reactive pattern since the different steps of your execution will be executed through different threads.
I have run into the same problem with the Play Reactive framework but found a workaround there by copying the mapped context transparently from one actor to another.
For spring and reactor, I could not find a satisfying solution yet.
Some random examples found on the internet:
First - It works but forces you to use a bunch of utility methods
Same thing
Second - It tries to copy the context during the onNext publisher event but seems to lose some features on the way of doing that. The signal context, for example, is lost.
I am in need of a proper solution to deal with this:
A library which would make the link between MDC and reactor?
A way to tweak reactor/spring to achieve it transparently?
Any advice?
"I could not find a satisfying solution yet."
Working with contexts is the only solution for the moment. Since as you said threadlocals goes against everything that has to do with reactive programming. Using thread local as a storage point during a request is a resource heavy way of solving things and in my opinion poor design. Unless logging frameworks themselves come up with a better solution to the problem we developers must pass the data through the context to accommodate for the logging frameworks blocking nature.
Reactive programming is a paradigm shift in the programming world. Other things like database drivers, that use threadlocal to rollback transactions are also in big trouble. the JDBC database driver spec is defined as blocking in nature, and atm. there has been attempts by spring and the R2DBC project to define a new JDBC driver spec that is inherently non/blocking. This means that all vendors must rewrite ther database driver implementations from scratch.
Reactive program is so new that lots of libraries need to rewrite entire codebases. The logging frameworks as we know it needs to be rewritten from the ground up which is a huge task. And the context in reactive is actually something that should not even be in reactive programming, it was implemented just to accommodate for MDC problems.
It's actually a lot of overhead needing to pass data from thread to thread.
So what can we do?
push on logging frameworks, and/or help logging frameworks to rewrite their codebase
Accept that there is no "tweak" that will magically fix this
use the context and the way suggested in the blogposts
Project reactor context
Is it sensible to use Spring in the server side of an in memory data grid based application?
My gut feeling tells me that it is nonsense in a low latency high performance system. A colleague of mine is insisting on including Spring in it. What are the pros and cons of such inclusion?
My position is that Spring is OK to be used in the client but it is too heavy for the server, it brings too many dependancies and is one more leaky abstraction to think of.
Data Grid systems are memory and I/O intensive in general. Using Spring does not affect that (you may argue that Spring creates a lot of beans but with proper Garbage Collection tuning this is not a problem).
On the other hand using Spring (or any other DI) helps you structure and test your code.
So if you are using implementing some sort of server based on Data Grid systems, pay attention to properly adjusting GC, sockets in your OS (memory buffers and socket memories). Those will give you much more benefits than cutting down DI.
First, I'm surprised by the "leaky abstraction" comment. I've never heard anyone criticize Spring for this. In fact, it's just the opposite. Spring removes the implementation details of infrastructure such as data grids from your application code and provides a consistent and familiar programming model, allowing you to focus on business logic. Spring does a lot to enhance configuration and access to data grids, especially Gemfire, and generally does not create any runtime overhead per se. During initialization of a Spring application, Spring uses tools like reflection and AOP internally which may increase the start up time of an application, but this has no impact on runtime performance. Spring has been proven in many high-throughput, low-latency production applications. In extreme cases, things like network latency and serialization, concerns external to Spring, are normally the biggest factors affecting performance.
"Spring brings in too many dependencies" is a common complaint, but is a fallacy. I would say Spring brings in the exact right amount of dependencies for what it needs to do. Additionally, Spring Boot starters and the platform BOM do a lot to simplify dependency management so you don't need to worry about version incompatibilities or explicitly declaring common dependencies. I'll have to side with your colleague on this one.