使用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

<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">
  <modelVersion>4.0.0</modelVersion>
  
  <groupId>io.zipkin.brave</groupId>
  <artifactId>brave-webmvc-example</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>brave-webmvc-examplea</name>
  <description>Example using Brave to trace RPCs from Spring Web MVC</description>
  <url>https://github.com/openzipkin/brave-webmvc-example</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring.version>4.3.3.RELEASE</spring.version>
    <jetty.version>8.1.20.v20160902</jetty.version>
    <brave.version>3.16.0</brave.version>
    <zipkin-reporter.version>0.6.9</zipkin-reporter.version>
  </properties>
  
  <dependencies>
  <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.10</version>
      <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.zipkin.brave</groupId>
        <artifactId>brave-core-spring</artifactId>
        <version>${brave.version}</version>
    </dependency>
    <dependency>
      <groupId>io.zipkin.reporter</groupId>
      <artifactId>zipkin-sender-okhttp3</artifactId>
      <version>${zipkin-reporter.version}</version>
    </dependency>
    <dependency>
      <groupId>io.zipkin.reporter</groupId>
      <artifactId>zipkin-sender-libthrift</artifactId>
      <version>${zipkin-reporter.version}</version>
    </dependency>
    <dependency>
      <groupId>io.zipkin.reporter</groupId>
      <artifactId>zipkin-sender-kafka08</artifactId>
      <version>${zipkin-reporter.version}</version>
    </dependency>
    <dependency>
        <groupId>io.zipkin.brave</groupId>
        <artifactId>brave-spring-web-servlet-interceptor</artifactId>
        <version>${brave.version}</version>
    </dependency>
    <dependency>
      <groupId>io.zipkin.brave</groupId>
      <artifactId>brave-spring-resttemplate-interceptors</artifactId>
      <version>${brave.version}</version>
    </dependency>
    <dependency>
    	<groupId>org.springframework</groupId>
	    <artifactId>spring-core</artifactId>
	    <version>${spring.version}</version>
    </dependency>
    <dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-context</artifactId>
	    <version>${spring.version}</version>
    </dependency>
    <dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-beans</artifactId>
	    <version>${spring.version}</version>
    </dependency>
    <dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-web</artifactId>
	    <version>${spring.version}</version>
    </dependency>
    <dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-webmvc</artifactId>
	    <version>${spring.version}</version>
    </dependency>
    <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-server</artifactId>
       <version>${jetty.version}</version>
       <scope>test</scope>
    </dependency>
    <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-webapp</artifactId>
       <version>${jetty.version}</version>
       <scope>test</scope>
    </dependency>
    	<dependency>
		<groupId>log4j</groupId>
		<artifactId>log4j</artifactId>
		<version>1.2.17</version>
	</dependency>
	<dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.21</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>1.7.21</version>
    </dependency>
  </dependencies>
  <build>
  	 <plugins>
            <plugin>
                <inherited>true</inherited>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                    <optimize>true</optimize>
                    <debug>true</debug>
                </configuration>
            </plugin>
            <plugin>
            	<groupId>org.apache.maven.plugins</groupId>
		        <artifactId>maven-failsafe-plugin</artifactId>
		        <version>2.19.1</version>
		        <executions>
			         <execution>
				        <id>integration-test</id>
				        <goals>
					       <goal>integration-test</goal>
				        </goals>
		  	         </execution>
			         <execution>
			             <id>verify</id>
				         <goals>
					       <goal>verify</goal>
				         </goals>
			         </execution>
		        </executions>
	       </plugin>
	       <plugin>
	    	    <groupId>org.apache.maven.plugins</groupId>
		        <artifactId>maven-war-plugin</artifactId>
		        <version>3.0.0</version>
		        <configuration>
			         <webResources>
				        <resource>
					       <directory>${basedir}/src/main/webapp</directory>
					       <filtering>true</filtering>
					       <includes>
						      <include>**/index.html</include>
					       </includes>
				        </resource>
				        <resource>
					       <directory>${basedir}/src/main/webapp/WEB-INF</directory>
					       <filtering>true</filtering>
					       <targetPath>WEB-INF</targetPath>
					       <includes>
						      <include>**/web.xml</include>
					       </includes>
				        </resource>
			         </webResources>
			         <packagingExcludes>WEB-INF/lib/servlet-api-*.jar</packagingExcludes>
		          </configuration>
	       </plugin>
	</plugins>
  </build>
</project>


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


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<Span> 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;


  @Autowired
  private BraveClientHttpRequestInterceptor clientInterceptor;


  @Autowired
  private RestTemplate restTemplate;


  // 添加rest template拦截器
  @PostConstruct
  public void init() {
    List<ClientHttpRequestInterceptor> interceptors =
        new ArrayList<ClientHttpRequestInterceptor>(restTemplate.getInterceptors());
    interceptors.add(clientInterceptor);
    restTemplate.setInterceptors(interceptors);
  }


  // 添加Severlet拦截器
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(serverInterceptor);
  }
}



3、springmvc的controller,发布a和b两个服务

package brave.webmvc;


import java.util.Random;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;


@RestController
@EnableWebMvc
@Configuration
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 {


    Random random = new Random();
    Thread.sleep(random.nextInt(1000));


    return "b";
  }
}


4、web.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>brave webmvc example</display-name>

<servlet>
 <servlet-name>dispatcher</servlet-name>
 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
 
 <init-param>
 <param-name>contextClass</param-name>
 <param-value>
 org.springframework.web.context.support.AnnotationConfigWebApplicationContext
 </param-value>
 </init-param> 
 <init-param>
 <param-name>contextConfigLocation</param-name>
 <!--  Loads the application configuration and resource. Tracing configuration is optional and goes last. -->
 <param-value>
brave.webmvc.ExampleController
brave.webmvc.WebTracingConfiguration
</param-value>
 </init-param>
 <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
 <servlet-name>dispatcher</servlet-name>
 <url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>


5、下载zipkin并运行

下载地址: https://search.maven.org/remote_content?g=io.zipkin.java&a=zipkin-server&v=LATEST&c=exec

运行: java -jar zipkin.jar


6、git上下载项目,maven打war包(打包时,请跳过测试,否则报错)部署到tomcat或在开发环境中运行

 访问a服务: http://localhost:8080/brave-webmvc-example/a

 打开:http://localhost:9411,查看调用链跟踪信息及耗时

 


 发现Brave提供的拦截器使用的Span的名称是默认的http的请求方法,好像没多大意义,且没有记录请求参数,若调用链中出现bug,不方便bug重现与问题排查,下一篇讲使用Brave的扩展与定制,重写span名称的获取与添加请求参数到跟踪信息中


展开阅读全文

没有更多推荐了,返回首页