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 在这里的作用是记录时间回移的数量,而不是直接返回经过调整的时间戳。
为什么要这样设计呢?考虑以下情况:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/620417.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB - 机器人关节空间运动模型

系列文章目录 前言 关节空间运动模型描述了在闭环关节空间位置控制下机械手的运动&#xff0c;在关节空间运动模型&#xff08;jointSpaceMotionModel&#xff09;对象和关节空间运动模型块中使用。 机器人机械手是典型的位置控制设备。要进行关节空间控制&#xff0c;需要指…

安卓MediaRecorder(3)音频采集编码写入详细源码分析

文章目录 前言音频采集音频初始化AudioRecord 分析AudioSource 采集到音频 音频编码音频编码后数据处理MPEG4Writer写入音频编码后数据到文件MPEG4Writer::Track 取编码后的音频编数据结语 本文首发地址 https://blog.csdn.net/CSqingchen/article/details/134896808 最新更新地…

Flask 小程序菜品搜索

mina/pages/food/index.wxml <!--index.wxml--> <!--1px 750/320 2.34rpx;--> <view class"container"><!--轮播图--><view class"swiper-container"><swiper class"swiper_box" autoplay"{{autoplay}…

直播预告丨看零售场,如何玩转 MaaS

今年&#xff0c;有一个被频繁提及的词是MaaS 这类工具正在帮助千行百业实现大模型落地产业 在零售场&#xff0c;特别是像京东这样拥有超高并发、超复杂协同的电商场内 也沉淀出了一套通用的AI基础设施——九数算法中台 从提升客户服务体验、平台效率出发&#xff0c;训练各…

Vue:调用浏览器数据库

在前一段时间写项目的时候&#xff0c;需要本地存储大量数据&#xff0c;需要在客户端进行数据存储、离线访问以及数据同步等&#xff0c;对本地数据的储存和管理非常重要。因此考虑使用了IndexedDB&#xff0c;但是接使用 IndexedDB API &#xff0c;非常麻烦&#xff0c;需要…

学习笔记-python文件基本操作

1.文件的基本操作 open()打开函数 语法 : open(name,mode) name&#xff1a;是要打开的目标文件名的字符串(可以包含文件所在的具体路径)。 mode&#xff1a;设置打开文件的模式(访问模式)&#xff1a;只读、写入、追加等。 # 打开文件open(): 如果报FileNotFoundError,文件路…

【Python】数据可视化--基于TMDB_5000_Movie数据集

一、数据准备 tmdb_5000_movie数据集下载 二、数据预处理 观察数据集合情况 import pandas as pd import ast import warnings warnings.filterwarnings(ignore) # 加载数据集 df pd.read_csv(tmdb_5000_movies.csv) # 查看数据集信息 print(df.info()) 由于原数据集包含的…

Jenkins集成Sonar Qube

下载插件 重启Jenkins 容器 sonarqube 使用令牌 Jenkins 配置 重新构建

小程序基础学习(多插槽)

先创建插槽 定义多插槽的每一个插槽的属性 在js文件中启用多插槽 在页面使用多插槽 组件代码 <!--components/my-slots/my-slots.wxml--><view class"container"><view class"left"> <slot name"left" ></slot>&…

YOLOv8改进 | 注意力篇 | 实现级联群体注意力机制CGAttention (全网首发)

一、本文介绍 本文给大家带来的改进机制是实现级联群体注意力机制CascadedGroupAttention,其主要思想为增强输入到注意力头的特征的多样性。与以前的自注意力不同,它为每个头提供不同的输入分割,并跨头级联输出特征。这种方法不仅减少了多头注意力中的计算冗余,而且通过增…

八爪鱼拉拉手

欢迎来到程序小院 八爪鱼拉拉手 玩法&#xff1a;点击鼠标左键拖动移动八爪鱼&#xff0c;当他的手很忙的时候他会很高兴&#xff0c; 不同关卡不同的八爪鱼的位置摆放&#xff0c;快去闯关吧^^。开始游戏https://www.ormcc.com/play/gameStart/248 html <div id"gam…

GCC工具源码编译

文章目录 背景一、下载源码二、编译前依赖准备2.1 相关工具依赖2.2 相关lib&#xff08;gmp/ mpfr /mpc&#xff09;依赖2.2.1 lib源码下载2.2.2 lib源码编译 三、编译GCC3.1 编译3.2 链接 四、报错处理 背景 日常可能涉及到系统里自带GCC版本与被编译源码存在不兼容&#xff…

【MySQL】巧用 Dense_Rank 窗口函数

力扣题 1、题目地址 2084. 为订单类型为 0 的客户删除类型为 1 的订单 2、模拟表 活动表&#xff1a;Orders Column NameTypeorder_idintcustomer_idintorder_typeint order_id是此表的主键列。此表的每一行都表示订单的ID、订购该订单的客户的ID以及订单类型。订单可以是…

大模型背景下计算机视觉年终思考小结(一)

1. 引言 在过去的十年里&#xff0c;出现了许多涉及计算机视觉的项目&#xff0c;举例如下&#xff1a; 使用射线图像和其他医学图像领域的医学诊断应用使用卫星图像分析建筑物和土地利用率相关应用各种环境下的目标检测和跟踪&#xff0c;如交通流统计、自然环境垃圾检测估计…

JavaScript系列——Proxy(代理)

文章目录 概要Proxy 语法handler 对象的方法Proxy 示例常用handler 对象的方法的参数handler.get()语法示例 handler.set()语法示例 使用场景验证值修正及附加属性 小结 概要 Proxy 用于创建一个对象的代理&#xff0c;将对原对象上的操作&#xff08;属性获取、赋值、函数调用…

【SSM框架】初识Spring

初识Spring Spring家族 Spring发展到今天已经形成了一种开发的生态圈&#xff0c;Spring提供了若千个项目&#xff0c;每个项目用于完成特定的功能 ✅Spring Framework&#xff08;底层框架&#xff09;Spring Boot&#xff08;提高开发速度&#xff09;Spring Cloud&#xf…

第1课 ROS 系统介绍

1.ROS操作系统介绍 在学习ROS 系统前&#xff0c;我们需要先了解操作系统的定义。操作系统&#xff0c;顾名思义&#xff0c;即提供部分软件和硬件的接口&#xff0c;以供用户直接使用。因此&#xff0c;针对不同的平台、不同的功能&#xff0c;需要采用不同的操作系统来完成底…

C++ 具名要求-全库范围的概念 - 函数对象 (FunctionObject) ,对于不同输入值产生相同输出具有很低概率-散列(hash)

此页面中列出的具名要求&#xff0c;是 C 标准的规范性文本中使用的具名要求&#xff0c;用于定义标准库的期待。 某些具名要求在 C20 中正在以概念语言特性进行形式化。在那之前&#xff0c;确保以满足这些要求的模板实参实例化标准库模板是程序员的重担。若不这么做&#xf…

智能导诊-医院信息化建设标准

智能导诊系统主要依赖于自然语言处理和机器学习等技术。患者可以通过语音、文字等方式描述病情&#xff0c;系统通过自然语言处理技术对病情进行语义分析和理解。随后&#xff0c;机器学习算法对患者的症状和病情进行推理&#xff0c;结合已有的疾病知识库&#xff0c;为患者提…

canvas设置图形图案、文字图案

查看专栏目录 canvas示例教程100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…