Springcloud链路追踪-集成sleuth和zipkin

Scroll Down

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客户端页面
zipkinempty.png

微服务客户端配置

注意是在搭建的过程中可能会碰到一些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  

然后启动服务,调用接口后查看效果
zipkin.png

遇到的问题和解决方法

问题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