I have Spring Cloud Sleuth (2.0.2.RELEASE) working within a (partially) reactive class in some web based request/response system. The code is something like this:
private static final Scheduler PROCESSING_SCHEDULER = Schedulers.newParallel("processingScheduler");
public Set<ProcessedItem> processItems(List<Item> incomingItems) {
return Flux.fromIterable(incomingItems)
.publishOn(PROCESSING_SCHEDULER)
.collectMultimap(Item::getRequestIdentifier)
.flatMapIterable(Map::values)
.flatMap(itemProcessor::processGroupedItems)
.collect(Collectors.toSet())
.block();
}
As there are quite many responses coming in all the time, this method is being called several hundreds of times for one single request.
I suspect that this call with the .publishOn leads to hundreds and thousands of async spans in Zipkin (see attached screenshot). At least I assume that the spans are from that because it is what I understand from the documentation
So my first question would be:
How can I associate a name for such async threads? I don't have a place to put #SpanName here.
As a follow up, is there any way to NOT collect these spans? I don't need them, they fill up our Zipkin storage, but I also don't want to disable reactive or Sleuth in general since it is needed in other places ...
Screenshot from Zipkin
You can create your own custom SpanAdjuster that will modify the span name. You can also use FinishedSpanHandler to operate on finished spans to tweak them.
Related
I would like to know is there, or can we make use of any functionality to log the actual time taken by a function returning Mono/Flux? For example something like creating a #Timed annotation to log the actual time taken by it.
I know the function return type being Flux/Mono, so it should return immediately so that is why I wanna know if we can actually do something like this so that we can know which modules/sub-modules are taking how much time?
We want to migrate our blocking spring-boot service to spring webflux, so going through all the possible options we have for better understanding.
P.S. I am new To reactive programming, still learning the paradigm.
You can use metrics() operator to time a publisher. You can combine this with the name() and tags() operators to customise the metrics that get published.
listenToEvents()
.name("events")
.tag("source", "kafka")
.metrics()
.doOnNext(event -> log.info("Received {}", event))
.delayUntil(this::processEvent)
.subscribe();
Publisher metrics docs
I am currently trying to understand how I can customize Spring Cloud Sleuth in a scalable way to add information to every Span.
What I have tried so far:
Using my own implementation of GenericFilterBean and HandlerInterceptorAdapter, give them a Tracer in the constructor and write Tags everytime they are called with tracer.addTag("key", "value")
I had a look at the idea of the new baggage information - however I interpret it in a way that it is global for the whole trace - and as the trace has several requests accross different services/machines it would not fit my purpose of adding information on service/machine level.
So far the tags from the Filter and Interceptor get set for some Spans but not for all, when I inspect the JSON that is written to my kafka topic through spring-cloud-stream-binder-kafka
So my question would be: Which types of requests/actions do exist that create spans and what are the appropriate ways to inject something into those spans. As I want to deploy this implementation to several micro services I do not want to annotate each and every method or do similarly work intensive and therefor not scalable approaches.
There are a lot of such places... but actually, we can tackle the problem from another angle. There's a single place where you can hook in - when the span is closed. https://github.com/spring-cloud/spring-cloud-sleuth/blob/master/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanReporter.java - you can create your own implementation of SpanReporter that before delegating to for example Zipkin span reporter will add a tag. Even easier way will be to just register the SpanAdjuster bean that adjusts the span before it gets reported. That way you can add the tag only in one place.
I am fetching data from several different APIs. They are rest and soap web services. I have one id that I pass to each API one by one and get data in return. But each API takes few seconds to return the result and so the final response object that I create takes too much time.
My application is a Spring 4 Rest Service. What is the best way to call all these several APIs in parallel so that my Response time reduces to as less as possible.
Thanks.
You can use #Async annotation. You can find an example here
Daniel's answer is right but I would like to add something more to it. If you want to do something with your results but don't want to block with Future#get then I would suggest you to use CompletableFuture class.
It will let you add various actions which will be triggered on its completion.
There is also a really nice article on how to use CompletableFuture with Spring's #async annotation. Here it the link. Completable futures with Spring async
I am looking at microservices, and the possibility of migrating some of our code to this architecture. I understand the general concept but am struggling to see how it would work for our example.
Supposing I have an interface called RatingEngine and an implementation called RatingEngineImpl, both running inside my monolithic application. The principle is simple - The RatingEngineImpl could run in a different machine, and be accessed by the monolithic application via (say) a REST API, serializing the DTOs with json over http. We even have an interface to help with this decoupling.
But how do I actually go about this? As far as I can see, I need to create a new implementation of the interface for the rump monolith (ie now the client), which takes calls to the interface methods, converts them into a REST call, and sends them over the network to the new 'rating engine service'. Then I also need to implement a new http server, with an endpoint for each interface method, which then deserializes the DTOs (method parameters) and routes the call to our original RatingEngineImpl, which sits inside the server. Then it serializes the response and sends it back to the client.
So that seems like an awful lot of plumbing code. It also adds maintenance overhead, since if you tweak a method in the interface you need to make changes in two more places.
Am I missing something? Is there some clever way we can automate this boilerplate code construction?
The Microservice pattern does not suggest you move every single service you have to it's own deployable. Only move self sustaining pieces of logic that will benefit from it's own release cycle. I.e. if your RatingEngine needs rating-logic updates weekly, but the rest of your system is pretty stable - it will likely benefit from beeing a service of it's own.
And yes - Microservices adds complexity, but not really boiler plate code of HTTP servers. There are a lot of frameworks around to deal with that. Vert.x is one good. Others are Spring Boot, Apache Camel etc. A complete microservice setup could look like this with Vert.x.
public class RatingService extends AbstractVerticle implements RatingEngine{
public void start() {
vertx.createHttpServer().requestHandler(req -> {
req.response()
.putHeader("content-type", "application/json")
.end(computeCurrentRating().encodePrettily());
}).listen(8080);
}
#Override
public int getRating(){
return 4; // or whatever.
}
protected JsonObject computeCurrentRating(){
return new JsonObject().put("rating", getRating());
}
}
Even the Java built-in framework JAX-RS helps making a microservice in not too many lines of code.
The really hard work with microservices is to add error-handling logic in the clients. Some common pitfalls
Microservice may go down If call to RatingService gives connection refused exception - can you deal with it? Can you estimate a "rating" in client to not prevent further processing? Can you reuse old responses to estimate the rating? .. Or at least - you need to signal the error to support staff.
Reactive app? How long can you wait for a response? A call to in memory methods will return within nano seconds, a call to an external HTTP service may take seconds or minutes depending on a number of factors. As long as the application is "reactive" and can continue to work without a "Rating" - and present the rating for the user once it's available - it's fine. If you are waiting for a blocking call to rating service, more than a few millisec. - response time becomes an obstacle. It's not as convenient/common to make reactive apps in Java as in node.js. A reactive approach will likely trigger a remake of you entire system.
Tolerant client Unit/integration testing a single project is easy. Testing a complex net of microservices is not. The best thing you can do about it is to make your client call less picky. Schema validations etc. are actually bad things. In XML use single XPaths to get data you want from the response, not more not less. That way, a change in the microservice response will not require updates of all clients. JSON is a bit easier to deal with than XML in this aspect.
No, unfortunately you do not miss anything substantial. The microservice architecture comes with its own cost. The one that caught your eye (boilerplate code) is one well-known item from the list. This is a very good article from Martin Fowler explaining the various advantages and disadvantages of the idea. It includes topics like:
added complexity
increased operational maintance cost
struggle to keep consistency (while allowing special cases to be treated in exceptional ways)
... and many more.
There are some frameworks out there to reduce such a boilerplate code. I use Spring Boot in a current project (though not for microservices). If you already have Spring based projects, then it really simplifies the development of microservices (or any other not-Microservice-application based on Spring). Checkout some of the examples: https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples
I use play framework 2.2.1.
I want to calculate the number of total requests received by playframework. However, I've found that every request is added up by multiple times e.g. 2,3 etc. when i handle it in the onRouteRequest method as below.
Any idea what is the problem?
#Override
public Handler onRouteRequest(play.mvc.Http.RequestHeader request){
TotalRequests +=1;
return super.onRouteRequest(request);
}
I'm not sure why the method should be invoked twice. However, rather than using this method, you could alternative make use of a filter. Filters are not yet available in the Java API but it should be relatively easy to write a Filter that does exactly what you are looking for, see for instance this answer.
Another alternative, rather than rolling your own request counting, would be to make use of a plugin such as the play2-metrics plugin that integrates the metrics library.