天天看点

zipkin实现SpringCloud链路追踪

一、概述

在微服务架构中,涉及服务与服务间的依赖关系非常复杂,SpringCloud 官方推荐 sleuth + zipkin 方式实现链路追踪,zipkin web 管理页面中,可以每个请求的依赖关系、请求时间、返回时间、服务与服务间的依赖图等。

在本文中主要介绍两种服务依赖情况

  • 微服务调用微服务
  • 微服务通过RabbitMQ发送消息

环境依赖:

名称 备注
JDK 1.8
RabbitMQ 3.5.6 在演示中需要启用RabbitMQ,详细介绍 https://blog.csdn.net/qq_36918149/article/details/100006373
SpringCloud Greenwich.SR1
Consul 1.5.2 注册中心,Consul安装及介绍 https://mp.csdn.net/mdeditor/95372805#
zipkin 最新版 zipkin安装配置 https://mp.csdn.net/mdeditor/100068323#

演示数据流转图:

zipkin实现SpringCloud链路追踪

customer-service 请求下单

waiter-service 生产订单,MQ通知barista-service制作咖啡,咖啡制作完成后MQ通知customer-service取coffee

barista-service 制作coffee,制作完成后MQ通知waiter-service

二 、代码

2.1 zipkin 启动并连上RabbitMQ

java -jar zipkin.jar --zipkin.collector.rabbitmq.addresses=100.61.11.211:5672 

           

2.2 customer-service (顾客服务)

1 ) 主要pom依赖

<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
 </properties>
 <dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
    <dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-consul-discovery</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
		</dependency>
		<dependency>
			<groupId>io.github.openfeign</groupId>
			<artifactId>feign-httpclient</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-zipkin</artifactId>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
		</dependency>
		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>httpclient</artifactId>
			<version>4.5.7</version>
		</dependency>
	</dependencies>
           

2 ) 配置文件

application.properties

spring.application.name=customer-service
server.port=8090

customer.name=spring-${server.port}

#zipkin 地址
spring.zipkin.base-url=http://127.0.0.1:9411/
#zipkin 日志采样比例
spring.sleuth.sampler.probability=1.0
#zipkin 推送方式
spring.zipkin.sender.type=web
# spring总是输出日志
spring.output.ansi.enabled=ALWAYS

#rabbitmq配置
spring.rabbitmq.host=100.61.11.211
spring.rabbitmq.port=5672
spring.rabbitmq.username=1234567
spring.rabbitmq.password=1234567

# 名称为:notifyOrders 的Exchange绑定消费端路由key为spring-8090
spring.cloud.stream.rabbit.bindings.notifyOrders.consumer.binding-routing-key=${customer.name}
           

3 ) CoffeeOrderService (rpc调用waiter-service接口)

@FeignClient(name = "waiter-service", contextId = "coffeeOrder")
public interface CoffeeOrderService {

    @PostMapping("/order/{id}")
    boolean createOrder(@PathVariable("id") Long id);
  }
           

4 ) CustomerController(客户订单触发接口)

@RestController
@RequestMapping("/customer")
@Slf4j
public class CustomerController {

    @Autowired
    private CoffeeOrderService coffeeOrderService;

    @PostMapping(value = "/create/order/{id}")
    public  Boolean createOrder(@PathVariable("id") Long  id){
        log.info("customer  create order no: {}",id);
      return   coffeeOrderService.createOrder(id);
    }
           

5 ) Waiter (服务启动时消息绑定接口)

public interface Waiter {
    String NOTIFY_ORDERS = "notifyOrders";

    @Input(NOTIFY_ORDERS)
    SubscribableChannel notification();
}

           

6 ) NotificationListener(接受coffee订单用餐通知)

@Component
@Slf4j
public class NotificationListener {

    @StreamListener(Waiter.NOTIFY_ORDERS)
    public void takeOrder(@Payload Long id) {
        log.info("Order No: {} is Fish, I'll take it.", id);
    }
}
           

7 ) CustomerServiceApplication 启动类

@SpringBootApplication
@Slf4j
@EnableDiscoveryClient
@EnableFeignClients
@EnableAspectJAutoProxy
@EnableBinding(Waiter.class)
public class CustomerServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(CustomerServiceApplication.class, args);
    }

    @Bean
    public CloseableHttpClient httpClient() {
        return HttpClients.custom()
                .setConnectionTimeToLive(30, TimeUnit.SECONDS)
                .evictIdleConnections(30, TimeUnit.SECONDS)
                .setMaxConnTotal(200)
                .setMaxConnPerRoute(20)
                .disableAutomaticRetries()
                .setKeepAliveStrategy(new CustomConnectionKeepAliveStrategy())
                .build();
    }
}
           

备注:@EnableBinding(Waiter.class) 绑定了MQ接口

2.3 waiter-service(服务员服务)

1 ) 主要pom依赖

<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
	</properties>
   <dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
</dependencyManagement>

     <dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-consul-discovery</artifactId>
		</dependency>
    	<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-consul-config</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-zipkin</artifactId>
		</dependency>
   </dependencies>
           

2 ) 配置文件

application.properties

spring.application.name=customer-service
server.port=8080
#zipkin 地址
spring.zipkin.base-url=http://127.0.0.1:9411/
#zipkin 日志采样比例
spring.sleuth.sampler.probability=1.0
#zipkin 推送方式
spring.zipkin.sender.type=web
# spring总是输出日志
spring.output.ansi.enabled=ALWAYS

#rabbitmq配置
spring.rabbitmq.host=100.61.11.211
spring.rabbitmq.port=5672
spring.rabbitmq.username=1234567
spring.rabbitmq.password=1234567

#Exchange 交换机: finishedOrders  绑定到Queue 队列: finishedOrders.waiter-service
spring.cloud.stream.bindings.finishedOrders.group=waiter-service
#notifyOrders 生产者路由根据 headers.customer
spring.cloud.stream.rabbit.bindings.notifyOrders.producer.routing-key-expression=headers.customer

           

3 ) Barista(服务启动时消息绑定接口)

public interface Barista {
    String NEW_ORDERS = "newOrders";
    String FINISHED_ORDERS = "finishedOrders";

    @Input
    SubscribableChannel finishedOrders();

    @Output
    MessageChannel newOrders();
}
           

4 ) Customer(服务启动时消息绑定接口)

public interface Customer {
    String NOTIFY_ORDERS = "notifyOrders";

    @Output(NOTIFY_ORDERS)
    MessageChannel notification();
}

           

5 ) CoffeeOrderController(提供rpc下单接口,及给barista发下单MQ)

@RestController
@RequestMapping("/order")
@Slf4j
public class CoffeeOrderController {
    @Autowired
    private Barista barista;

    @PostMapping("/{id}")
    public boolean createOrder(@PathVariable( "id") Long id){
        // 通知咖啡师有新的coffee有新的订单
        barista.newOrders().send(MessageBuilder.withPayload(id).build());
        return  true ;
    }
}
           

6 ) OrderListener(监听咖啡完成MQ及给customer-service 发取餐MQ)

@Component
@Slf4j
public class OrderListener {
    @Autowired
    private Customer customer;
    @Autowired
    private CoffeeOrderService orderService;

    @StreamListener(Barista.FINISHED_ORDERS)
    public void listenFinishedOrders(Long id) {
        log.info("We've finished an order no [{}].", id);
        String customerName = "张三";
        Message<Long> message = MessageBuilder.withPayload(id)
                .setHeader("customer", customerName)
                .build();
        log.info("Notify the customer: {}", customerName);
        customer.notification().send(message);
    }
}
           

7 ) WaiterServiceApplication启动类(绑定启动了对应MQ接口)

@SpringBootApplication
@EnableDiscoveryClient
@EnableBinding({ Barista.class, Customer.class })
public class WaiterServiceApplication implements WebMvcConfigurer {

    public static void main(String[] args) {
        SpringApplication.run(WaiterServiceApplication.class, args);
    }
  }
           

备注:@EnableBinding({ Barista.class, Customer.class }) 这里是在绑定相应的MQ

2.4 barista-service(制作coffee服务)

1 ) 主要pom依赖

<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
	</properties>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-zipkin</artifactId>
		</dependency>
   </dependencies>
           

2 ) 配置文件

application.properties

#服务名称
spring.application.name=barista-service
#服务端口,0表示随机端口
server.port=0
#总是推送链路到zipkin中
spring.output.ansi.enabled=ALWAYS
#zipkin中日志抽样比例
spring.sleuth.sampler.probability=1.0
#zipkin中采集日志的模式
spring.zipkin.sender.type=rabbit

#actuator 相关配置
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always

spring.rabbitmq.host=100.61.11.211
spring.rabbitmq.port=5672
spring.rabbitmq.username=1234567
spring.rabbitmq.password=1234567
#生成名称为newOrders的exchange,并绑定到 名称为 newOrders.barista-service 的Queue 上
spring.cloud.stream.bindings.newOrders.group=barista-service
           

3 ) Waiter (服务启动时消息绑定接口)

public interface Waiter {
    String NEW_ORDERS = "newOrders";
    String FINISHED_ORDERS = "finishedOrders";

    @Input(NEW_ORDERS)
    SubscribableChannel newOrders();

    @Output(FINISHED_ORDERS)
    MessageChannel finishedOrders();
}
           

4 ) OrderListener (消息监听及发送类)

@Component
@Slf4j
public class OrderListener {

    @Autowired
    @Qualifier(Waiter.FINISHED_ORDERS)
    private MessageChannel finishedOrdersMessageChannel;

    @StreamListener(Waiter.NEW_ORDERS)
    public void processNewOrder(Long id) {
        log.info("Barista start make  coffer order no {} .", id);
        try {
            Thread.sleep(200L);
        } catch (Exception e) {
        }
        finishedOrdersMessageChannel.send(MessageBuilder.withPayload(id).build());
        log.info("Barista notify Waiter finish coffee order no {} .", id);
    }

}
           

5 ) BaristaServiceApplication(启动类)

@EnableJpaRepositories
@SpringBootApplication
@EnableBinding(Waiter.class)
public class BaristaServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(BaristaServiceApplication.class, args);
    }

}

           

注意:@EnableBinding(Waiter.class) 是绑定消息接口。

三、结果演示

3.1 客户下单

url :http://localhost:8090/customer/create/order/230

zipkin实现SpringCloud链路追踪

3.2 服务调用链路

zipkin实现SpringCloud链路追踪

3.3 服务依赖关系图

zipkin实现SpringCloud链路追踪

3.4 rabbitMQ

zipkin实现SpringCloud链路追踪
zipkin实现SpringCloud链路追踪
zipkin实现SpringCloud链路追踪

四、总结

1)在项目中,可以通过http 向zipkin推送链路信息, 但是如果在生成环境数据量太大势必会有性能问题;

2)zipkin 关于海量日志数据如何保存, 还需在后期研究一下。