【Java】Feign 服务调用使用 Zipkin 链路追踪
0、介绍
分布式微服务时代,方便了业务的快速增长和服务的稳定,但是系统出现问题后,面对同业务多服务排查起来令人头大。这时候领导就想着集成分布式追踪系统。Zipkin 是 Twitter 的一个开源项目,基于 Google Dapper 实现。可以使用它来收集各个服务器上请求链路的跟踪数据,并通过它提供的 REST API 接口来辅助我们查询跟踪数据以实现对分布式系统的监控程序,从而及时地发现系统中出现的延迟升高问题并找出系统性能瓶颈的根源。除了面向开发的 API 接口之外,它也提供了方便的 UI 组件帮助我们直观的搜索跟踪信息和分析请求链路明细,比如:可以查询某段时间内各用户请求的处理时间等。
1、环境准备
Zipkin 服务依赖环境
Zipkin 客户端项目版本
2、Zipkin 服务安装
2.1、Docker 安装
#拉取镜像docker pull openzipkin/zipkin
#1、Web 连接方式启动
docker run --name zipkin-web -d -p 9411:9411 openzipkin/zipkin
#2、Rabbit 连接方式启动 注意 RABBIT_ADDRESSES 的 Ip 要实际 Ip
docker run -d --name zipkin-rabbitmq -p 9411:9411 -e RABBIT_ADDRESSES=192.168.1.105:5672 -e RABBIT_USER=guest -e RABBIT_PASSWORD=guest openzipkin/zipkin
#3、Rabbit 连接方式启动,存储介质由内存改为 Mysql (暂时有问题)
docker run -d --name zipkin-rabbit-mysql -p 9411:9411 -e RABBIT_ADDRESSES=192.168.1.105:5672 -e RABBIT_USER=guest -e RABBIT_PASSWORD=guest -e STORAGE_TYPE=mysql -e MYSQL_HOST=192.168.1.105 -e MYSQL_TCP_PORT=13306 -e MYSQL_USER=root -e MYSQL_PASS=123456 -e MYSQL_DB=zipkin openzipkin/zipkin
2.2、Jar 安装
官方说明 如果服务器安装了 JDK8 以及更高的,那么 Jar 包方式启动是最快的入门方式。
可以本地下载好 Jar 然后上传服务器再执行,也可以服务器直接下载再执行
- 下载最新 Jar 包,地址
- 服务器下载命令
curl -sSL https://zipkin.io/quickstart.sh | bash -s
Jar 服务启动
#1、Web 连接方式启动java -jar zipkin.jar
#2、Rabbit 连接方式启动
java -jar zipkin-server-2.23.1-exec.jar --zipkin.collector.rabbitmq.addresses=localhost
#后面的 --zipkin.collector.rabbitmq.addresses=localhost 就是 RabbitMQ 的配置,这是默认的,如果要自己指定的用户名和密码可以参考下面的启动命令:
nohup java -jar zipkin-server-2.23.1-exec.jar > zipkin.log --zipkin.collector.rabbitmq.addresses=localhost:5672 --zipkin.collector.rabbitmq.username=guest --zipkin.collector.rabbitmq.password=guest 2>&1 &
#3、Rabbit 连接方式启动,修改存储介质,默认为内存,现在改为 Mysql,也可以使用 Elasticsearch 持久化
nohup java -jar zipkin-server-2.23.1-exec.jar > zipkin.log \
--zipkin.collector.rabbitmq.addresses=localhost:5672 \
--zipkin.collector.rabbitmq.username=guest \
--zipkin.collector.rabbitmq.password=guest \
--zipkin.storage.type=mysql \
--zipkin.storage.mysql.host=localhost \
--zipkin.storage.mysql.port=3306 \
--zipkin.storage.mysql.username=root \
--zipkin.storage.mysql.password=root \
--zipkin.storage.mysql.db=zipkin \
2>&1 &
其他环境变量参数配置
属性 | 环境变量 | 描述 |
---|---|---|
zipkin.collector.rabbitmq.concurrency | RABBIT_CONCURRENCY | 并发消费者数量,默认为 1 |
zipkin.collector.rabbitmq.connection-timeout | RABBIT_CONNECTION_TIMEOUT | 建立连接时的超时时间,默认为 60000 毫秒,即 1 分钟 |
zipkinzipkin.collector.rabbitmq.queue | RABBIT_QUEUE | 从中获取 span 信息的队列,默认为 zipkin |
zipkin.collector.rabbitmq.uri | RABBIT_URI | 符合 RabbitMQ URI 规范 的 URI,例如 amqp://user:[email protected]:10000/vhost |
如果设置了 URL,则以下属性将被忽略
属性 | 环境变量 | 描述 |
---|---|---|
zipkin.collector.rabbitmq.addresses | RABBIT_ADDRESSES | 用逗号分隔的 RabbitMQ 地址列表,例如 localhost:5672,localhost:5673 |
zipkin.collector.rabbitmq.password | RABBIT_PASSWORD | 连接到 RabbitMQ 时使用的密码,默认为 guest |
zipkinzipkinzipkin.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 建立链接 |
摘抄自 地址
注意: 存储介质由默认的内存改为 Mysql,需要先建数据库 Zipkin,然后导入 zipkin 的默认库,建完库后执行如下内容即可
https://github.com/openzipkin/zipkin/blob/master/zipkin-storage/mysql-v1/src/main/resources/mysql.sql
3、项目集成 zipkin
项目集成使用 2 模块来说明,模块名为 consumer 和 provider。主要以 Rabbit 连接方式来介绍,也会注释说下 Web 的方式
3.1、模块工程分别引入 pom
<!-- 包含 Sleuth 和 Zipkin 依赖,看下图--><dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<!-- 使用 Rabbit 连接方式启动才需要下面依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
3.2、application.yml 添加配置
consumer
spring:zipkin:
# base-url: http://192.168.1.105:9411 #Web 连接方式使用
service:
name: consumer
sender:
# type: web #Web 连接方式使用
type: rabbit # 还有 activemq、kafka
sleuth:
sampler:
probability: 1 #跟踪信息收集采样比例,默认 0.1,为 1 即 100%,收集所有 注意之前的版本是 percentage 新版本中更换为 probability
# rate: 50 # 每秒速率,即每秒最多能跟踪的请求,rate 优先
#Sleuth 使用 Rabbitmq 来向 Zipkin 发送数据
rabbitmq:
host: 192.168.1.105
port: 5672
username: guest
password: guest
provider
spring:zipkin:
# base-url: http://192.168.1.105:9411 #Web 连接方式使用
service:
name: provider
sender:
# type: web #Web 连接方式使用
type: rabbit # 还有 activemq、kafka
sleuth:
sampler:
probability: 1 #跟踪信息收集采样比例,默认 0.1,为 1 即 100%,收集所有 注意之前的版本是 percentage 新版本中更换为 probability
# rate: 50 # 每秒速率,即每秒最多能跟踪的请求,rate 优先
#Sleuth 使用 Rabbitmq 来向 Zipkin 发送数据
rabbitmq:
host: 192.168.1.105
port: 5672
username: guest
password: guest
4、测试
4.1、启动服务
分别启动 consumer、provider,然后浏览器调用 consumer 的测试接口
http://localhost:8081/consumer1?name=1111
4.2、看日志
#consumer2021-01-03 13:18:48.647 INFO [consumer,dd07a4eaac415456,dd07a4eaac415456,true] 6556 --- [nio-8081-exec-8] cn.songo.controller.ConsumerController : consumer111>>>>>>:port:8081,age:25
#provider
2021-01-03 13:18:48.652 INFO [provider,dd07a4eaac415456,75c232c4616558ce,true] 596 --- [io-18080-exec-6] cn.songo.controller.ProviderController : send---->age:261,port:18080
来看下上面的日志信息,==[consumer,dd07a4eaac415456,dd07a4eaac415456,true]==
,含义为[项目名, TraceId(相同视为一请求), SpanId(每个服务节点唯一), 是否被 Zipkin 收录]
这里使用的是 Springboot 自带的日志框架 Logback,如果使用 Log4j2,则需要修改 Pattern 添加链路信息,参考如下内容。
%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%logger{50}:%L] [%X{X-B3-TraceId},%X{X-B3-ParentSpanId},%X{X-B3-SpanId},%X{X-Span-Export}] - %msg%n
4.3、Zipkin UI 查看
浏览器地址栏访问
http://192.168.1.105:9411
可以看出来一个请求链路顺序为 consumer->provider,还可以看到调用花费的时间,到此就算配置成功了。
5、与 Seata 集成的冲突问题
5.1、问题详情
如果微服务中使用分布式事务 Seata,那集成 Zipkin 后, 就会出现问题服务调用服务失败的问题如下
com.netflix.client.ClientException: Load balancer does not have available server for client:ip
主要原因是 pom 引入的 Zipkin 包含 Sleuth,而 Sleuth 的配置类 TraceFeignClientAutoConfiguration 和 Seata 的配置类 SeataFeignClientAutoConfiguration 都创建了 Bean:feignHystrixBuilder,冲突导致上面的错误。
5.2、问题解决
每个服务工程配置 Seata 拦截器类 SetSeataInterceptor ,以拦截器的方式传递 XID
import com.bpmaxx.common.utils.StringUtils;import feign.RequestInterceptor;
import feign.RequestTemplate;
import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.stereotype.Component;
/**
* @Description: 解决 seata 与 zipkin 整合时因 SeataFeignClientAutoConfiguration 和 TraceFeignClientAutoConfiguration 都创建 Bean:feignHystrixBuilder 冲突问题
*/
@Component
@ConditionalOnClass({RequestInterceptor.class,GlobalTransactional.class})
public class SetSeataInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate request) {
String xid = RootContext.getXID();
if (StringUtils.isNotEmpty(xid)) {
request.header(RootContext.KEY_XID, xid);
}
}
}
启动类排除 SeataFeignClientAutoConfiguration.class
@SpringBootApplication(exclude = {SeataFeignClientAutoConfiguration.class})
以上是 【Java】Feign 服务调用使用 Zipkin 链路追踪 的全部内容, 来源链接: utcz.com/a/93521.html