traceId:SkyWalking的traceId生成策略

这篇具有很好参考价值的文章主要介绍了traceId:SkyWalking的traceId生成策略。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

废话不多说,咱们直接上代码讲解

/**
 * SkyWalking的traceId生成策略
 * traceId 是用于唯一标识一个跟踪操作(trace)的标识符
 */
public class SkyWalkingTraceIdGenerator {
    // 生成一个唯一的进程ID,使用UUID去除横杠
    private static final String PROCESS_ID = UUID.randomUUID().toString().replaceAll("-", "");
    /*
    * 使用ThreadLocal保持每个线程的IDContext
    * 在每个线程首次访问 THREAD_ID_SEQUENCE 时,会为该线程创建一个新的 IDContext 实例
    * 并且这个实例会一直附着在这个线程上,供线程在后续的操作中使用
    * 这是为了确保每个线程都有自己独立的 IDContext 实例,以避免线程之间的干扰
    * 创建一个 ThreadLocal 对象,并通过提供的 Supplier 实例在每个线程首次访问该 ThreadLocal 对象时获取初始值
    * 在这里,初始值就是由()-> new IDContext(System.currentTimeMillis(),(short) 0) 提供的,即每个线程都会获取一个新的IDContext实例
    */
    private static final ThreadLocal<IDContext> THREAD_ID_SEQUENCE = ThreadLocal.withInitial(
        //(short) 0 表示线程内序列的起始值,即 IDContext 类中的 threadSeq 字段的初始值。在这里,它将线程内序列的起始值设置为0
        () -> new IDContext(System.currentTimeMillis(), (short) 0));

    private SkyWalkingTraceIdGenerator() {
    }

    /**
     * 生成一个新的ID,由三个部分组成。
     * 第一个部分表示应用程序实例ID。
     * 第二个部分表示线程ID。
     * 第三个部分也有两个部分,1)时间戳(以毫秒为单位)2)线程内的序列,在0(包括)和9999(包括)之间。
     *
     * @return 用于表示跟踪或段的唯一ID
     */
    public static String generate() {
        return Joiner.on(".").join(
            PROCESS_ID,
            String.valueOf(Thread.currentThread().getId()),
            String.valueOf(THREAD_ID_SEQUENCE.get().nextSeq())
        );
    }

    // IDContext类用于保持线程特定的上下文,其中包含了跟踪 ID 生成所需的信息
    private static class IDContext {
        private static final int MAX_SEQ = 10_000;
        //记录上一次的时间戳
        private long lastTimestamp;
        //记录线程内的序列
        private short threadSeq;

        // 记录上一次时间回移的时间戳,仅用于考虑由运维或操作系统引起的时间回移。
        private long lastShiftTimestamp;
        //记录上一次时间回移的值
        private int lastShiftValue;

        private IDContext(long lastTimestamp, short threadSeq) {
            this.lastTimestamp = lastTimestamp;
            this.threadSeq = threadSeq;
        }

        private long nextSeq() {
            return timestamp() * 10000 + nextThreadSeq();
        }

        private long timestamp() {
            long currentTimeMillis = System.currentTimeMillis();

            if (currentTimeMillis < lastTimestamp) {

                if (lastShiftTimestamp != currentTimeMillis) {
                    lastShiftValue++;
                    lastShiftTimestamp = currentTimeMillis;
                }
                return lastShiftValue;
            } else {
                lastTimestamp = currentTimeMillis;
                return lastTimestamp;
            }
        }

        private short nextThreadSeq() {
            if (threadSeq == MAX_SEQ) {
                threadSeq = 0;
            }
                return threadSeq++;
        }
    }
}

这是 IDContext 类中的几个关键方法的代码块的解释:

  1. private IDContext(long lastTimestamp, short threadSeq) { … }: 构造函数,用于初始化 IDContext 实例的初始状态。
    ○ this.lastTimestamp = lastTimestamp;: 将传入的 lastTimestamp 参数赋值给实例变量 lastTimestamp,表示上一次记录的时间戳。
    ○ this.threadSeq = threadSeq;: 将传入的 threadSeq 参数赋值给实例变量 threadSeq,表示线程内序列。
  2. private long nextSeq() { … }: 生成下一个序列,由时间戳和线程内序列组成。
    ○ return timestamp() * 10000 + nextThreadSeq();: 调用 timestamp() 方法获取当前时间戳,乘以 10000,然后加上调用 nextThreadSeq() 方法获取的下一个线程内序列。
  3. private long timestamp() { … }: 获取当前时间戳,考虑了时间回移的情况。
    ○ long currentTimeMillis = System.currentTimeMillis();: 获取当前时间戳。
    ○ if (currentTimeMillis < lastTimestamp) { … }: 如果当前时间小于上一次记录的时间戳,表示发生了时间回移。
    ■ if (lastShiftTimestamp != currentTimeMillis) { … }: 如果上一次时间回移的时间戳不等于当前时间戳,表示这是第一次发现时间回移。
    ● lastShiftValue++;: 时间回移值加1,用于在 timestamp() 方法中计算回移后的时间。
    ● lastShiftTimestamp = currentTimeMillis;: 记录时间回移的时间戳。
    ■ return lastShiftValue;: 返回回移后的时间。
    ○ else { … }: 如果当前时间大于等于上一次记录的时间戳,表示正常情况。
    ■ lastTimestamp = currentTimeMillis;: 更新上一次记录的时间戳。
    ■ return lastTimestamp;: 返回当前时间戳。
  4. private short nextThreadSeq() { … }: 获取下一个线程内序列,注意在达到最大值后会重新从0开始。
    ○ if (threadSeq == MAX_SEQ) { … }: 如果线程内序列达到最大值,重置为0。
    ■ threadSeq = 0;: 重置线程内序列。
    ○ return threadSeq++;: 返回当前线程内序列值,并将其递增。

在正常情况下,timestamp() 方法确实返回最新的时间戳,因为在正常情况下,当前时间戳大于等于上一次记录的时间戳。
但是,当系统检测到时间回移时,它会调整时间戳,避免出现由于时间回移导致的不连续性。lastShiftValue 在这里的作用是记录时间回移的数量,而不是直接返回经过调整的时间戳。
为什么要这样设计呢?考虑以下情况:文章来源地址https://www.toymoban.com/news/detail-809373.html

  1. 时间回移的可能性: 操作系统或运维可能会引起时间回移,导致当前时间小于上一次记录的时间。在这种情况下,返回 lastShiftValue 允许应用程序意识到发生了时间回移,而不是简单地返回一个调整后的时间戳。
  2. 连续性和递增性: 返回 lastShiftValue 可以确保时间戳的连续性和递增性。在时间回移的情况下,返回 lastShiftValue 提供了一种方式来追踪这种变化。这有助于保持生成的 ID 在整个系统中的一致性,避免由于时间回移引起的问题。
    总体来说,这个设计是为了在系统检测到时间回移时提供一种反映这一情况的机制,并确保生成的时间序列仍然是有序和递增的。

到了这里,关于traceId:SkyWalking的traceId生成策略的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • skywalking agent监控java服务

    一、前言 skywalking agent可以监控的服务类型有多种,python、go、java、nodejs服务等都可以监控,现在通过java服务来演示skywalking agent的使用,并且是使用容器的方式实现 二、部署skywalking agent监控 需要注意,skywalking agent服务也是需要使用java服务的,所以需要使用跟java服务对应的

    2024年02月11日
    浏览(43)
  • skywalking-agent-java默认不支持spring cloud gateway问题

    开发环境:Windows10 、JDK17 skywalking官网下载地址:https://skywalking.apache.org/downloads/ 解压目录为:D:Programssoft-Pluginsapache-skywalking-java-agent-8.16.0skywalking-agent 解压后目录结构为: 可参考官网博客文档:https://skywalking.apache.org/zh/2020-04-19-skywalking-quick-start/#232-idea 我的IDEA版本: Int

    2024年02月09日
    浏览(48)
  • k8s部署服务接入skywalking之java agent使用(基于sideCar模式)

    java应用在接入skywalking的时候,需要在启动参数指定 java agent的jar包 -javaagent:/usr/local/skywalking/apache-skywalking-apm-bin/agent/skywalking-agent/skywalking-agent.jar 目前不打算将agent相关文件制作到java服务镜像里面 希望通过 挂载 的方式将agent包提供出来供java服务使用 决定采用 基于sideCar 模式

    2024年02月07日
    浏览(52)
  • Spring Cloud【SkyWalking日志、SkyWalking告警 、Skywalking自定义告警规则】(十五)

      目录 分布式请求链路追踪_SkyWalking日志 分布式请求链路追踪_SkyWalking告警 

    2024年02月14日
    浏览(39)
  • Spring boot 集成 Skywalking 配置 || Skywalking 打不开【已解决】

    Apache SkyWalking 如果下载太慢,建议复制下载链接, 然后用下载器下载 ,比如某雷。 ​ 打开apm-bin 里的webapp 修改port ​ ​ 这样就解决了端口冲突问题。 ​  ​ ​   ​ -javaagent:D:testxunleiapache-skywalking-java-agent-8.10.0skywalking-agentskywalking-agent.jar //这个是你自己skywalking-agent.j

    2024年02月14日
    浏览(33)
  • Spring Cloud【SkyWalking服务环境搭建、微服务接入SkyWalking探针、Docker搭建Elasticsearch环境 】(十四)

      目录 分布式请求链路追踪_SkyWalking服务环境搭建

    2024年02月07日
    浏览(51)
  • SkyWalking链路追踪-搭建-spring-boot-cloud-单机环境 之《10 分钟快速搭建 SkyWalking 服务》

    首先了解一下单机环境 第一步,搭建一个 Elasticsearch 服务。 第二步,下载 SkyWalking 软件包。 第三步,搭建一个 SkyWalking OAP 服务。 第四步,启动一个 Spring Boot 应用,并配置 SkyWalking Agent。 第五步,搭建一个 SkyWalking UI 服务。 准备工作,准备一个docker网络组,网络组的名字为

    2024年02月15日
    浏览(59)
  • skywalking服务部署

    一、前言 Apache SkyWalking 是一个开源的分布式跟踪、监控和诊断系统,旨在帮助用户监控和诊断分布式应用程序、微服务架构和云原生应用的性能和健康状况。它提供了可视化的分析工具,帮助开发人员和运维团队深入了解应用程序的性能、调用链和异常情况 功能特点 分布式

    2024年02月11日
    浏览(36)
  • skywalking全链路监控部署

    环境配置要求 Centos 7 jdk1.8.0.144 elasticsearch 7.8.1 skyWalking 3.2.6 一、安装jdk1.8 创建相关目录,解压安装包,解压并移动到jdk目录下 设置环境变量,查看jdk版本 二、安装elasticsearch 2.1、创建用户elasticsearch useradd es passwd es 2.2、下载elasticsearch7.8.1,并解压到相关目录 2.3、修改系统参

    2024年02月08日
    浏览(39)
  • skywalking自定义插件开发

    skywalking是使用字节码操作技术和AOP概念拦截Java类方法的方式来追踪链路的,由于skywalking已经打包了字节码操作技术和链路追踪的上下文传播,因此只需定义拦截点即可。 这里以skywalking-8.7.0版本为例。 关于插件拦截的原理,可以看我的另一篇文章:skywalking插件工作原理剖析

    2023年04月24日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包