likes
comments
collection
share

聊聊 SpringBoot3 的 Micrometer Tracing

作者站长头像
站长
· 阅读数 15

这是个很尴尬的话题,为什么这么说呢?当我们在讨论卷和造轮子两个事情的时候,SpringBoot 的开发人员也正在做着同样的事情...

回顾

之前在 微服务-分布式链路 这篇文章中我介绍了 Dapper、OpenTracing,并以蚂蚁分布式链路组件 SOFATracer 为例,较为详细的说明了分布式链路组件中的一些技术细节和实现方式,有兴趣的同学可以自行查看。

Micrometer Tracing

最近关注 SpringBoot3 的发布,在 Production-ready Features 中,首次将 tracing 作为一个单独的功能项写进官方文档中;在此之前 SpringBoot 仅提供了 Http Tracing 的能力,并且默认情况下,是在内存中存储 近 100 次请求的记录;在 2.7.x 的官方文档中,Http Tracing 只是建议在开发环境使用,对于生产环境,官方文档也明确的指出,建议使用 Zipkin 或 Spring Cloud Sleuth 这类比较成熟的可观测性解决方案。

从 Dapper 到 OpenTracing,解决了厂商无关和统一链路 API 的问题,从 OpenTracing 到 OpenTelemetry,解决统一可观测性 API 的问题,并且 OpenTelemetry2019-5.7 被 CNCF Accepted 之后,也在不断地孵化和完善。如果说 SpringBoot 面向 OpenTelemetry 提供 Tracing,可能更便于接受,但是 SpringBoot 却使用了 Micrometer tracing,并且通过 Facade 进行了桥接 Brave 和 otel。

首先一点是,SpringBoot 将 Tracing 在 v3 系列提供出来比较容易理解,在可观测性上,tracing 一直都是 SpringBoot 缺失的,在 SpringCloud 中,它通过 Spring Cloud Slueth 整合了 Brave 补缺了这一环。

比较疑惑的是,SpringBoot 提供的 tracing 为什么会选择使用一个新的 facade Micrometer tracing 来实现,这一点我尝试从 issue 中去找答案,但也没有找到比较有说服力的,比如 Add auto-configuration for Micrometer 2.0 Observation APIAdd support for Micrometer tracing。不过有意思的是,在 spring.io/projects/sp… 这里给出了一些信息,意思就是 Spring Cloud Slueth 将迁移到 Micrometer tracing

那么关于为什么 SpringBoot 使用 Micrometer 而不是 OpenTelemetry,可能有以下几点原因(一家之言,欢迎指导):

  • 1、在之前的一些版本中,Micrometer 关注更多是 metrics,而 OpenTelemetry 则更多关注 tracing,但是随着版本的迭代完善,Micrometer 和 OpenTelemetry 在 metrics 和 tracing API 上基本都具备了。重要的是,在此之前,SpringBoot 已经对 Micrometer Metrics 进行了支持,所谓近水楼台先得月
  • 2、OpenTelemetry 的目标是厂商无关,语言无关,penTelemetry 更适合在异构技术栈中发挥作用而 Micrometer 一直以来都是基于 Java 语言,这与 Spring 体系从根上是一致的
  • 3、Micrometer API 进行大量更改。最重要的变化是引入了一个新的 API:Observation API,这样便于使用者能够使用统一的 API 来观测业务代码,包括 metrics, tracing 以及 logging。

下面就 SpringBoot3 Tracing 展开聊聊。

SpringBoot3 Tracing 剖析

SpringBoot3 在 Spring Boot Actuator 中为 Micrometer Tracing 的依赖性管理和自动配置。Micrometer Tracing 充当了类似日志领域内 slf4j 门面的角色。

Micrometer Tracing API

Micrometer Tracing 中的相关概念也是借用 Dapper 的,比如 SpanTrace 等,这里不做过多介绍。总体来说,Micrometer Tracing 包括以下几个部分:

  • 核心模块主要包含 instrumentation SPI
  • 用于适配其它 tracing 实现的 bridge 桥接器
  • 用于上报 span 数据的 reportor 扩展机制
  • 测试模块

功能划分和代码模块结构组织是一致的

聊聊 SpringBoot3 的 Micrometer Tracing

在 Micrometer Tracing 中,一个完整的 tracing 大致如下图所示

聊聊 SpringBoot3 的 Micrometer Tracing

bridge 桥接器

当前版本,Micrometer Tracing 支持两种 Tracers

在使用时,你只能选择一个 bridge 桥接实现,如果在你的 classpath 中包括两个,可能会有一些意想不到的问题,比如重复的 trace 或者 span。

Reporters

当前版本,Micrometer Tracing 支持两种 Reporters

如何和 Brave 集成的

不管是 brave 还是 otel,它们都是完整的分布式链路解决方案,包括 API 和 instrumentation;Micrometer Tracing 与 brave、otel 的集成是典型的 接口继承 + 委托 的形式实现的,以 span 为例:

import io.micrometer.tracing.Span;

/**
 * Brave implementation of a {@link Span}.
 *
 * @author Marcin Grzejszczak
 * @since 1.0.0
 */
public class BraveSpan implements Span {

    final brave.Span delegate;
    // 省略其它无关代码 ... 
}

这种方式也是 skywalking、zipkin-brave、sofatracer1.0、jaeger 等组件在早期支持 opentrcing API 的实现方式。

如何上报给 zipkin 的

我在 原理 | 分布式链路跟踪组件 SOFATracer 和 Zipkin 模型转换 这篇文章中介绍过 SOFATracer 是如何将 span 数据上报给 zipkin 的,它的做法是:在 span 结束的时候,通过预留的 reporter 扩展机制,使得用户可以通过自定义 reporter 来实现 span 数据的上报。两个关键点:

  • 上报时机:span 结束时
  • 上报方式:通过自定义 reporter 上报

Micrometer Tracing 本身包括了对 span 完整生命周期管理的 API

/**
 * Starts this span.
 * @return this span
 */
Span start();

/**
 * Ends the span. The span gets stopped and recorded if not noop.
 */
void end();

/**
 * Ends the span. The span gets stopped and recorded if not noop.
 * @param time timestamp
 * @param timeUnit time unit of the timestamp
 */
void end(long time, TimeUnit timeUnit);

因此上报时机都是一样的,在 span 结束时发生。上报方式,Brave 提供了一个 SpanHandler 扩展接口,对应的具体实现是 ZipkinSpanHandler,otel 中提供的是 SpanExporter 扩展接口,对应的实现是 ZipkinSpanExporter。下面用一张简单的图描述下

聊聊 SpringBoot3 的 Micrometer Tracing

a simple guides for you

这里给一个小案例,主要是官方文档中并没有提供 step by step 的集成方式。以 Micrometer tacing + brave + zipkin 的方式为例。

依赖

  • 增加依赖,下面给出的依赖均为必须提供的
<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-brave</artifactId>
    </dependency>
    <dependency>
        <groupId>io.zipkin.reporter2</groupId>
        <artifactId>zipkin-reporter-brave</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-tracing-bom</artifactId>
            <version>1.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

提供一个测试 REST API

@RequestMapping("api")
@RestController()
public class MyController {
    private static final Log logger = LogFactory.getLog(MyController.class);
    @RequestMapping("test")
    public String test() {
        // 配置了在日志中输出 traceId
        logger.info("this is test log ....");
        return "SUCCESS";
    }
}

基本配置

# 采样比率
management.tracing.sampling.probability=1.0
# 将 traceId 和 spanId 和 log 绑定
logging.pattern.level=%5p [${spring.application.name:test},%X{traceId:-},%X{spanId:-}]`

测试

访问 curl http://localhost:8080/api/test

  • 日志输出如下:
2022-12-06T12:06:36.971+08:00  INFO 
[test,638ebfccd315f7022e7eee028343517f,2e7eee028343517f] 61043 --- [nio-8080-
exec-1] c.g.bridge.boot.controller.MyController  : this is test log ....
  • zipkin 界面

聊聊 SpringBoot3 的 Micrometer Tracing

PS:你可能没有看到任何关于 zipkin 的配置,因为默认情况下,zipkin 的上报地址是 127.0.0.1:9411,我在本地通过 docker 启动了一个 zipkin 实例,所以我并不需要做额外的配置。

总结

本篇对 SpringBoot3 tracing 做了一些介绍,通过本篇文章,希望你可以了解到 SpringBoot3 中提供 tracing 的初衷,以及在众多事实标准存在情况下选择 Micrometer tracing 作为 API 的原因。这篇文章并不会涉及到过多对于 tracing 基础概念的介绍,如果你有兴趣可以自行查阅。最后我给出了 Micrometer tacing + brave + zipkin 一个小案例,希望可以帮助到你。

本文正在参加「金石计划 . 瓜分6万现金大奖」