目的是对一个请求所经过的整个服务链的跟踪,帮助我们快速发现错误根源以及监控分析每条请求链路上的性能瓶颈。
首先前提是启动服务消费者和服务提供者并且分别服务注册中心注册
在消费者和提供者的依赖中添加sleuth依赖
org.springframework.cloud
spring-cloud-starter-sleuth
在消费者消费之后,可以看到打印了一些信息
引用依赖之后会自动为当前应用构建起各通信通道的跟踪机制,比如
通过rabbitmq、kafka(或者其他任何stream绑定器实现的消息中间件)传递的请求
通过Zuul代理传递的请求
通过RestTemplate 发起的请求
原理是通过在请求头设置标记段标记请求
由于系统一般会有高并发的场景,如果收集信息过大则会影响性能。所以在上方的跟踪消息处的第四个值是个boolean类型,代表是否需要被收集器收集
通过实现接口Sample的isSmampled()方法,如果返回false则不收集
public interface Sampler {
boolean isSampled(Span var1);
}
默认情况下使用PercentageBasedSampler实现收集的策略
public class PercentageBasedSampler implements Sampler {
public boolean isSampled(Span currentSpan) {
if (this.configuration.getPercentage() != 0.0F && currentSpan != null) {
if (this.configuration.getPercentage() == 1.0F) {
return true;
} else {
synchronized(this) {
int i = this.counter.getAndIncrement();
boolean result = this.sampleDecisions.get(i);
if (i == 99) {
this.counter.set(0);
}
return result;
}
}
} else {
return false;
}
}
}
配置方法比较简单,通过配置文件即可,默认为0.1,也就是收集10%的数据
spring.sleuth.sampler.probability=0.1
由于跟踪信息都在每个服务实例上,看起来非常麻烦,所以我们需要一个工具来帮忙收集存储和搜索这些跟踪信息。比如基于日志的分析系统ELK平台
ELK平台由ElasticSerach、Logstash和Kibana三个开源工具组成。
ElasticSerach :是一个开源分布式搜索引擎,它的特点有:分布式,零配置,自动发现,索引自动分片,索引副本机制,RESTful风格接口,多数据源,自动搜索负载等。
Logstash :是一个完全开源的工具,它可以对日志进行收集、过滤,并将其存储供以后使用
Kibana:也是一个开源和免费的工具,它可以为Logstash和ElasticSearch提供日志分析友好的Web界面,可以帮助汇总、分析和搜索重要数据日志。
由于ELK平台主要的就是将Logstash与服务对接,而spring boot使用的日志是logback,而Logstash也有与logback对接的工具类
下面引入这个工具依赖
net.logstash.logback
logstash-logback-encoder
5.2
然后在resource目录下写上配置文件logback-spring.xml
INFO
${CONSOLE_LOG_PATTERN}
utf8
${LOG_FILE}.json
${LOG_FILE}.json.%d{yyyy-MM-dd}.gz
7
UTC
{
"severity": "%level",
"service": "${springAppName:-}",
"trace": "%X{X-B3-TraceId:-}",
"span": "%X{X-B3-SpanId:-}",
"exportable": "%X{X-Span-Export:-}",
"pid": "${PID:-}",
"thread": "%thread",
"class": "%logger{40}",
"rest": "%message"
}
由于ELK缺乏对时间延迟的关注,所以我们需要使用ZipKIn
Zipkin主要包括四部分组成
下面详细介绍Slueth与ZipKin的基础整合过程
创建一个zipKin-server服务,引入相关依赖
io.zipkin.java
zipkin-server
io.zipkin.java
zipkin-autoconfigure-ui
开启ZipKIn server注解
@EnableZipkinServer
@SpringBootApplication
public class ZipkinApplication {
public static void main(String[] args) {
SpringApplication.run(ZipkinApplication.class, args);
}
}
完成后通过访问http://localhost:9411可以看到管理首页
官方提供了一键脚本
|
|
如果用 Docker 的话,直接
|
|
需要被收集信息的服务添加依赖
org.springframework.cloud
spring-cloud-sleuth-zipkin
接着配置ZipKin Server 的地址
spring.zipkin.base-url=http://localhost:9411
通过消息中间件来跟踪信息进行异步收集的封装,通过结合stream,可以非常轻松地让应用客户端将跟踪信息输出到消息中间件上,同时ZipKin服务端从消息中间件上异步地消费这些跟踪信息
相比于HTTP的方式来说,使用消息中间件有以下优点
org.springframework.cloud
spring-cloud-starter-ribbon
org.springframework.cloud
spring-cloud-starter-sleuth
org.springframework.cloud
spring-cloud-sleuth-stream
org.springframework.cloud
spring-cloud-starter-stream-rabbit
设置配置信息
这里已经去掉ZioKin Server 地址的配置,实现解耦
spring.application.name=trace-2
server.port=9102
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#spring.sleuth.sampler.percentage=0.1
# log trace detail
logging.level.org.springframework.web.servlet.DispatcherServlet=DEBUG
logging.file=${spring.application.name}.log
添加依赖
org.springframework.cloud
spring-cloud-sleuth-zipkin-stream
org.springframework.cloud
spring-cloud-starter-stream-rabbit
io.zipkin.java
zipkin-autoconfigure-ui
配置信息
spring.application.name=zipkin-server-stream
server.port=9411
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
logging.file=${spring.application.name}.log
开启服务
@EnableZipkinStreamServer
@SpringBootApplication
public class ZipkinApplication {
public static void main(String[] args) {
SpringApplication.run(ZipkinApplication.class, args);
}
}
因为之前说的 Zipkin 不再推荐我们来自定义 Server 端了,所以在最新版本的 Spring Cloud 依赖管理里已经找不到 zipkin-server 了。
那么如果直接用官方提供的 jar 包怎么从 RabbitMQ 中获取 trace 信息呢?
我们可以通过环境变量让 Zipkin 从 RabbitMQ 中读取信息,就像这样:
复制
|
|
可配置的环境变量如下表所示:
属性 | 环境变量 | 描述 |
---|---|---|
zipkin.collector.rabbitmq.concurrency |
RABBIT_CONCURRENCY |
并发消费者数量,默认为1 |
zipkin.collector.rabbitmq.connection-timeout |
RABBIT_CONNECTION_TIMEOUT |
建立连接时的超时时间,默认为 60000 毫秒,即 1 分钟 |
zipkin.collector.rabbitmq.queue |
RABBIT_QUEUE |
从中获取 span 信息的队列,默认为 zipkin |
zipkin.collector.rabbitmq.uri |
RABBIT_URI |
符合 RabbitMQ URI 规范 的 URI,例如amqp://user:pass@host:10000/vhost |
如果设置了 URI,则以下属性将被忽略。
属性 | 环境变量 | 描述 |
---|---|---|
zipkin.collector.rabbitmq.addresses |
RABBIT_ADDRESSES |
用逗号分隔的 RabbitMQ 地址列表,例如localhost:5672,localhost:5673 |
zipkin.collector.rabbitmq.password |
RABBIT_PASSWORD |
连接到 RabbitMQ 时使用的密码,默认为 guest |
zipkin.collector.rabbitmq.username |
RABBIT_USER |
连接到 RabbitMQ 时使用的用户名,默认为guest |
zipkin.collector.rabbitmq.virtual-host |
RABBIT_VIRTUAL_HOST |
使用的 RabbitMQ virtual host,默认为 / |
zipkin.collector.rabbitmq.use-ssl |
RABBIT_USE_SSL |
设置为true 则用 SSL 的方式与 RabbitMQ 建立链接 |
关于 Zipkin 的 Client 端,也就是微服务应用,我们就在之前 trace-a、trace-b 的基础上修改,只要在他们的依赖里都引入spring-cloud-stream-binder-rabbit
就好了,别的不用改。
|
|
不过为了说明是通过 RabbitMQ 传输的信息,我将spring.zipkin.base-url
均改为http://localhost:9412/
,即指向一个错误的地址。
分别重启 trace-a、trace-b 工程,并启动 Zipkin Server
|
|
然后访问 http://localhost:8080/trace-a 并刷新 Zipkin UI,看到如下内容,就说明 Sleuth+Zipkin+RabbitMQ 整合成功了。
此时看 RabbitMQ Admin,会看到多了一个名为 zipkin 的 Queue
(略)
由于Zipin Server 只会将跟踪信息存储咋内存中,一般情况下,我们都需要将这个记录保存到mysql数据库中
org.jooq是为了防止依赖版本错误而配置的依赖
org.springframework.boot
spring-boot-starter-jdbc
mysql
mysql-connector-java
org.jooq
jooq
3.8.0
可以直接扫描依赖的sql文件创建表
spring.datasource.schema=classpath:/mysql.sql
spring.datasource.url=jdbc:mysql://localhost:3306/zipkin
spring.datasource.password=root
spring.datasource.username=root
spring.datasource.continue-on-error=true
spring.datasource.initialize=true
zipkin.storage.type=mysql
ZipKin提供了RESTFul API接口供用户在第三方系统中调用来定制自己的跟踪信息展示或监控