Microservices distributed tracing with Zipkin and Micronaut

Use Zipkin distributed tracing to investigate the behaviour of your Micronaut apps.

Authors: Sergio del Amo

Micronaut Version: 1.0.0.M4

1 Getting Started

In this guide, we are going to integrate Zipkin in a Micronaut app composed of three microservices.

Zipkin is a distributed tracing system. It helps gather timing data needed to troubleshoot latency problems in microservice architectures. It manages both the collection and lookup of this data.

You will discover how Micronaut eases Zipkin integration.

1.1 What you will need

To complete this guide, you will need the following:

  • Some time on your hands

  • A decent text editor or IDE

  • JDK 1.8 or greater installed with JAVA_HOME configured appropriately

1.2 Solution

We recommend you to follow the instructions in the next sections and create the app step by step. However, you can go right to the completed example.

or

Then, cd into the complete folder which you will find in the root project of the downloaded/cloned project.

2 Writing the App

The initial folder contains a sample application. To learn more about this sample app read Consul and Micronaut - Microservices service discovery guide. The application contains three microservices.

  • bookcatalogue - It returns a list of books. It uses a domain consisting of a book name and isbn.

  • bookinventory - It exposes an endpoint to check whether a book has sufficient stock to fullfil an order. I uses a domain consisting of a stock level and isbn.

  • bookrecommendation - It consumes previous services and exposes and endpoint which recommends book names which are in stock.

The bookcatalogue service consumes endpoints exposed by the other services. The following image illustrates the application flow:

flow

If you are using Java or Kotlin and IntelliJ IDEA make sure you have enabled annotation processing.

annotationprocessorsintellij

3 Zipkin and Micronaut

3.1 Install Zipkin via Docker

The quickest way to start Zipkin is via Docker:

$ docker run -d -p 9411:9411 openzipkin/zipkin

3.2 Integrate Zipkin

3.3 Book Catalogue

Modify build.gradle to add tracing dependency.

bookcatalogue/build.gradle
dependencies {
    ...
    ..
    .
    compile "io.micronaut:tracing"
}

Also, to send tracing spans to Zipkin the minimal configuration requires you add the following dependencies to build.gradle:

bookcatalogue/build.gradle
dependencies {
    ...
    ..
    .
    runtime 'io.zipkin.brave:brave-instrumentation-http:4.19.0'
    runtime 'io.zipkin.reporter2:zipkin-reporter:2.5.0'
    compile 'io.opentracing.brave:brave-opentracing:0.30.0'
}

Append to bookcatalogue service application.yml the following snippet:

bookcatalogue/src/main/resources/application.yml
tracing:
    zipkin:
        http:
            url: http://localhost:9411
        enabled: true
        sampler:
            probability: 1 (1)
1 Trace 100% of requests.

In production, you will probably want to trace a smaller percentage of the requests. However, in order to keep this tutorial easy, we set it to trace 100%.

Disable distributed tracing in tests:

bookcatalogue/src/main/resources/application-test.yml
tracing:
    zipkin:
        enabled: false

3.4 Book Inventory

Modify build.gradle to add tracing dependency.

bookinventory/build.gradle
dependencies {
    ...
    ..
    .
    compile "io.micronaut:tracing"
}

Also, to send tracing spans to Zipkin the minimal configuration requires you add the following dependencies to build.gradle:

bookinventory/build.gradle
dependencies {
    ...
    ..
    .
    runtime 'io.zipkin.brave:brave-instrumentation-http:4.19.0'
    runtime 'io.zipkin.reporter2:zipkin-reporter:2.5.0'
    compile 'io.opentracing.brave:brave-opentracing:0.30.0'
}

Append to bookinventory service application.yml the following snippet:

bookinventory/src/main/resources/application.yml
tracing:
    zipkin:
        http:
            url: http://localhost:9411
        enabled: true
        sampler:
            probability: 1 (1)
1 Trace 100% of requests.

In production, you will probably want to trace a smaller percentage of the requests. However, in order to keep this tutorial easy, we set it to trace 100%.

Disable distributed tracing in tests:

bookinventory/src/main/resources/application-test.yml
tracing:
    zipkin:
        enabled: false

Annotate BookController method with @ContinueSpan and the method parameter with @SpanTag:

bookinventory/src/main/java/example/micronaut/bookinventory/BooksController.java
Unresolved directive in <stdin> - include::/home/travis/build/micronaut-guides/micronaut-microservices-distributed-tracing-zipkin-kotlin/complete/bookinventory/src/main/java/example/micronaut/bookinventory/BooksController.java[]
1 The @ContinueSpan annotation will continue an existing span, wrapping the method call or reactive type.
2 The @SpanTag annotation can be used on method arguments to include the value of each argument within a Span’s tags. When you use @SpanTag you need either to annotate the method with @NewSpan or @ContinueSpan`

3.5 Book Recommendation

Modify build.gradle to add tracing dependency.

bookrecommendation/build.gradle
dependencies {
    ...
    ..
    .
    compile "io.micronaut:tracing"
}

Also, to send tracing spans to Zipkin the minimal configuration requires you add the following dependencies to build.gradle:

bookrecommendation/build.gradle
dependencies {
    ...
    ..
    .
    runtime 'io.zipkin.brave:brave-instrumentation-http:4.19.0'
    runtime 'io.zipkin.reporter2:zipkin-reporter:2.5.0'
    compile 'io.opentracing.brave:brave-opentracing:0.30.0'
}

Append to bookrecommendation service application.yml the following snippet:

bookrecommendation/src/main/resources/application.yml
tracing:
    zipkin:
        http:
            url: http://localhost:9411
        enabled: true
        sampler:
            probability: 1 (1)
1 Trace 100% of requests.

In production, you will probably want to trace a smaller percentage of the requests. However, in order to keep this tutorial easy, we set it to trace 100%.

Disable distributed tracing in tests:

bookrecommendation/src/main/resources/application-test.yml
tracing:
    zipkin:
        enabled: false

4 Running the app

Run bookcatalogue microservice:

bookcatalogue $ ./gradlew run
 Starting a Gradle Daemon, 2 stopped Daemons could not be reused, use --status for details

 > Task :bookcatalogue:compileJava
 Note: Creating bean classes for 1 type elements

 > Task :bookcatalogue:run
 14:28:34.034 [main] INFO  io.micronaut.runtime.Micronaut - Startup completed in 499ms. Server Running: http://localhost:8081

Run bookinventory microservice:

bookinventory $ ./gradlew run
 Starting a Gradle Daemon, 2 stopped Daemons could not be reused, use --status for details

 > Task :bookinventory:compileJava
 Note: Creating bean classes for 1 type elements

 > Task :bookcatalogue:run
 14:31:13.104 [main] INFO  io.micronaut.runtime.Micronaut - Startup completed in 499ms. Server Running: http://localhost:8082

Run bookrecommendation microservice:

bookrecommendation $ ./gradlew run
Starting a Gradle Daemon, 2 busy and 2 stopped Daemons could not be reused, use --status for details

> Task :bookrecommendation:compileJava
Note: Creating bean classes for 3 type elements

> Task :bookrecommendation:run
14:31:57.389 [main] INFO  io.micronaut.runtime.Micronaut - Startup completed in 523ms. Server Running: http://localhost:8080

You can run a cURL command to test the whole application:

$ curl http://localhost:8080/books
[{"name":"Building Microservices"}

You can then navigate to http://localhost:9411 t to access the Jaeger UI.

The previous request generates a trace composed by 5 spans.

zipkinui

In the previous image, you can see the requests to bookinventory are done in paralell.

You can see the details if you click the span:

zipkinclientserver

In the previous image, you can see that:

  • Whenever a Micronaut HTTP client executes a new network request, a span is involved.

  • Whenever a Micronaut Server receives a request, a span is involved.

The stock.isbn tags that we configured with @SpanTag is present as shown in the next image:

zipkintag

5 Next Steps

As you have seen in this tutorial, without any annotations you get distributing tracing up-and-running fast with Micronaut.

Micronaut includes several annotations to give you more flexibility. We introduced the @ContinueSpan, @SpanTag annotations. Also, you have at your disposal the @NewSpan annotation which will create a new span, wrapping the method call or reactive type.

Make sure to read more about Tracing with Zipkin inside Micronaut.