什么是zipkin
Zipkin 是 Twitter 的一个开源项目,允许开发者收集 Twitter 各个服务上的监控数据,并提供查询接口
为什么要使用zipkin
随着业务发展,系统拆分导致系统调用链路愈发复杂一个前端请求可能最终需要调用很多次后端服务才能完成,当整个请求变慢或不可用时,我们是无法得知该请求是由某个或某些后端服务引起的,这时就需要解决如何快读定位服务故障点,以对症下药。于是就有了分布式系统调用跟踪的诞生。而zipkin就是开源分布式系统调用跟踪的佼佼者
zipkin基于google-Dapper的论文有兴趣的可以看下
zipkin体系介绍
zipkin架构
包含组件
- controller 控制器
- 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运行 启动完成界面 启动zipkin使用elasticsearch
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 控制台
zipkin 明细
zipkin 依赖
springboot+apache-httpclient使用zipkin
项目结构
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>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
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
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启动类
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修改
public Brave brave(SpanCollector spanCollector){
Builder builder = new Builder("service2");//指定serviceName
builder.spanCollector(spanCollector);
builder.traceSampler(Sampler.create(1));//采集率
return builder.build();
}
controller修改
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修改
@Bean
public Brave brave(SpanCollector spanCollector){
Builder builder = new Builder("service3");//指定serviceName
builder.spanCollector(spanCollector);
builder.traceSampler(Sampler.create(1));//采集率
return builder.build();
}
controller修改
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修改
@Bean
public Brave brave(SpanCollector spanCollector){
Builder builder = new Builder("service4");//指定serviceName
builder.spanCollector(spanCollector);
builder.traceSampler(Sampler.create(1));//采集率
return builder.build();
}
controller修改
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
- zipkin 运行需要jdk8
- pinpoint 可以关注下,同样是分布式链路追踪系统(ps:搭建环境1天下来,trace一直不能生成。。有谁碰到过这个问题可以回复下 0.0)
参考