UL Systems Advent Calendar 2019-Day 18
Today, [Eclipse MicroProfile OpenTracing] with reference to Tracing MP Guide of Helidon ](Https://github.com/eclipse/microprofile-opentracing) and Jaeger I would like to try out distributed tracing visualization. (The Tracing MP Guide uses Zipkin, but this time I would like to use Jaeger because of the cute logo.)
Recently, it has become more common to configure the entire system with a microservice architecture. At that time, if a failure or delay occurs in the process that spans multiple services with the method trace used in the conventional monolithic system, it is difficult to determine where it occurs, so the distribution is traced throughout. A mechanism called tracing is required.
An open source-based framework for developing lightweight microservices that can be used to create microservices for Java, announced by Oracle in September 2018.
This time we will use Helidon MP, which supports MaicroProfile.
Eclipse MicroProfile is a specification of the Enterprise Java API for microservices. It now includes APIs such as JAX-RS, JSON-P, and CDI, as well as APIs such as configuration, metrics, and fault tolerance. The Helidon MP used this time supports Eclipse MicroProfile 3.2.
OpenTracing consists of API specifications, frameworks and libraries that implement them, and project documentation. OpenTracing allows developers to add tracing functionality to their application code using APIs that are not locked to a particular product or vendor.
An open source OpenTracing compatible distributed tracing system inspired by Dapper and OpenZipkin and released by Uber Technologies. This time, the OpenTracing API part in the figure below is MicroProfile OpenTracing, and the jaeger-client part is the Client for Jaeger provided by Helidon.
First of all, I would like to set up the parts other than Client. Regarding the setup, the All-in-one Docker image is published, so use it. (Start by specifying only the minimum required ports)
$ docker run -d --name jaeger \
-p 5778:5778 \
-p 16686:16686 \
-p 14268:14268 \
jaegertracing/all-in-one:1.15
Helidon's jaeger-client seems to use HTTP 5778
by default.
(This can be changed by setting)
Then create the main service project using the Helidon MP Maven archetype quickstart.
$ mvn archetype:generate -DinteractiveMode=false \
-DarchetypeGroupId=io.helidon.archetypes \
-DarchetypeArtifactId=helidon-quickstart-mp \
-DarchetypeVersion=1.4.0 \
-DgroupId=io.helidon.main_service \
-DartifactId=main_service \
-Dpackage=io.helidon.main_service
Add the following dependency to pom.xml and add Jaeger Client.
pom.xml(add to)
<dependency>
<groupId>io.helidon.tracing</groupId>
<artifactId>helidon-tracing-jaeger</artifactId>
</dependency>
Specify the service name to be linked to the tracing data sent from Helidon to Jaeger in META-INF / microprofile-config.properties
.
microprofile-config.properties
tracing.service=helidon-main-service
Now, I would like to see the results created so far. The project created by quickstart is created so that the server can be started by executing the Main
method of the ʻio.helidon.main_service.Main` class.
If you access http: // localhost: 8080 / greet
after starting the server, the service created by quickstart will be executed and you should see{"message": "Hello World!"}
.
$ curl http://localhost:8080/greet
{"message":"Hello World!"}
If you look at the tracing data from the jaeger UI (http: // localhost: 16686 / search
) after accessing it several times, you should see the following tracing data.
Click each trace further to display the trace details page listing the spans. You can clearly see the root span and the relationships between all the spans in the trace, as well as timing information.
You can also see the details of the span by clicking each span row.
In addition, tracing at the class or method level is possible by adding the @Traced
annotation provided by MicroProfile OpenTracing.
GreetingProvider.java
@Traced
@ApplicationScoped
public class GreetingProvider {
...
}
Next, I would like to do tracing across services.
Create it using the Helidon MP Maven archetype quickstart as well as the Main service and add the Jaeger Client.
$ mvn archetype:generate -DinteractiveMode=false \
-DarchetypeGroupId=io.helidon.archetypes \
-DarchetypeArtifactId=helidon-quickstart-mp \
-DarchetypeVersion=1.4.0 \
-DgroupId=io.helidon.second_service \
-DartifactId=second_service \
-Dpackage=io.helidon.second_service
pom.xml(add to)
<dependency>
<groupId>io.helidon.tracing</groupId>
<artifactId>helidon-tracing-jaeger</artifactId>
</dependency>
Hello From Second Service
so that it can be easily identified as a return from the Second service.8081
.microprofile-config.properties(After change)
# Application properties. This is the default greeting
app.greeting=Hello From Second Service
# Microprofile server properties
server.port=8081
If you run the Second service and check the operation, the following results will be obtained.
$ curl http://localhost:8081/greet
{"message":"Hello From Second Service World!"}
Change to call the Second service from the Main service you created first.
First, you need to create a Rest Client in the Main service to call the Second service.
Unlike the Tracing MP Guide, I'd like to create it using the Micro Profile Rest Client
here.
SecondServiceClient.java
package io.helidon.main_service;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import javax.json.JsonObject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@RegisterRestClient(baseUri="http://localhost:8081")
public interface SecondServiceClient {
@Path("/greet")
@GET
JsonObject getDefaultMessage();
}
Then, use the created Client to call the Second service from the Main service. Inject the created SecondServiceClient into the calling class and call the Second service using SecondServiceClient to the method that originally returned the response.
GreetResource.java
@Path("/greet")
@RequestScoped
public class GreetResource {
@Inject
@RestClient
SecondServiceClient secondServiceClient;
@GET
@Produces(MediaType.APPLICATION_JSON)
public JsonObject getDefaultMessage() {
// return createResponse("World");
return secondServiceClient.getDefaultMessage();
}
Run the Main service on port 8080
and make sure the Second service is called.
$ curl http://localhost:8080/greet
{"message":"Hello From Second Service World!"}
This process is configured so that the request from the console turns the Main service and calls the Second service.
If you look at the tracing data of this request in Jaeger UI, it will take that much processing time as a whole, and you can check the processing flow.
This time I tried distributed tracing using Eclipse MicroProfile Open Tracing. If distributed tracing can be visualized when a distributed system is adopted, it may be easier to understand even if a system failure or delay occurs.
In addition to OpenTracing, Eclipse MicroProfile has specifications such as Eclipse MicroProfile Metrics and Eclipse MicroProfile Fault Tolerance, and Helidon also supports them. I think it can be considered as an option other than Spring Framework, such as migration from applications that are currently using Java EE.