Zipkin は分散トレーシングシステムです。これは、リアルタイムデータの追跡のために Twitter によって開発されたオープンソースシステムです。Zipkin は、複数の異種システムから収集されたリアルタイムの監視データを集約するために使用されます。Zipkin を使用して、Java アプリケーションデータを Tracing Analysis に送信できます。
前提条件
背景情報
Zipkin は長年にわたって開発されており、次のような Java フレームワークなど、包括的なフレームワークセットをサポートしています。詳細については、brave-instrumentation を参照してください。
- Apache HttpClient
- Dubbo
- gRPC
- JAX-RS 2.X
- Jersey Server
- Java Message Service (JMS)
- Kafka
- MySQL
- Netty
- OkHttp
- Servlet
- Spark
- Spring Boot
- Spring MVC
Zipkin を使用して Java アプリケーションデータを Tracing Analysis コンソールに送信するには、最初にアプリケーションをインストラメント化する必要があります。アプリケーションのインストラメント化は、手動で行うか、既存のコンポーネントを使用して行うことができます。
Java アプリケーションを手動でインストラメント化する
Java アプリケーションを手動でインストラメント化する場合は、インストラメント化コードを記述する必要があります。
- JAR パッケージを依存関係として追加します。
<dependency> <groupId>io.zipkin.brave</groupId> <artifactId>brave</artifactId> <version>5.4.2</version> </dependency> <dependency> <groupId>io.zipkin.reporter2</groupId> <artifactId>zipkin-sender-okhttp3</artifactId> <version>2.7.9</version> </dependency>
- トレーサーを作成します。
private static final String zipkinEndPoint = "<endpoint>"; ... // Create an object that is used to send data. OkHttpSender sender = OkHttpSender.newBuilder().endpoint(zipkinEndPoint).build(); // Create an object that is used to report data. Reporter<Span> reporter = AsyncReporter.builder(sender).build(); tracing = Tracing.newBuilder().localServiceName(localServiceName).spanReporter(reporter).build();
- スパンと子スパンを作成します。
private void firstBiz() { // Create a root span. tracing.tracer().startScopedSpan("parentSpan"); Span span = tracing.tracer().currentSpan(); span.tag("key", "firstBiz"); secondBiz(); span.finish(); } private void secondBiz() { tracing.tracer().startScopedSpanWithParent("childSpan", tracing.tracer().currentSpan().context()); Span childSpan = tracing.tracer().currentSpan(); childSpan.tag("key", "secondBiz"); childSpan.finish(); System.out.println("end tracing,id:" + childSpan.context().traceIdString()); }
- オプション。迅速なトラブルシューティングのために、スパンにカスタムタグを追加します。たとえば、リクエストの戻り値を記録したり、エラーが発生したかどうかを確認したりするために、カスタムタグを追加できます。
tracer.activeSpan().setTag("http.status_code", "500");
- 分散システムでは、リモートプロシージャコール (RPC) リクエストはトレースデータとともに送信されます。トレースデータには、TraceId、ParentSpanId、SpanId、および Sampled パラメータの値が含まれています。Extract または Inject メソッドを呼び出して、HTTP リクエストヘッダーでデータを指定できます。次の例は、プロセス全体を示しています。
- クライアントで Inject メソッドを呼び出して、コンテキスト情報を指定します。
// start a new span representing a client request oneWaySend = tracer.nextSpan().name(service + "/" + method).kind(CLIENT); --snip-- // Add the trace context to the request, so it can be propagated in-band tracing.propagation().injector(Request::addHeader) .inject(oneWaySend.context(), request); // fire off the request asynchronously, totally dropping any response request.execute(); // start the client side and flush instead of finish oneWaySend.start().flush();
- サーバーで Extract メソッドを呼び出して、コンテキスト情報を抽出します。
// pull the context out of the incoming request extractor = tracing.propagation().extractor(Request::getHeader); // convert that context to a span which you can name and add tags to oneWayReceive = nextSpan(tracer, extractor.extract(request)) .name("process-request") .kind(SERVER) ... add tags etc. // start the server side and flush instead of finish oneWayReceive.start().flush(); // you should not modify this span anymore as it is complete. However, // you can create children to represent follow-up work. next = tracer.newSpan(oneWayReceive.context()).name("step2").start();
- クライアントで Inject メソッドを呼び出して、コンテキスト情報を指定します。
Spring 2.5 MVC または Spring 3.0 MVC を使用して Java アプリケーションをインストラメント化する
Spring 2.5 MVC または Spring 3.0 MVC を使用して Java アプリケーションをインストラメント化できます。
- applicationContext.xml ファイルでトレーシングオブジェクトを設定します。
<bean class="zipkin2.reporter.beans.OkHttpSenderFactoryBean"> <property name="endpoint" value="<endpoint>"/> </bean> <!-- allows us to read the service name from spring config --> <context:property-placeholder/> <bean class="brave.spring.beans.TracingFactoryBean"> <property name="localServiceName" value="brave-webmvc3-example"/> <property name="spanReporter"> <bean class="zipkin2.reporter.beans.AsyncReporterFactoryBean"> <property name="encoder" value="JSON_V2"/> <property name="sender" ref="sender"/> <!-- wait up to half a second for any in-flight spans on close --> <property name="closeTimeout" value="500"/> </bean> </property> <property name="propagationFactory"> <bean class="brave.propagation.ExtraFieldPropagation" factory-method="newFactory"> <constructor-arg index="0"> <util:constant static-field="brave.propagation.B3Propagation.FACTORY"/> </constructor-arg> <constructor-arg index="1"> <list> <value>user-name</value> </list> </constructor-arg> </bean> </property> <property name="currentTraceContext"> <bean class="brave.spring.beans.CurrentTraceContextFactoryBean"> <property name="scopeDecorators"> <bean class="brave.context.log4j12.MDCScopeDecorator" factory-method="create"/> </property> </bean> </property> </bean> <bean class="brave.spring.beans.HttpTracingFactoryBean"> <property name="tracing" ref="tracing"/> </bean>
- interceptors オブジェクトを追加します。
<bean class="brave.httpclient.TracingHttpClientBuilder" factory-method="create"> <constructor-arg type="brave.http.HttpTracing" ref="httpTracing"/> </bean> <bean factory-bean="httpClientBuilder" factory-method="build"/> <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"> <property name="interceptors"> <list> <bean class="brave.spring.webmvc.SpanCustomizingHandlerInterceptor"/> </list> </property> </bean> <!-- Loads the controller --> <context:component-scan base-package="brave.webmvc"/>
- filter オブジェクトを追加します。
<!-- Add the delegate to the standard tracing filter and map it to all paths --> <filter> <filter-name>tracingFilter</filter-name> <filter-class>brave.spring.webmvc.DelegatingTracingFilter</filter-class> </filter> <filter-mapping> <filter-name>tracingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Spring 4.0 MVC または Spring Boot を使用して Java アプリケーションをインストラメント化する
Spring 4.0 MVC または Spring Boot を使用して Java アプリケーションをインストラメント化できます。
- トレーシングオブジェクトとフィルターオブジェクトを設定します。
/** Configuration for how to send spans to Zipkin */ @Bean Sender sender() { return OkHttpSender.create("<endpoint>"); // Zipkin へのスパン送信方法の設定 } /** Configuration for how to buffer spans into messages for Zipkin */ @Bean AsyncReporter<Span> spanReporter() { return AsyncReporter.create(sender()); // Zipkin へのメッセージのバッファ方法の設定 } /** Controls aspects of tracing such as the name that shows up in the UI */ @Bean Tracing tracing(@Value("${spring.application.name}") String serviceName) { return Tracing.newBuilder() // UI に表示される名前など、トレースの側面を制御します .localServiceName(serviceName) .propagationFactory(ExtraFieldPropagation.newFactory(B3Propagation.FACTORY, "user-name")) .currentTraceContext(ThreadLocalCurrentTraceContext.newBuilder() .addScopeDecorator(MDCScopeDecorator.create()) // puts trace IDs into logs //トレースIDをログに記録 .build() ) .spanReporter(spanReporter()).build(); } /** decides how to name and tag spans. By default they are named the same as the http method. */ @Bean HttpTracing httpTracing(Tracing tracing) { return HttpTracing.create(tracing); // スパンの名前付けとタグ付け方法を決定します。デフォルトでは、HTTP メソッドと同じ名前が付けられます。 } /** Creates client spans for http requests */ // We are using a BPP as the Frontend supplies a RestTemplate bean prior to this configuration @Bean BeanPostProcessor connectionFactoryDecorator(final BeanFactory beanFactory) { return new BeanPostProcessor() { // HTTP リクエストのクライアントスパンを作成します @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) { if (!(bean instanceof RestTemplate)) return bean; RestTemplate restTemplate = (RestTemplate) bean; List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>(restTemplate.getInterceptors()); interceptors.add(0, getTracingInterceptor()); restTemplate.setInterceptors(interceptors); return bean; } // Lazy lookup so that the BPP doesn't end up needing to proxy anything. ClientHttpRequestInterceptor getTracingInterceptor() { return TracingClientHttpRequestInterceptor.create(beanFactory.getBean(HttpTracing.class)); } }; } /** Creates server spans for http requests */ @Bean Filter tracingFilter(HttpTracing httpTracing) { return TracingFilter.create(httpTracing); // HTTP リクエストのサーバースパンを作成します } @Autowired SpanCustomizingAsyncHandlerInterceptor webMvcTracingCustomizer; /** Decorates server spans with application-defined web tags */ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(webMvcTracingCustomizer); // サーバースパンをアプリケーション定義の Web タグで装飾します }
- spring.factories ファイルで自動設定を設定します。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ brave.webmvc.TracingConfiguration
Dubbo を使用して Java アプリケーションをインストラメント化する
Dubbo を使用して Java アプリケーションをインストラメント化できます。
- JAR パッケージを依存関係として追加します。
<dependency> <groupId>io.zipkin.brave</groupId> <artifactId>brave-instrumentation-dubbo-rpc</artifactId> <version>5.4.2</version> </dependency> <dependency> <groupId>io.zipkin.brave</groupId> <artifactId>brave-spring-beans</artifactId> <version>5.4.2</version> </dependency> <dependency> <groupId>io.zipkin.brave</groupId> <artifactId>brave-context-slf4j</artifactId> <version>5.4.2</version> </dependency> <dependency> <groupId>io.zipkin.reporter2</groupId> <artifactId>zipkin-sender-okhttp3</artifactId> <version>2.7.9</version> </dependency> <dependency> <groupId>io.zipkin.brave</groupId> <artifactId>brave</artifactId> <version>5.4.2</version> </dependency> <dependency> <groupId>io.zipkin.reporter2</groupId> <artifactId>zipkin-sender-okhttp3</artifactId> <version>2.7.9</version> </dependency>
- トレーシングオブジェクトを設定します。
<bean class="zipkin2.reporter.beans.OkHttpSenderFactoryBean"> <property name="endpoint" value="<endpoint>"/> </bean> <bean class="brave.spring.beans.TracingFactoryBean"> <property name="localServiceName" value="double-provider"/> <property name="spanReporter"> <bean class="zipkin2.reporter.beans.AsyncReporterFactoryBean"> <property name="sender" ref="sender"/> <!-- wait up to half a second for any in-flight spans on close --> <property name="closeTimeout" value="500"/> </bean> </property> <property name="currentTraceContext"> <bean class="brave.spring.beans.CurrentTraceContextFactoryBean"> <property name="scopeDecorators"> <bean class="brave.context.slf4j.MDCScopeDecorator" factory-method="create"/> </property> </bean> </property> </bean>
- フィルターオブジェクトを設定します。
// Configuration on the server. <dubbo:provider filter="tracing" /> // サーバー側の設定 // Configuration on the client. <dubbo:consumer filter="tracing" /> // クライアント側の設定
Spring Sleuth を使用して Java アプリケーションをインストラメント化する
Spring Sleuth を使用して Java アプリケーションをインストラメント化できます。
- JAR パッケージを依存関係として追加します。
<dependency> <groupId>io.zipkin.brave</groupId> <artifactId>brave</artifactId> <version>5.4.2</version> </dependency> <dependency> <groupId>io.zipkin.reporter2</groupId> <artifactId>zipkin-sender-okhttp3</artifactId> <version>2.7.9</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.0.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-core</artifactId> <version>2.0.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-zipkin</artifactId> <version>2.0.1.RELEASE</version> </dependency>
- application.yml ファイルを設定します。説明
<endpoint_short>
は、クライアントとリージョンのエンドポイントに置き換える必要があります。Tracing Analysis コンソールにログインし、クラスタ設定ページの クラスター構成 タブで、api/v2/spans で終わるパブリックエンドポイントを取得できます。spring: application: # This ends up as the service name in zipkin // Zipkin のサービス名として使用されます name: sleuthDemo zipkin: # Uncomment to send to zipkin, replacing 192.168.99.100 with your zipkin IP address // Zipkin に送信するにはコメントを外し、192.168.99.100 を Zipkin の IP アドレスに置き換えます baseUrl: <endpoint_short> sleuth: sampler: probability: 1.0 sample: zipkin: # When enabled=false, traces log to the console. Comment to send to zipkin // enabled=false の場合、トレースはコンソールに記録されます。Zipkin に送信するにはコメントアウトします enabled: true
- HTTP リクエストを開始します。例:
http://localhost:3380/traced
。説明 その他のリクエストパスについては、デモプロジェクトのcom.alibaba.apm.SampleController
にあるメソッドを参照してください。
FAQ
Q: デモプログラムを実行した後、特定の Web サイトでデータが見つからないのはなぜですか?
A: parseResponse メソッドにブレークポイントを挿入して zipkin2.reporter.okhttp3.HttpCall をデバッグし、データ送信リクエストの戻り値を確認します。403 エラーが返された場合は、ユーザー名設定が無効です。エンドポイント設定を確認する必要があります。