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
<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>
<groupId>io.zipkin.reporter</groupId>
<artifactId>zipkin-sender-okhttp3</artifactId>
<version>${zipkin-reporter.version}</version>
<artifactId>zipkin-sender-libthrift</artifactId>
<artifactId>zipkin-sender-kafka08</artifactId>
<artifactId>brave-spring-web-servlet-interceptor</artifactId>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-spring-resttemplate-interceptors</artifactId>
<version>${brave.version}</version>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<artifactId>spring-context</artifactId>
<artifactId>spring-beans</artifactId>
<artifactId>spring-web</artifactId>
<artifactId>spring-webmvc</artifactId>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty.version}</version>
<scope>test</scope>
<artifactId>jetty-webapp</artifactId>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
<artifactId>jcl-over-slf4j</artifactId>
</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>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.19.1</version>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
<id>verify</id>
<goals>
<goal>verify</goal>
</goals>
</executions>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
<webResources>
<resource>
<directory>${basedir}/src/main/webapp</directory>
<filtering>true</filtering>
<includes>
<include>**/index.html</include>
</includes>
</resource>
<directory>${basedir}/src/main/webapp/WEB-INF</directory>
<targetPath>WEB-INF</targetPath>
<include>**/web.xml</include>
</webResources>
<packagingExcludes>WEB-INF/lib/servlet-api-*.jar</packagingExcludes>
</configuration>
</plugins>
</build>
</project>
2、Brave的初始化及添加攔截器
<b>[java]</b> view plain copy
<span style="font-size:18px;">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;
private BraveClientHttpRequestInterceptor clientInterceptor;
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);
}</span>
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配置
<span style="font-size:18px;"><?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>
<param-name>contextConfigLocation</param-name>
<!-- Loads the application configuration and resource. Tracing configuration is optional and goes last. -->
brave.webmvc.ExampleController
brave.webmvc.WebTracingConfiguration
</param-value>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
</span>
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,檢視調用鍊跟蹤資訊及耗時
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2QvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2Lc1TVYl1c0JTWohXbZZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39DNxEzMyITNyIDOwQDM3EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
發現Brave提供的攔截器使用的Span的名稱是預設的http的請求方法,好像沒多大意義,且沒有記錄請求參數,若調用鍊中出現bug,不友善bug重制與問題排查,下一篇講使用Brave的擴充與定制,重寫span名稱的擷取與添加請求參數到跟蹤資訊中