LoginSignup
4
3

More than 5 years have passed since last update.

Jersey (JAX-RS2) アプリケーションに Zipkin を導入してみる

Last updated at Posted at 2018-01-03

したいこと

Jersey で作った JAX-RS2 Java アプリケーションを Zipkin でトレーシングします。

jersey-zipkin.png

Zipkin サーバーを立てる

docker をインストールします.

  • Mac / Windows / Linuxはパッケージ管理で入れる

Linux は docker-compose を追加でインストールします. Mac, Windows は Docker installer に同梱されているので不要です

sudo curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

github から docker-zipkin をクローンして dockerZipkin サーバーを動かします

git clone https://github.com/openzipkin/docker-zipkin.git
cd docker-zipkin
docker-compose up -d

次のURLで Zipkin の Web UI にアクセスできます

アプリケーションを実装する

アプリケーションは表題の通り Jersey で作ります. 完成したものを github に上げました.

依存ライブラリ (pom.xml)

サーバーサイド JAX-RS2 参照実装である Jersey 2 を利用します.

Jerseyでググると良く出る、groupId=com.sun.jersey は Jersey 1系で互換性がないので注意.

<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-server -->
<dependency>
  <groupId>org.glassfish.jersey.core</groupId>
  <artifactId>jersey-server</artifactId>
  <version>2.26</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.inject/jersey-hk2 -->
<dependency>
  <groupId>org.glassfish.jersey.inject</groupId>
  <artifactId>jersey-hk2</artifactId>
  <version>2.26</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.containers/jersey-container-servlet -->
<dependency>
  <groupId>org.glassfish.jersey.containers</groupId>
  <artifactId>jersey-container-servlet</artifactId>
  <version>2.26</version>
</dependency>

クライアントサイド JAX-RS2 も参照実装である Jersey 2 を利用します.

<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-client -->
<dependency>
  <groupId>org.glassfish.jersey.core</groupId>
  <artifactId>jersey-client</artifactId>
  <version>2.26</version>
</dependency>

Javaで書いた Web Application は普段は Tomcat, Glassfish, Jetty 等で動かしますが、今回は簡単の為 jersey-container-jdk-http を利用してHttpサーバー実装をアプリケーションに直接埋め込みます.

<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.containers/jersey-container-jdk-http -->
<dependency>
  <groupId>org.glassfish.jersey.containers</groupId>
  <artifactId>jersey-container-jdk-http</artifactId>
  <version>2.26</version>
</dependency>

JAX-RS2 Javaアプリケーション用の Zipkin Instrumentation ライブラリです. これを使って JAX-RSサーバー/クライアントでトレーシングが出来るようになります.

<!-- https://mvnrepository.com/artifact/io.zipkin.brave/brave-instrumentation-jaxrs2 -->
<dependency>
  <groupId>io.zipkin.brave</groupId>
  <artifactId>brave-instrumentation-jaxrs2</artifactId>
  <version>4.3.1</version>
</dependency>

収集したトレーシングデータは Zipkin サーバーに送信しなければなりません. このライブラリが任意の宛先に送信してくれます.

<!-- https://mvnrepository.com/artifact/io.zipkin.reporter/zipkin-sender-urlconnection -->
<dependency>
  <groupId>io.zipkin.reporter</groupId>
  <artifactId>zipkin-sender-urlconnection</artifactId>
  <version>1.1.2</version>
</dependency>

Java コード

JAX-RS2 では javax.ws.rs.core.Feature IFを実装した外部ライブラリをプラグインできます.

Javaアプリケーション向けの Zipkin ライブラリである Brave は様々なJavaフレームワークに対応しています. 今回は JAX-RS2 用の brave-instrumentation-jaxrs2 を使用します.

  • brave.jaxrs2.TracingFeature は JAX-RS2 用のトレーシング実装 (Trace Instrumentation) で、トレーシングデータを作成 します
  • zipkin.reporter.AsyncReporter はアプリケーション上に集めたトレーシングデータを Zipkin サーバーに送信します
package zipkin;

import brave.Tracing;
import brave.jaxrs2.TracingFeature;
import brave.sampler.Sampler;
import zipkin.reporter.AsyncReporter;
import zipkin.reporter.urlconnection.URLConnectionSender;
import javax.ws.rs.core.Feature;

public class ZipkinFeature {

    /**
     * @param localServiceName Zipkin Web UI に表示されるサービス名
     */
    public static Feature create(String localServiceName) {
        // create a zipkin reporter.
        AsyncReporter<Span> asyncReporter = AsyncReporter
                .builder(URLConnectionSender.create("http://localhost:9411/api/v1/spans"))
                .build();

        // create a zipkin tracing.
        Tracing tracing = Tracing.newBuilder()
                .reporter(asyncReporter)
                .localServiceName(localServiceName)
                .sampler(Sampler.ALWAYS_SAMPLE)
                .build();

        // create a JAX-RS feature.
        Feature tracingFeature = TracingFeature.create(tracing);

        return tracingFeature;
    }
}

サーバーサイド JAX-RS2 のエントリポイントである javax.ws.rs.core.Application IFを実装したクラスを作ります. ここで先程生成したトレーシング機能 brave.jaxrs2.TracingFeature をサーバーサイド JAX-RS2 に登録します.

package app;

import zipkin.ZipkinFeature;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Feature;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;

@ApplicationPath("")
public class MyApplication extends Application {

    @Override
    public Set<Object> getSingletons() {
        // create a JAX-RS feature.
        Feature tracingFeature = ZipkinFeature.create("server");

        return new LinkedHashSet<>(Arrays.asList(tracingFeature));
    }
}

サーバーサイド JAX-RS2 のリソースクラス (API定義) を作ります. 本来は複数のサービスをデプロイして Zipkin の動作を確認したいのですが、簡単化の為に 3 API を定義し、クライアント JAX-RS2 で順に呼んでいます.
ここでも先程生成したトレーシング機能 brave.jaxrs2.TracingFeature をクライアント JAX-RS2 に登録しています.

  • /front --> /mid --> /back
package resource;

import zipkin.ZipkinFeature;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("")
public class MyResource {

    /**
     * /front --> /mid --> /back
     *
     * @return String that will be returned as a text/plain response.
     */
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("front")
    public Response front() {
        // create a JAX-RS feature.
        Feature tracingFeature = ZipkinFeature.create("client");

        // http client: GET /mid
        Response r = ClientBuilder.newClient()
                .register(tracingFeature)
                .target("http://localhost:8080/myapp/mid")
                .request()
                .get();

        return Response.fromResponse(r).build();
    }

    /**
     * /mid --> /back
     *
     * @return String that will be returned as a text/plain response.
     */
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("mid")
    public Response mid() {
        // create a JAX-RS feature.
        Feature tracingFeature = ZipkinFeature.create("client");

        // http client: GET /back
        Response r = ClientBuilder.newClient()
                .register(tracingFeature)
                .target("http://localhost:8080/myapp/back")
                .request()
                .get();

        return Response.fromResponse(r).build();
    }

    /**
     * /back
     *
     * @return String that will be returned as a text/plain response.
     */
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("back")
    public String back() {
        return "hello";
    }
}

簡単に動かしたいので、Httpサーバー実装には jersey-container-jdk-http を使用します。

package main;

import app.MyApplication;
import com.sun.net.httpserver.HttpServer;
import org.glassfish.jersey.jdkhttp.JdkHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import java.net.URI;

public class Main {

    public static void main(String[] args) {
        // register JAX-RS Application class.
        ResourceConfig rc = ResourceConfig.forApplicationClass(MyApplication.class);

        // register a path of REST resources.
        rc.packages(true, "resource");

        // run a jersey server.
        URI uri = URI.create("http://localhost:8080/myapp/");
        HttpServer httpServer = JdkHttpServerFactory.createHttpServer(uri, rc);
        Runtime.getRuntime().addShutdownHook(new Thread(() -> httpServer.stop(0)));
    }
}

アプリケーションを実行します. 以下のURLでアクセスできます.

Zipkin Web UI にアクセスしましょう. 先程アクセスした際のトレーシングデータが見れる筈です.

zipkin.png

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3