如何在 Spring Cloud 集成 Micrometer Tracing?

1.什么是 Micrometer Tracing?

Micrometer Tracing 是一个用于微服务架构的追踪库,它提供了一种简单而强大的方式来收集和报告分布式系统中的性能和调用链信息。它是 Micrometer 库的一部分,Micrometer 是一个用于应用程序监控的指标收集工具,支持多种监控系统,如 Prometheus、Graphite 和 InfluxDB。

Micrometer Tracing 旨在帮助开发者和运维人员理解微服务之间的交互,识别性能瓶颈,并提高系统的可观察性。通过追踪请求的生命周期,Micrometer Tracing 可以提供详细的调用链信息,帮助团队快速定位问题。

Micrometer Tracing 的优势

  • 简单易用:Micrometer Tracing 提供了简单的注解和 API,使得在应用程序中添加追踪变得非常容易。
  • 与 Micrometer 生态系统集成:作为 Micrometer 的一部分,Micrometer Tracing 可以与其他监控工具无缝集成,提供全面的监控解决方案。
  • 灵活的采样策略:用户可以根据需求自定义采样策略,以平衡追踪的详细程度和性能开销。
  • 丰富的上下文信息:通过 Tags 和 Span,用户可以获得丰富的上下文信息,帮助快速定位问题。

Micrometer Tracing 的核心概念

  1. Span:Span 是追踪的基本单位,表示一个操作的开始和结束。每个 Span 都有一个唯一的标识符(Span ID),并且可以包含父 Span 的信息,从而形成一个调用链。

  2. Trace:Trace 是由多个 Span 组成的,表示一个请求在系统中的完整生命周期。每个 Trace 都有一个唯一的标识符(Trace ID),可以用来追踪整个请求的路径。

  3. Tags:Tags 是附加到 Span 上的键值对,用于提供额外的上下文信息,例如服务名称、方法名称、状态码等。Tags 可以帮助用户更好地理解和分析追踪数据。

  4. Sampler:Sampler 决定哪些请求将被追踪。可以根据请求的特征(如请求类型、服务名称等)配置采样策略,以减少性能开销。

2.环境搭建

pull images

bash 复制代码
docker pull openzipkin/zipkin

run docker

arduino 复制代码
docker run -d -p 9411:9411 openzipkin/zipkin

web UI

http://localhost:9411

3.代码工程

实验目标

在 Spring Cloud 应用程序中使用 Micrometer Tracing

添加依赖

pom.xml 中添加 Micrometer Tracing 和 Spring Cloud Sleuth 的依赖:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud-demo</artifactId>
        <groupId>com.et</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>spring-cloud-sleuth</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-tracing</artifactId>
        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-tracing-bridge-otel</artifactId>
        </dependency>
        <dependency>
            <groupId>io.opentelemetry</groupId>
            <artifactId>opentelemetry-exporter-zipkin</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

</project>

配置类

java 复制代码
package com.et.config;

import io.micrometer.observation.ObservationRegistry;
import io.micrometer.observation.aop.ObservedAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ObservedAspectConfiguration {

    @Bean
    public ObservedAspect observedAspect(ObservationRegistry observationRegistry) {
        observationRegistry.observationConfig().observationHandler(new SimpleLoggingHandler());
        return new ObservedAspect(observationRegistry);
    }
}

package com.et.config;

import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationHandler;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SimpleLoggingHandler  implements ObservationHandler<Observation.Context> {
    @Override
    public void onStart(Observation.Context context) {
        ObservationHandler.super.onStart(context);
        log.info("Starting context {} ", context);
    }

    @Override
    public void onError(Observation.Context context) {
        ObservationHandler.super.onError(context);
    }

    @Override
    public void onEvent(Observation.Event event, Observation.Context context) {
        ObservationHandler.super.onEvent(event, context);
    }

    @Override
    public void onScopeOpened(Observation.Context context) {
        ObservationHandler.super.onScopeOpened(context);
    }

    @Override
    public void onScopeClosed(Observation.Context context) {
        ObservationHandler.super.onScopeClosed(context);
    }

    @Override
    public void onScopeReset(Observation.Context context) {
        ObservationHandler.super.onScopeReset(context);
    }

    @Override
    public void onStop(Observation.Context context) {

        ObservationHandler.super.onStop(context);
        log.info("Stopping context {} ", context);
    }

    @Override
    public boolean supportsContext(Observation.Context context) {
        return true;
    }
}

为了使tracking的newspan注解生效,需要额外配置如下

kotlin 复制代码
package com.et.config;

import io.micrometer.tracing.Tracer;
import io.micrometer.tracing.annotation.DefaultNewSpanParser;
import io.micrometer.tracing.annotation.ImperativeMethodInvocationProcessor;
import io.micrometer.tracing.annotation.MethodInvocationProcessor;
import io.micrometer.tracing.annotation.NewSpanParser;
import io.micrometer.tracing.annotation.SpanAspect;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class SpanAspectConfiguration {

  @Bean
  NewSpanParser newSpanParser() {
    return new DefaultNewSpanParser();
  }

  @Bean
  MethodInvocationProcessor methodInvocationProcessor(
      NewSpanParser newSpanParser, Tracer tracer, BeanFactory beanFactory) {
    return new ImperativeMethodInvocationProcessor(
        newSpanParser, tracer, beanFactory::getBean, beanFactory::getBean);
  }

  @Bean
  SpanAspect spanAspect(MethodInvocationProcessor methodInvocationProcessor) {
    return new SpanAspect(methodInvocationProcessor);
  }
}

启用 Tracing:

在 Spring Boot 的主类上添加 @EnableAspectJAutoProxy 注解,以启用 AOP 支持:

typescript 复制代码
package com.et;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@SpringBootApplication
@EnableAspectJAutoProxy

public class SpringCloudApplication {

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

使用注解:

在需要追踪的方法上使用 @NewSpan 注解,以创建新的 Span。例如:

kotlin 复制代码
package com.et.service;

import io.micrometer.tracing.annotation.NewSpan;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * @author liuhaihua
 * @version 1.0
 * @ClassName DemoService
 * @Description todo
 * @date 2024/12/03/ 17:37
 */
@Service
@Slf4j
public class DemoService {
    @NewSpan
    public String sayHello(String name){
        log.info("hello "+name);
        return "hello "+name;
    }
}

controller

kotlin 复制代码
package com.et.controller;

import io.micrometer.tracing.SpanName;
import io.micrometer.tracing.annotation.NewSpan;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j

public class MyController {
    @Autowired
    com.et.service.DemoService demoService;
    @GetMapping("/hello")
    @NewSpan
    @SpanName("customSpanName")
    public String hello() {
        log.info("into controller ");
        return demoService.sayHello("jack");
    }
}

application.yml

yaml 复制代码
spring.application.name: demo-tracing

server:
  port: 8088
  servlet:
    context-path: /app
logging.pattern.level: "%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]"
management:
  zipkin:
    tracing:
      endpoint: http://localhost:9411/api/v2/spans
  tracing:
    sampling:
      probability: 1.0

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库

4.测试

启动Spring Cloud应用

访问rest api

访问http://127.0.0.1:8088/app/hello,控制台输出日志

ini 复制代码
2024-12-03T18:18:30.845+08:00 INFO [demo-tracing,d0f7eb048278e2374cf99e898d8cffb9,59da48fe2de9af72] 13304 --- [demo-tracing] [nio-8088-exec-4] [d0f7eb048278e2374cf99e898d8cffb9-59da48fe2de9af72] com.et.controller.MyController : into controller 
2024-12-03T18:18:30.846+08:00 INFO [demo-tracing,d0f7eb048278e2374cf99e898d8cffb9,62a3992306bc6344] 13304 --- [demo-tracing] [nio-8088-exec-4] [d0f7eb048278e2374cf99e898d8cffb9-62a3992306bc6344] com.et.service.DemoService : hello jack

查看追踪数据:

Micrometer Tracing 会自动收集追踪数据,并将其发送到配置的zipkin。你可以使用这些数据来分析请求的性能和调用链。

5.结论

Micrometer Tracing 是一个强大的工具,可以帮助开发者和运维人员更好地理解和监控微服务架构中的请求流。通过简单的配置和使用,Micrometer Tracing 可以显著提高系统的可观察性,帮助团队快速识别和解决性能问题。在现代微服务架构中,采用 Micrometer Tracing 是提升应用程序性能和可靠性的有效手段。

6.引用

相关推荐
Pandaconda15 分钟前
【Golang 面试题】每日 3 题(三十九)
开发语言·经验分享·笔记·后端·面试·golang·go
编程小筑1 小时前
R语言的编程范式
开发语言·后端·golang
技术的探险家1 小时前
Elixir语言的文件操作
开发语言·后端·golang
ss2731 小时前
【2025小年源码免费送】
前端·后端
Ai 编码助手1 小时前
Golang 中强大的重试机制,解决瞬态错误
开发语言·后端·golang
齐雅彤2 小时前
Lisp语言的区块链
开发语言·后端·golang
齐雅彤2 小时前
Lisp语言的循环实现
开发语言·后端·golang
梁雨珈2 小时前
Lisp语言的物联网
开发语言·后端·golang
邓熙榆3 小时前
Logo语言的网络编程
开发语言·后端·golang
羊小猪~~7 小时前
MYSQL学习笔记(四):多表关系、多表查询(交叉连接、内连接、外连接、自连接)、七种JSONS、集合
数据库·笔记·后端·sql·学习·mysql·考研