Seata 基于改良版雪花算法的分布式 UUID 生成器分析

news2024/11/19 14:28:57

一般来说,除了“全局唯一”这个基本属性之外,还会要求生成出来的 ID 具有“递增趋势”,这样的好处是能减少 MySQL 数据页分裂的情况,从而减少数据库的 IO 压力,提升服务的性能。

雪花算法,就是一个能生产全局唯一、递增趋势、高性能的分布式 ID 生成算法。

标准版存在的问题

时钟回拨

因为在雪花算法中,由于要生成单调递增的 ID,因此它利用了时间的单调递增性,所以是强依赖于系统时间的。

如果系统时间出现了回拨,那么生成的 ID 就可能会重复。

系统的时间漂移是一个在毫秒级别的极短的时间。

所以可以在获取 ID 的时候,记录一下当前的时间戳。然后在下一次过来获取的时候,对比一下当前时间戳和上次记录的时间戳,如果发现当前时间戳小于上次记录的时间戳,所以出现了时钟回拨现象,对外抛出异常,本次 ID 获取失败。

理论上当前时间戳会很快的追赶上上次记录的时间戳。

但是,你可能也注意到了,“对外抛出异常,本次 ID 获取失败”,意味着这段时间内你的服务对外是不可使用的。

比如,你的订单号中的某个部分是由这个 ID 组成的,此时由于 ID 生成不了,你的订单号就生成不了,从而导致下单失败。

再比如,在 Seata 里面,如果是使用数据库作为 TC 集群的存储工具,那么这段时间内该 TC 就是处于不可用状态。

简单的理解为:基础组件的错误导致服务不可用

突发性能有上限

标准版雪花算法宣称的 QPS 很大,约 400w/s,但严格来说这算耍了个文字游戏~ 因为算法的时间戳单位是毫秒,而分配给序列号的位长度为 12,即每毫秒 4096 个序列空间。 所以更准确的描述应该是 4096/ms。400w/s 与 4096/ms 的区别在于前者不要求每一毫秒的并发都必须低于 4096 (也许有些毫秒会高于 4096,有些则低于)。Seata 亦遵循此限制,若当前时间戳的序列空间已耗尽,会自旋等待下一个时间戳。

Seata 改良思路

http://seata.io/zh-cn/blog/seata-snowflake-explain.html

改进的核心思想是解除与操作系统时间戳的时刻绑定,生成器只在初始化时获取了系统当前的时间戳,作为初始时间戳, 但之后就不再与系统时间戳保持同步了。它之后的递增,只由序列号的递增来驱动。比如序列号当前值是 4095,下一个请求进来, 序列号 +1 溢出 12 位空间,序列号重新归零,而溢出的进位则加到时间戳上,从而让时间戳 +1。 至此,时间戳和序列号实际可视为一个整体了。实际上我们也是这样做的,为了方便这种溢出进位,我们调整了 64 位 ID 的位分配策略, 由原版的: 原版位分配策略

改成(即时间戳和节点ID换个位置): 改进版位分配策略

  • 这样时间戳和序列号在内存上是连在一块的,在实现上就很容易用一个 AtomicLong 来同时保存它俩:
/**
 * timestamp and sequence mix in one Long
 * highest 11 bit: not used
 * middle  41 bit: timestamp
 * lowest  12 bit: sequence
 */
private AtomicLong timestampAndSequence;
  • 最高 11 位可以在初始化时就确定好,之后不再变化:
/**
 * business meaning: machine ID (0 ~ 1023)
 * actual layout in memory:
 * highest 1 bit: 0
 * middle 10 bit: workerId
 * lowest 53 bit: all 0
 */
private long workerId;
  • 那么在生产 ID 时就很简单了:
public long nextId() {
   // 获得递增后的时间戳和序列号
   long next = timestampAndSequence.incrementAndGet();
   // 截取低53位
   long timestampWithSequence = next & timestampAndSequenceMask;
   // 跟先前保存好的高11位进行一个或的位运算
   return workerId | timestampWithSequence;
}

至此,我们可以发现:

  • 生成器不再有 4096/ms 的突发性能限制了。倘若某个时间戳的序列号空间耗尽,它会直接推进到下一个时间戳, "借用"下一个时间戳的序列号空间(不必担心这种"超前消费"会造成严重后果,下面会阐述理由)

  • 生成器弱依赖于操作系统时钟。在运行期间,生成器不受时钟回拨的影响(无论是人为回拨还是机器的时钟漂移), 因为生成器仅在启动时获取了一遍系统时钟,之后两者不再保持同步。 唯一可能产生重复ID的只有在重启时的大幅度时钟回拨(人为刻意回拨或者修改操作系统时区,如北京时间改为伦敦时间~ 机器时钟漂移基本是毫秒级的,不会有这么大的幅度)。

  • 持续不断的"超前消费"会不会使得生成器内的时间戳大大超前于系统的时间戳, 从而在重启时造成ID重复? 理论上如此,但实际几乎不可能。要达到这种效果,意味该生成器接收的 QPS 得持续稳定在 400w/s之上~ 说实话,TC 也扛不住这么高的流量,所以说呢,天塌下来有个子高的先扛着,瓶颈一定不在生成器这里。

此外,我们还调整了下节点 ID 的生成策略。原版在用户未手动指定节点ID时,会截取本地 IPv4 地址的低 10 位作为节点ID。 在实践生产中,发现有零散的节点 ID 重复的现象(多为采用 k8s 部署的用户)。例如这样的 IP 就会重复:

  • 192.168.4.10
  • 192.168.8.10

即只要 IP 的第 4 个字节和第 3 个字节的低 2 位一样就会重复。 新版的策略改为优先从本机网卡的 MAC 地址截取低 10位,若本机未配置有效的网卡,则在[0, 1023]中随机挑一个作为节点 ID。 这样调整后似乎没有新版的用户再报同样的问题了(当然,有待时间的检验,不管怎样,不会比 IP 截取策略更糟糕)。

以上就是对 Seata 的分布式 UUID 生成器的简析,如果您喜欢这个生成器,也可以直接在您的项目里使用它, 它的类声明是 public 的,完整类名为: io.seata.common.util.IdWorker

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

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

相关文章

浅谈霍尔电流传感器在汽车电池管理系统中的应用

摘要: 随着电动汽车和混合动力汽车的需求和产量正在增加,两种类型的车辆都需要高电流容量的电池来运行50kW 或更高功率的电机,并且这些都使用高压系统。汽车电池管理系统中对于电流的测量检测需要隔离测量的方式,而霍尔电流传感器…

【DLL修复工具下载】一键修复电脑丢失d3dcompiler_47.dll问题方法

在我们使用电脑的过程中,有时候会遇到一些错误提示,其中“缺失 d3dcompiler_47.dll”就是比较常见的一种。那么,d3dcompiler_47.dll 到底是什么呢?为什么会出现缺失的情况?丢失 d3dcompiler_47.dll 又会对电脑产生什么…

电压放大器如何选型号和参数配置

选择适合的电压放大器型号和配置参数是设计电子系统中至关重要的一步。电压放大器是一种关键的电子器件,用于将输入电压信号放大到所需的输出电压级别。下面西安安泰将详细介绍如何选择电压放大器的型号和配置参数。 确定应用需求:首先,需要明…

MyBatis 日志模块

文章目录 前言LogLogFactory日志应用JDBC 日志BaseJdbcLoggerConnectionLogger应用实现 总结 前言 日志在我们开发过程中占据了一个非常重要的地位,是开发和运维管理之间的桥梁,在Java中的日志框架也非常多,Log4j、Log4j2、slf4j等&#xff…

孙宇晨:稳定币支付交易具百倍增长潜力 后FTX时代行业仍需修炼内功

9月14日,波场TRON创始人、火币HTX全球顾问委员会成员孙宇晨受邀出席于新加坡举办的TOKEN 2049,并参加了“生态系统和行业增长:展望加密货币的未来十年”主题板块的讨论。孙宇晨在发言中表示,接下来的 10 年里,加密货币和区块链的最大日常应用场景仍然是稳定币支付交易,预计将有…

nodeJs+Mongodb+mongoose入门

nodeJsexpressMongodbmongooseNavicat 自我记录 一、简介 1.1 Mongodb 是什么 MongoDB 是一个基于分布式文件存储的数据库,官方地址 https://www.mongodb.com/ 1.2 数据库是什么 数据库(DataBase)是按照数据结构来组织、存储和管理数据…

KF32A学习笔记(一):工程导入、编译烧录方法(KF32 IDE+ KF32 PRO)

目录 概述KF32 IDE打开现有项目工程1.工程导入2.编译工程3.下载程序 KF32 PRO 概述 本文主要是对KF32A150芯片程序的编译、烧录方法进行说明。针对开发过程中的编译烧录和无代码情况下的烧录两种场景,需要安装ChipON PRO KF32和ChipON IDE KF32两个上位机工具&…

Linux Qt5.15.2 编译QWebEngine源码支持音视频H264

背景 默认自带的QWebEngine 因版权问题不支持音视频功能,需要自己编译源码以支持。 平台:Linux(UOS V20 1050) Qt:5.15.2 准备工作 下载 Qt 5.15.2 对应版本源码,使用镜像网站或者Qt Maintenance Tool工…

MyCat主从数据库集群搭建

1 背景 最近工作需要对比几种数据库技术方案,主从读写分离集群也是其中之一。接着上一篇文章《MySQL主从数据库搭建》基础上继续搭建MyCat主从集群。 2 MyCat 什么是MyCat?MyCat是数据库中间件,就是介于数据库和应用之间,进行数据处理与交互…

易点易动库存管理系统:引领库存用量控制新时代,助力企业节约成本

在现代企业经营中,库存管理一直是一个关键的环节。过多的库存会造成资金占用和浪费,而过少的库存则容易导致生产中断和客户满意度下降。为了解决这一难题,易点易动库存管理系统应运而生。 一、全面的库存数据管理 易点易动库存管理系统通过与…

AP5193 DC-DC恒流转换器 消防应急 灯汽车灯 应急日光灯太阳能灯驱动IC

AP5193是一款PWM工作模式,高效率、外围简单、 内置功率MOS管,适用于4.5-100V输入的高精度 降压LED恒流驱动芯片。电流2.5A。AP5193可实现线性调光和PWM调光,线性调光 脚有效电压范围0.55-2.6V. AP5193 工作频率可以通过RT 外部电阻编程来设定&#xff0c…

融云观察:AI Agent 是不是游戏赛道的下一个「赛点」?

本周四 融云直播间,点击报名~ ChatGPT 的出现,不仅让会话成为了未来商业的基本形态,也把大家谈论 AI 的语境从科技产业转向了 AI 与全产业的整合。 关注【融云全球互联网通信云】了解更多 而目前最热衷于拥抱生成式 AI 的行业中&#xff0c…

Springboot整合之Shiro和JWT技术实现无感刷新

一、Shiro简介 Shiro是Java领域非常知名的认证( Authentication )与授权 ( Authorization )框架,用以替代JavaEE中的JAAS功能。相 较于其他认证与授权框架,Shiro设计的非常简单,所以广受好 评。…

互联网架构演进方向

目录 1 业务架构1.1 单体模式1.2 中台战略1.2.1 概述1.2.2 背景1.2.3 案例 1.3 总结与思考 2 数据架构2.1 单数据库2.2 主从读写2.3 分库分表2.4 高速缓存2.5 数据多样化2.5.1 分布式文件2.5.2 nosql2.5.3 搜索引擎2.5.4 架构特点 3、应用架构3.1 单机调优3.2 动静分离3.3 分布…

【李沐深度学习笔记】矩阵计算(2)

课程地址和说明 线性代数实现p4 本系列文章是我学习李沐老师深度学习系列课程的学习笔记,可能会对李沐老师上课没讲到的进行补充。 本节是第二篇 矩阵计算 矩阵的导数运算 此处参考了视频:矩阵的导数运算 为了方便看出区别,我将所有的向量…

MQ - 21 可观测性_消息轨迹功能的设计

文章目录 导图概述丢消息是怎么回事?消息的唯一标识唯一 ID 的生成方式消息轨迹的设计应该注意什么?消息轨迹的实现方案设计客户端轨迹数据记录服务端轨迹数据记录本地文件内置 Topic (推荐)第三方服务单机维度的存储引擎结论持久存储引擎的选择RabbitMQ 消息轨迹方案设计实…

基于时序分析及约束(1)-时序约束是什么?

首先回答标题的问题: 时序约束是什么? 简单来讲,时序约束就是你要告诉综合工具,你的标准是什么。 综合工具应该如何根据你的标准来布线,以满足所以寄存器的时序要求。 为什么要做时序约束? 这里引用特权同…

Linux 入门:基本指令

本篇文章来介绍我们在初学Linux时可以会碰倒的一些基本指令,让我们对这些指令有一个基本的了解。 目录 01. ls 指令 02. pwd 命令 03. cd 指令 04. touch 指令 05. mkdir 指令(重要) 06. rmdir指令 && rm 指令(重…

基于Yolov8的工业小目标缺陷检测(4):SPD-Conv,低分辨率图像和小物体涨点明显

💡💡💡本文改进:SPD-Conv,处理低分辨率图像和小物体等更困难的任务时效果明显。 SPD-Conv | 亲测在工业小目标缺陷涨点明显,原始mAP@0.5 0.679提升至0.775 收录专栏: 💡💡💡深度学习工业缺陷检测 :http://t.csdn.cn/fVSgs ✨✨✨提供工业缺陷检测性能提升…

uniapp 内容展开组件

uni-collapse折叠面板并不符合需求&#xff0c;需要自己写一个。 效果展示&#xff1a; 代码&#xff1a; &#xff08;vue3版本&#xff09; <template><view class"collapse-view"><view class"collapse-content"><swiper:autopl…