Springcloud链路追踪-集成sleuth和zipkin
springcloud sleuth和zipkin介绍
在微服务系统中,随着系统业务增加,微服务越来越多那么各个服务之间的通信也会越来越复杂,当一个业务会调用到3个服务或者3个以上服务的时候,那么如果业务处理失败,对于研发来说定位问题会很麻烦,我们需要从头一步一步跟来确定问题。本文就讲述一下springcloud sleuth组件 + zipkin的方式来进行链路追踪,sleuth + zipkin可以提供一个web ui来帮助我们方便的进行接口调用的分析和查看。
关于sleuth和zipkin的介绍大家可以参考一下链接,这里就不在过多详细介绍了(sleuth zipkin介绍)。
zipkin server搭建
现在有很多介绍搭建zipkin server的文章,这里主要提一点在springboot2.x之后官方已经不推荐使用自己搭建springboot项目的形式来搭建zipkin服务了。可以参考下面的代码,是我搭建zipkin的方式
使用jar的方式
#下载zipkin jar包,然后运行
curl -sSL https://zipkin.io/quickstart.sh | bash -s
java -jar zipkin.jar
使用docker cmd的方式
docker run -d -p 9411:9411 openzipkin/zipkin
使用docker file的方式
docker-compose -f docker-zipkin.yaml up -d
docker file内容
version: '2'
services:
zipkin:
container_name: zipkin
image: openzipkin/zipkin
environment:
- RABBIT_ADDRESSES=192.168.123.4:5672
- RABBIT_USER=admin
- RABBIT_PASSWORD=admin
- RABBIT_VIRTUAL_HOST=/vhost1
- STORAGE_TYPE=elasticsearch
- ES_HOSTS=http://192.168.123.15:9200,http://192.168.123.16:9200,http://192.168.123.17:9200
- ES_INDEX=zipkin
- ES_CLUSTER=logging-dev
ports:
- 9411:9411
我采用的是通过docker file的方式来搭建项目中的zipkin server。因为zipkin server默认的存储方式是保存在内存中,并且使用http的方式将服务之间的调用数据上报给zipkin server的。这种方式有一些隐患。
1.存储在内存中,那么zipkin server重启后数据就会丢失,那么这肯定不满足我的实际使用情况,虽然我们可以容忍链路追踪的数据不需要完全实时,可是我们也不能容忍数据这么容易全部丢失,因此我们在服务启动的时候通过STORAGE_TYPE=elasticsearch来配置存储到es中,其他ES相关的配置都是为此服务的,指定ES的host位置和index和集群名称。STORAGE_TYPE也可以指定‘cassandra,mysql’。可以参考一下链接来设置不同storage_type的配置方式和元数据(zipkin-storage)
2.使用http的方式上报数据,如果微服务之间与zipkin服务端网络不通,或调用链路上的网络有问题,那么http通信收集方式就无法工作,因此我在使用的过程中选择通过rabbit的方式来进行解藕。
RABBIT_ADDRESSES=192.168.123.4:5672
RABBIT_USER=admin
RABBIT_PASSWORD=admin
RABBIT_VIRTUAL_HOST=/vhost1
STORAGE_TYPE=elasticsearch
ES_HOSTS=http://192.168.123.15:9200,http://192.168.123.16:9200,http://192.168.123.17:9200
ES_INDEX=zipkin
ES_CLUSTER=logging-dev
有兴趣的同学可以参考官方链接来搭建zipkin server(zipkin官方搭建).
搭建完成后方位http://:9411可以看到zipkin的web客户端页面
微服务客户端配置
注意是在搭建的过程中可能会碰到一些springboot/springcloud版本兼容性的问题。这个后面在详细描述我在搭建过程中遇到的问题。项目原本使用的是springboot2.1.1.RELEASE,但是在集成过程中遇到一些问题,最终我选择的方案是springcloud版本Greenwich.SR1和springboot版本2.1.3.RELEASE最终完成服务搭建的.
添加依赖
buildscript {
ext {
springBootVersion = '2.1.4.RELEASE'
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-amqp'
implementation 'org.springframework.cloud:spring-cloud-starter-sleuth'
implementation 'org.springframework.cloud:spring-cloud-starter-zipkin'
}
添加配置
spring:
zipkin:
base-url: http://192.168.123.8:9411/
sender:
type: rabbit #type可以设置kafka,http
rabbitmq:
addresses: 192.168.123.4
port: 5672
username: admin
password: admin
virtual-host: /vhost1
然后启动服务,调用接口后查看效果
遇到的问题和解决方法
问题1.Error creating bean with name 'rabbitListenerContainerFactory' defined in class path resource [org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.class]: Initialization of bean failed; nested exception is java.lang.NullPointerException
2021-07-19 14:59:23.449 ERROR [rundeck,,,] 81213 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'rabbitListenerContainerFactory' defined in class path resource [org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.class]: Initialization of bean failed; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:584)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:846)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:863)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248)
at com.anchnet.smartops.rundeck.Application.main(Application.java:27)
Caused by: java.lang.NullPointerException: null
at org.springframework.amqp.rabbit.config.AbstractRabbitListenerContainerFactory.getAdviceChain(AbstractRabbitListenerContainerFactory.java:198)
at brave.spring.rabbit.SpringRabbitTracing.decorateSimpleRabbitListenerContainerFactory(SpringRabbitTracing.java:170)
at org.springframework.cloud.sleuth.instrument.messaging.SleuthRabbitBeanPostProcessor.postProcessBeforeInitialization(TraceMessagingAutoConfiguration.java:186)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:419)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1737)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:576)
... 15 common frames omitted
解决办法:
springcloud 版本Greenwich.SR1和springboot版本2.1.1.RELEASE集成bug fix,升级springboot到2.1.3.RELEASE可以解决(参考链接);
问题2.springcloud sleuth持久化数据到es的时候,dependence tab页没有数据显示的bug fix
解决办法:
通过使用zipkin-dependencies解决,但是zipkin-dependencies不是一个会一直在后台运行的服务,因此需要定时执行,定时间隔可以结合自己的实际场景来设置(zipken-dependenices)。
zipkin dependenices安装
通过dockerfile启动zipkin-dependenices服务
docker-compose -f docker-zipkin-dependencies.yaml up -d
docker-zipkin-dependencies.yaml文件内容
version: '2'
services:
zipkin-dependencies:
container_name: zipkin-dependencies
image: openzipkin/zipkin-dependencies
environment:
- STORAGE_TYPE=elasticsearch
- ES_HOSTS=http://192.168.123.15:9200,http://192.168.123.16:9200,http://192.168.123.17:9200