zipkin简单介绍及环境搭建(一)

什么是zipkin

Zipkin 是 Twitter 的一个开源项目,允许开发者收集 Twitter 各个服务上的监控数据,并提供查询接口

为什么要使用zipkin

随着业务发展,系统拆分导致系统调用链路愈发复杂一个前端请求可能最终需要调用很多次后端服务才能完成,当整个请求变慢或不可用时,我们是无法得知该请求是由某个或某些后端服务引起的,这时就需要解决如何快读定位服务故障点,以对症下药。于是就有了分布式系统调用跟踪的诞生。而zipkin就是开源分布式系统调用跟踪的佼佼者

zipkin基于google-Dapper的论文有兴趣的可以看下

google-Dapper

zipkin体系介绍

zipkin架构

image
包含组件

  • collector 收集器
  • storage 存储
  • api 查询api
  • ui 界面

zipkin存储

zipkin存储默认使用inMemory

支持存储模式

  • inMemory
  • mysql
  • Cassandra
  • Elasticsearch

ZipKin数据模型

  • Trace:一组代表一次用户请求所包含的spans,其中根span只有一个。
  • Span: 一组代表一次HTTP/RPC请求所包含的annotations。
  • annotation:包括一个值,时间戳,主机名(留痕迹)。

几个时间

  • cs:客户端发起请求,标志Span的开始
  • sr:服务端接收到请求,并开始处理内部事务,其中sr - cs则为网络延迟和时钟抖动
  • ss:服务端处理完请求,返回响应内容,其中ss - sr则为服务端处理请求耗时
  • cr:客户端接收到服务端响应内容,标志着Span的结束,其中cr - ss则为网络延迟和时钟抖动

搭建zipkin

下载文件

启动zipkin

java -jar zipkin-server-1.22.1-exec.jar

使用elasticsearch-5.3.0作为存储启动zipkin

链接

  • elasticsearch-5.3.0下载
  • github
    解压elasticsearch-5.3.0运行
    image
    启动完成界面
    image
    启动zipkin使用elasticsearch
    1
    2
    3
    java -jar zipkin-server-1.22.1-exec.jar --STORAGE_TYPE=elasticsearch --DES_HOSTS=http://localhost:9200
    zipkin-server-1.22.1-exec.jar采用springboot编写,springboot传入参数使用--key=value.
    当前为什么使用--STORAGE_TYPE,--DES_HOSTS由配置文件里面决定

zipkin 控制台
image
zipkin 明细
image
zipkin 依赖

springboot+apache-httpclient使用zipkin

项目结构

image

pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<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>com.kite.zipkin</groupId>
<artifactId>zipkin-demo-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>zipkin-demo-server</name>
<url>http://maven.apache.org</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- brave core -->
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-core</artifactId>
<version>3.9.0</version>
</dependency>
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-spancollector-http</artifactId>
<version>3.9.0</version>
</dependency>
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-web-servlet-filter</artifactId>
<version>3.9.0</version>
</dependency>
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-apache-http-interceptors</artifactId>
<version>3.9.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>

ZipkinConfig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package com.kite.zipkin.config;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.github.kristofa.brave.Brave;
import com.github.kristofa.brave.Brave.Builder;
import com.github.kristofa.brave.EmptySpanCollectorMetricsHandler;
import com.github.kristofa.brave.Sampler;
import com.github.kristofa.brave.SpanCollector;
import com.github.kristofa.brave.http.DefaultSpanNameProvider;
import com.github.kristofa.brave.http.HttpSpanCollector;
import com.github.kristofa.brave.http.HttpSpanCollector.Config;
import com.github.kristofa.brave.httpclient.BraveHttpRequestInterceptor;
import com.github.kristofa.brave.httpclient.BraveHttpResponseInterceptor;
import com.github.kristofa.brave.servlet.BraveServletFilter;
@Configuration
public class ZipkinConfig {
//span(一次请求信息或者一次链路调用)信息收集器
@Bean
public SpanCollector spanCollector() {
Config config = HttpSpanCollector.Config.builder()
.compressionEnabled(false)// 默认false,span在transport之前是否会被gzipped
.connectTimeout(5000)
.flushInterval(1)
.readTimeout(6000)
.build();
return HttpSpanCollector.create("http://localhost:9411", config, new EmptySpanCollectorMetricsHandler());
}
//作为各调用链路,只需要负责将指定格式的数据发送给zipkin
@Bean
public Brave brave(SpanCollector spanCollector){
Builder builder = new Builder("service1");//指定serviceName
builder.spanCollector(spanCollector);
builder.traceSampler(Sampler.create(1));//采集率
return builder.build();
}
//设置server的(服务端收到请求和服务端完成处理,并将结果发送给客户端)过滤器
@Bean
public BraveServletFilter braveServletFilter(Brave brave) {
BraveServletFilter filter = new BraveServletFilter(brave.serverRequestInterceptor(),
brave.serverResponseInterceptor(), new DefaultSpanNameProvider());
return filter;
}
//设置client的(发起请求和获取到服务端返回信息)拦截器
@Bean
public CloseableHttpClient okHttpClient(Brave brave){
CloseableHttpClient httpclient = HttpClients.custom()
.addInterceptorFirst(new BraveHttpRequestInterceptor(brave.clientRequestInterceptor(), new DefaultSpanNameProvider()))
.addInterceptorFirst(new BraveHttpResponseInterceptor(brave.clientResponseInterceptor()))
.build();
return httpclient;
}
}

ZipkinBraveController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.kite.zipkin.controller;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ZipkinBraveController {
@Autowired
private CloseableHttpClient okHttpClient;
@GetMapping("/service1")
public String myboot() throws Exception {
Thread.sleep(100);//100ms
HttpGet get = new HttpGet("http://localhost:81/test");
CloseableHttpResponse execute = okHttpClient.execute(get);
/*
* 1、执行execute()的前后,会执行相应的拦截器(cs,cr)
* 2、请求在被调用方执行的前后,也会执行相应的拦截器(sr,ss)
*/
return EntityUtils.toString(execute.getEntity(), "utf-8");
}
}

Application启动类

1
2
3
4
5
6
7
8
9
10
11
package com.kite.zipkin;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

======================

zipkin-demo-server-2 serviceName修改

1
2
3
4
5
6
public Brave brave(SpanCollector spanCollector){
Builder builder = new Builder("service2");//指定serviceName
builder.spanCollector(spanCollector);
builder.traceSampler(Sampler.create(1));//采集率
return builder.build();
}

controller修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.kite.zipkin.controller;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ZipkinBraveController {
@Autowired
private CloseableHttpClient httpClient;
@GetMapping("/test")
public String myboot() throws Exception {
Thread.sleep(200);//100ms
HttpGet get1 = new HttpGet("http://localhost:82/test");
CloseableHttpResponse execute1 = httpClient.execute(get1);
/*
* 1、执行execute()的前后,会执行相应的拦截器(cs,cr)
* 2、请求在被调用方执行的前后,也会执行相应的拦截器(sr,ss)
*/
HttpGet get2 = new HttpGet("http://localhost:83/test");
CloseableHttpResponse execute2 = httpClient.execute(get2);
return EntityUtils.toString(execute1.getEntity(), "utf-8") + "-" +EntityUtils.toString(execute2.getEntity(), "utf-8");
}
}

zipkin-demo-server-3 serviceName修改

1
2
3
4
5
6
7
@Bean
public Brave brave(SpanCollector spanCollector){
Builder builder = new Builder("service3");//指定serviceName
builder.spanCollector(spanCollector);
builder.traceSampler(Sampler.create(1));//采集率
return builder.build();
}

controller修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.kite.zipkin.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ZipkinBraveController {
@GetMapping("/test")
public String myboot() throws Exception {
Thread.sleep(100);//100ms
return "service3";
}
}

zipkin-demo-server-4 serviceName修改

1
2
3
4
5
6
7
@Bean
public Brave brave(SpanCollector spanCollector){
Builder builder = new Builder("service4");//指定serviceName
builder.spanCollector(spanCollector);
builder.traceSampler(Sampler.create(1));//采集率
return builder.build();
}

controller修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.kite.zipkin.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ZipkinBraveController {
@GetMapping("/test")
public String myboot() throws Exception {
Thread.sleep(100);//100ms
return "service3";
}
}

关注点point