天天看點

使用Zipkin 和 Brave 實作http(springmvc)服務調用跟蹤(一)使用Zipkin 和 Brave 實作http(springmvc)服務調用跟蹤(一)

Zipkin 是一款開源的分布式實時資料追蹤系統(Distributed Tracking System),基于 Google Dapper 的論文設計而來,由 Twitter 公司開發貢獻。其主要功能是聚集來自各個異構系統的實時監控資料,用來追蹤微服務架構下的系統延時問題。

Brave 是用來裝備 Java 程式的類庫,提供了面向 Standard Servlet、Spring MVC、Http Client、JAX RS、Jersey、Resteasy 和 MySQL 等接口的裝備能力,可以通過編寫簡單的配置和代碼,讓基于這些架構建構的應用可以向 Zipkin 報告資料。同時 Brave 也提供了非常簡單且标準化的接口,在以上封裝無法滿足要求的時候可以友善擴充與定制(下篇會講)。

有關zipkin與Brave的詳細介紹:http://www.tuicool.com/articles/f2qAZnZ

用戶端發起請求到接收到服務端回應,先後經過四個階段:用戶端/消費者發起請求(cs)、服務端/生産者接收到請求(sr)、服務端/生産者發送應答(ss)和用戶端/消費者接收到應答(cr)。Brave為Spring提供的Servlet攔截器(ServletHandlerInterceptor)及Rest(BraveClientHttpRequestInterceptor)模闆的攔截器,向zipkin報告監控資料,其中,BraveClientHttpRequestInterceptor負責cs與cr的處理,ServletHandlerInterceptor負責sr與ss的處理。

好,開始實驗這兩個攔截器的使用,目标是釋出兩個服務a和b,在a中調用b服務,記錄調用的跟蹤資訊。

git項目位址:https://github.com/blacklau/brave-webmvc-example   (forked from openzipkin/brave-webmvc-example ,請忽略README.md說明)

1、pom.xml

<b>[html]</b> view plain copy

&lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&gt;

  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;

  &lt;groupId&gt;io.zipkin.brave&lt;/groupId&gt;

  &lt;artifactId&gt;brave-webmvc-example&lt;/artifactId&gt;

  &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;

  &lt;packaging&gt;war&lt;/packaging&gt;

  &lt;name&gt;brave-webmvc-examplea&lt;/name&gt;

  &lt;description&gt;Example using Brave to trace RPCs from Spring Web MVC&lt;/description&gt;

  &lt;url&gt;https://github.com/openzipkin/brave-webmvc-example&lt;/url&gt;

  &lt;properties&gt;

    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;

    &lt;spring.version&gt;4.3.3.RELEASE&lt;/spring.version&gt;

    &lt;jetty.version&gt;8.1.20.v20160902&lt;/jetty.version&gt;

    &lt;brave.version&gt;3.16.0&lt;/brave.version&gt;

    &lt;zipkin-reporter.version&gt;0.6.9&lt;/zipkin-reporter.version&gt;

  &lt;/properties&gt;

  &lt;dependencies&gt;

  &lt;dependency&gt;

      &lt;groupId&gt;junit&lt;/groupId&gt;

      &lt;artifactId&gt;junit&lt;/artifactId&gt;

      &lt;version&gt;4.10&lt;/version&gt;

      &lt;scope&gt;test&lt;/scope&gt;

    &lt;/dependency&gt;

    &lt;dependency&gt;

        &lt;groupId&gt;io.zipkin.brave&lt;/groupId&gt;

        &lt;artifactId&gt;brave-core-spring&lt;/artifactId&gt;

        &lt;version&gt;${brave.version}&lt;/version&gt;

      &lt;groupId&gt;io.zipkin.reporter&lt;/groupId&gt;

      &lt;artifactId&gt;zipkin-sender-okhttp3&lt;/artifactId&gt;

      &lt;version&gt;${zipkin-reporter.version}&lt;/version&gt;

      &lt;artifactId&gt;zipkin-sender-libthrift&lt;/artifactId&gt;

      &lt;artifactId&gt;zipkin-sender-kafka08&lt;/artifactId&gt;

        &lt;artifactId&gt;brave-spring-web-servlet-interceptor&lt;/artifactId&gt;

      &lt;groupId&gt;io.zipkin.brave&lt;/groupId&gt;

      &lt;artifactId&gt;brave-spring-resttemplate-interceptors&lt;/artifactId&gt;

      &lt;version&gt;${brave.version}&lt;/version&gt;

        &lt;groupId&gt;org.springframework&lt;/groupId&gt;

        &lt;artifactId&gt;spring-core&lt;/artifactId&gt;

        &lt;version&gt;${spring.version}&lt;/version&gt;

        &lt;artifactId&gt;spring-context&lt;/artifactId&gt;

        &lt;artifactId&gt;spring-beans&lt;/artifactId&gt;

        &lt;artifactId&gt;spring-web&lt;/artifactId&gt;

        &lt;artifactId&gt;spring-webmvc&lt;/artifactId&gt;

       &lt;groupId&gt;org.eclipse.jetty&lt;/groupId&gt;

       &lt;artifactId&gt;jetty-server&lt;/artifactId&gt;

       &lt;version&gt;${jetty.version}&lt;/version&gt;

       &lt;scope&gt;test&lt;/scope&gt;

       &lt;artifactId&gt;jetty-webapp&lt;/artifactId&gt;

        &lt;dependency&gt;

        &lt;groupId&gt;log4j&lt;/groupId&gt;

        &lt;artifactId&gt;log4j&lt;/artifactId&gt;

        &lt;version&gt;1.2.17&lt;/version&gt;

        &lt;groupId&gt;org.slf4j&lt;/groupId&gt;

        &lt;artifactId&gt;slf4j-log4j12&lt;/artifactId&gt;

        &lt;version&gt;1.7.21&lt;/version&gt;

        &lt;artifactId&gt;jcl-over-slf4j&lt;/artifactId&gt;

  &lt;/dependencies&gt;

  &lt;build&gt;

     &lt;plugins&gt;

            &lt;plugin&gt;

                &lt;inherited&gt;true&lt;/inherited&gt;

                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;

                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;

                &lt;version&gt;2.5.1&lt;/version&gt;

                &lt;configuration&gt;

                    &lt;source&gt;1.6&lt;/source&gt;

                    &lt;target&gt;1.6&lt;/target&gt;

                    &lt;optimize&gt;true&lt;/optimize&gt;

                    &lt;debug&gt;true&lt;/debug&gt;

                &lt;/configuration&gt;

            &lt;/plugin&gt;

                &lt;artifactId&gt;maven-failsafe-plugin&lt;/artifactId&gt;

                &lt;version&gt;2.19.1&lt;/version&gt;

                &lt;executions&gt;

                     &lt;execution&gt;

                        &lt;id&gt;integration-test&lt;/id&gt;

                        &lt;goals&gt;

                           &lt;goal&gt;integration-test&lt;/goal&gt;

                        &lt;/goals&gt;

                     &lt;/execution&gt;

                         &lt;id&gt;verify&lt;/id&gt;

                         &lt;goals&gt;

                           &lt;goal&gt;verify&lt;/goal&gt;

                         &lt;/goals&gt;

                &lt;/executions&gt;

           &lt;/plugin&gt;

           &lt;plugin&gt;

                &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;

                &lt;version&gt;3.0.0&lt;/version&gt;

                     &lt;webResources&gt;

                        &lt;resource&gt;

                           &lt;directory&gt;${basedir}/src/main/webapp&lt;/directory&gt;

                           &lt;filtering&gt;true&lt;/filtering&gt;

                           &lt;includes&gt;

                              &lt;include&gt;**/index.html&lt;/include&gt;

                           &lt;/includes&gt;

                        &lt;/resource&gt;

                           &lt;directory&gt;${basedir}/src/main/webapp/WEB-INF&lt;/directory&gt;

                           &lt;targetPath&gt;WEB-INF&lt;/targetPath&gt;

                              &lt;include&gt;**/web.xml&lt;/include&gt;

                     &lt;/webResources&gt;

                     &lt;packagingExcludes&gt;WEB-INF/lib/servlet-api-*.jar&lt;/packagingExcludes&gt;

                  &lt;/configuration&gt;

    &lt;/plugins&gt;

  &lt;/build&gt;

&lt;/project&gt;

2、Brave的初始化及添加攔截器

<b>[java]</b> view plain copy

&lt;span style="font-size:18px;"&gt;package brave.webmvc;

import com.github.kristofa.brave.Brave;

import com.github.kristofa.brave.LoggingReporter;

import com.github.kristofa.brave.http.DefaultSpanNameProvider;

import com.github.kristofa.brave.http.SpanNameProvider;

import com.github.kristofa.brave.spring.BraveClientHttpRequestInterceptor;

import com.github.kristofa.brave.spring.ServletHandlerInterceptor;

import java.util.ArrayList;

import java.util.List;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.Import;

import org.springframework.http.client.ClientHttpRequestInterceptor;

import org.springframework.web.client.RestTemplate;

import org.springframework.web.servlet.config.annotation.InterceptorRegistry;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import zipkin.Span;

import zipkin.reporter.Reporter;

import zipkin.reporter.Sender;

import zipkin.reporter.okhttp3.OkHttpSender;

/**

 * This adds tracing configuration to any web mvc controllers or rest template clients. This should

 * be configured last.

 */

@Configuration

// import as the interceptors are annotation with javax.inject and not automatically wired

@Import({BraveClientHttpRequestInterceptor.class, ServletHandlerInterceptor.class})

public class WebTracingConfiguration extends WebMvcConfigurerAdapter {

  /** 發送器配置 */

  @Bean Sender sender() {

    return OkHttpSender.create("http://127.0.0.1:9411/api/v1/spans");

    //return LibthriftSender.create("127.0.0.1");

    // return KafkaSender.create("127.0.0.1:9092");

  }

  /** 用什麼方式顯示span資訊 */

  @Bean Reporter&lt;Span&gt; reporter() {

//取消注釋,日志列印span資訊

//return new LoggingReporter(); 

    return AsyncReporter.builder(sender()).build();

  @Bean Brave brave() {

    return new Brave.Builder("brave-webmvc-example").reporter(reporter()).build();

  // span命名提供者,預設為http方法.

  @Bean SpanNameProvider spanNameProvider() {

    return new DefaultSpanNameProvider();

  @Autowired

  private ServletHandlerInterceptor serverInterceptor;

  private BraveClientHttpRequestInterceptor clientInterceptor;

  private RestTemplate restTemplate;

  // 添加rest template攔截器

  @PostConstruct

  public void init() {

    List&lt;ClientHttpRequestInterceptor&gt; interceptors =

        new ArrayList&lt;ClientHttpRequestInterceptor&gt;(restTemplate.getInterceptors());

    interceptors.add(clientInterceptor);

    restTemplate.setInterceptors(interceptors);

  // 添加Severlet攔截器

  @Override

  public void addInterceptors(InterceptorRegistry registry) {

    registry.addInterceptor(serverInterceptor);

}&lt;/span&gt;

3、springmvc的controller,釋出a和b兩個服務

import java.util.Random;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@RestController

@EnableWebMvc

public class ExampleController {

  @Bean RestTemplate template() {

    return new RestTemplate();

  @Autowired RestTemplate template;

  @RequestMapping("/a")

  public String a() throws InterruptedException {

    Random random = new Random();

    Thread.sleep(random.nextInt(1000));

    return template.getForObject("http://localhost:8080/brave-webmvc-example/b", String.class);

  @RequestMapping("/b")

  public String b() throws InterruptedException {

    return "b";

4、web.xml配置

&lt;span style="font-size:18px;"&gt;&lt;?xml version="1.0" encoding="UTF-8"?&gt;

&lt;!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"&gt;

&lt;web-app&gt;

&lt;display-name&gt;brave webmvc example&lt;/display-name&gt;

&lt;servlet&gt;

 &lt;servlet-name&gt;dispatcher&lt;/servlet-name&gt;

 &lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;

 &lt;init-param&gt;

 &lt;param-name&gt;contextClass&lt;/param-name&gt;

 &lt;param-value&gt;

 org.springframework.web.context.support.AnnotationConfigWebApplicationContext

 &lt;/param-value&gt;

 &lt;/init-param&gt;

 &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;

 &lt;!--  Loads the application configuration and resource. Tracing configuration is optional and goes last. --&gt;

brave.webmvc.ExampleController

brave.webmvc.WebTracingConfiguration

&lt;/param-value&gt;

 &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;

&lt;/servlet&gt;

&lt;servlet-mapping&gt;

 &lt;url-pattern&gt;/*&lt;/url-pattern&gt;

&lt;/servlet-mapping&gt;

&lt;/web-app&gt;

&lt;/span&gt;

5、下載下傳zipkin并運作

下載下傳位址: https://search.maven.org/remote_content?g=io.zipkin.java&amp;a=zipkin-server&amp;v=LATEST&amp;c=exec

運作: java -jar zipkin.jar

6、git上下載下傳項目,maven打war包(打包時,請跳過測試,否則報錯)部署到tomcat或在開發環境中運作

通路a服務: http://localhost:8080/brave-webmvc-example/a

打開:http://localhost:9411,檢視調用鍊跟蹤資訊及耗時

使用Zipkin 和 Brave 實作http(springmvc)服務調用跟蹤(一)使用Zipkin 和 Brave 實作http(springmvc)服務調用跟蹤(一)

發現Brave提供的攔截器使用的Span的名稱是預設的http的請求方法,好像沒多大意義,且沒有記錄請求參數,若調用鍊中出現bug,不友善bug重制與問題排查,下一篇講使用Brave的擴充與定制,重寫span名稱的擷取與添加請求參數到跟蹤資訊中