如何在 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.引用

相关推荐
why1512 小时前
腾讯(QQ浏览器)后端开发
开发语言·后端·golang
浪裡遊2 小时前
跨域问题(Cross-Origin Problem)
linux·前端·vue.js·后端·https·sprint
声声codeGrandMaster2 小时前
django之优化分页功能(利用参数共存及封装来实现)
数据库·后端·python·django
呼Lu噜3 小时前
WPF-遵循MVVM框架创建图表的显示【保姆级】
前端·后端·wpf
bing_1583 小时前
为什么选择 Spring Boot? 它是如何简化单个微服务的创建、配置和部署的?
spring boot·后端·微服务
学c真好玩3 小时前
Django创建的应用目录详细解释以及如何操作数据库自动创建表
后端·python·django
Asthenia04123 小时前
GenericObjectPool——重用你的对象
后端
Piper蛋窝3 小时前
Go 1.18 相比 Go 1.17 有哪些值得注意的改动?
后端
excel3 小时前
招幕技术人员
前端·javascript·后端
盖世英雄酱581364 小时前
什么是MCP
后端·程序员