详解分布式ID实践
引言
分布式ID,所谓的分布式ID,就是针对整个系统而言,任何时刻获取一个ID,无论系统处于何种情况,该值不会与之前产生的值重复,之后获取分布式ID时,也不会再获取到与其相同的值,它是一个绝对意义上的全局唯一值。
那么,究竟什么情况下需要用到分布式ID呢?
最经典的场景是分库分表,还是以用户数据来举例子,之前只有一张用户表,所以设置表ID自增后,每新增一条数据都会自增ID值,从而确保了ID永远不会重复。
此刻用户表被分成了十张,如果再依靠数据库本身的自增机制来分配ID,显然会导致ID重复,这时分布式ID就派上了用场。除开分库分表外,通常还会用到分布式ID的场景有:
- 链路
ID
:分布式链路中,需要通过全局唯一的traceId
来串联所有日志; - 请求
ID
:幂等性处理时,需要通过唯一的ID
来判断是否为重复请求; - 消息标识:
MQ
需要基于唯一的msgID
来区分数据,确保数据不重复或丢失; - 短链码:生成短链接时,需要获取一个全局唯一的值作为
Code
避免重复;
下面将阐述怎么在项目中实践,为我们的对象生成一个分布式ID
UUID生成
String uuid = UUID.randomUUID().toString();
System.out.println(uuid);/*
* 输出结果:
* b2c2ec5d-efb9-44c7-b2c8-9cef367c8b3f
* */
通过JDK提供的UUID工具类,一行代码就能生成一个UUID,并且得到的UUID不会重复,怎么保障的呢?UUID的底层,会基于硬件地址(MAC地址)、时间戳和随机因子来生成ID。
世界上没有两片完全相同的叶子,者如这句话一般,世界上也没有两台完全相同的机器,这时硬件地址自然不同,再加上正常情况下不可逆转的时间戳,以及一定范围的随机数,就能确保产生的UUID,其全球唯一性。
雪花算法
雪花算法生成的分布式ID
,在Java
中会使用Long
类型来承载,Long
类型占位8bytes
,也就正好对应上述这张图的64
个比特位,这64bit
会被分为四部分:
- 符号位(
1bit
):永远为零,表示生成的分布式ID
为正数。 - 时间戳位(
2~42bit
):会将当前系统的时间戳插入到这段位置。 - 工作进程位(
43~53bit
):在集群环境下,每个进程唯一的工作ID
。 - 序列号位(
54~64bit
):该序列是用来在同一个毫秒内生成不同的序列号。
/*
* 雪花算法实现类
* */
public class Snowflake implements Serializable {private static final long serialVersionUID = 1L;// 雪花算法的起始时间纪元public static long DEFAULT_TWEPOCH = 1288834974657L;public static long DEFAULT_TIME_OFFSET = 2000L;// 机器标识所占的位数private static final long WORKER_ID_BITS = 5L;// 数据中心标识所占的位数private static final long DATA_CENTER_ID_BITS = 5L;// 毫秒内的自增位数private static final long SEQUENCE_BITS = 12L;// 机器ID最大值private static final long MAX_WORKER_ID = 31L;// 数据中心ID最大值private static final long MAX_DATA_CENTER_ID = 31L;// 机器ID左移12位private static final long WORKER_ID_SHIFT = 12L;// 数据中心左移17位private static final long DATA_CENTER_ID_SHIFT = 17L;// 毫秒时间戳左移22位private static final long TIMESTAMP_LEFT_SHIFT = 22L;private static final long SEQUENCE_MASK = 4095L;// 雪花ID相关组成部分的定义private final long twepoch;private final long workerId;private final long dataCenterId;private final boolean useSystemClock;private final long timeOffset;private final long randomSequenceLimit;private long sequence;// 最近一次生产ID的时间戳private long lastTimestamp;public Snowflake() {this(IdUtil.getWorkerId(IdUtil.getDataCenterId(31L), 31L));}public Snowflake(long workerId) {this(workerId, IdUtil.getDataCenterId(31L));}public Snowflake(long workerId, long dataCenterId) {this(workerId, dataCenterId, false);}public Snowflake(long workerId, long dataCenterId, boolean isUseSystemClock) {this((Date)null, workerId, dataCenterId, isUseSystemClock);}public Snowflake(Date epochDate, long workerId, long dataCenterId, boolean isUseSystemClock) {this(epochDate, workerId, dataCenterId, isUseSystemClock, DEFAULT_TIME_OFFSET);}public Snowflake(Date epochDate, long workerId, long dataCenterId, boolean isUseSystemClock, long timeOffset) {this(epochDate, workerId, dataCenterId, isUseSystemClock, timeOffset, 0L);}public Snowflake(Date epochDate, long workerId, long dataCenterId, boolean isUseSystemClock, long timeOffset, long randomSequenceLimit) {this.sequence = 0L;this.lastTimestamp = -1L;this.twepoch = null != epochDate ? epochDate.getTime() : DEFAULT_TWEPOCH;this.workerId = Assert.checkBetween(workerId, 0L, 31L);this.dataCenterId = Assert.checkBetween(dataCenterId, 0L, 31L);this.useSystemClock = isUseSystemClock;this.timeOffset = timeOffset;this.randomSequenceLimit = Assert.checkBetween(randomSequenceLimit, 0L, 4095L);}public long getWorkerId(long id) {return id >> 12 & 31L;}public long getDataCenterId(long id) {return id >> 17 & 31L;}public long getGenerateDateTime(long id) {return (id >> 22 & 2199023255551L) + this.twepoch;}public synchronized long nextId() {long timestamp = this.genTime();// 解决时钟回拨问题if (timestamp < this.lastTimestamp) {if (this.lastTimestamp - timestamp >= this.timeOffset) {throw new IllegalStateException(StrUtil.format("Clock moved backwards. Refusing to generate id for {}ms", new Object[]{this.lastTimestamp - timestamp}));}timestamp = this.lastTimestamp;}if (timestamp == this.lastTimestamp) {long sequence = this.sequence + 1L & 4095L;if (sequence == 0L) {timestamp = this.tilNextMillis(this.lastTimestamp);}this.sequence = sequence;} else if (this.randomSequenceLimit > 1L) {this.sequence = RandomUtil.randomLong(this.randomSequenceLimit);} else {this.sequence = 0L;}this.lastTimestamp = timestamp;return timestamp - this.twepoch << 22 | this.dataCenterId << 17 | this.workerId << 12 | this.sequence;}public String nextIdStr() {return Long.toString(this.nextId());}private long tilNextMillis(long lastTimestamp) {long timestamp;for(timestamp = this.genTime(); timestamp == lastTimestamp; timestamp = this.genTime()) {}if (timestamp < lastTimestamp) {throw new IllegalStateException(StrUtil.format("Clock moved backwards. Refusing to generate id for {}ms", new Object[]{lastTimestamp - timestamp}));} else {return timestamp;}}private long genTime() {return this.useSystemClock ? SystemClock.now() : System.currentTimeMillis();}
}
上面代码可以直接引用来作为我们的雪花算法工具类
由于原始版雪花算法存在的问题,出现了许多改良版算法,但其核心还是前面聊到的雪花算法,比如百度的Uid-Generator算法、美团的Leaf算法-雪花模式、阿里的Seata框架里的雪花算法实现等等,感兴趣的小伙伴可以自行翻阅源码。
以上就是最常用的实践方式欢迎大家补充
相关文章:

详解分布式ID实践
引言 分布式ID,所谓的分布式ID,就是针对整个系统而言,任何时刻获取一个ID,无论系统处于何种情况,该值不会与之前产生的值重复,之后获取分布式ID时,也不会再获取到与其相同的值,它是…...

.NET + Vue3 的前后端项目在IIS的发布
目录 一、发布准备 1、安装 IIS 2、安装 Windows Hosting Bundle(.NET Core 托管捆绑包) 3、安装 IIS URL Rewrite 二、项目发布 1、后端项目发布 2、前端项目发布 3、将项目部署到 IIS中 三、网站配置 1、IP配置 2、防火墙配置 3、跨域配置…...

软件测试之压力测试
🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 压力测试 压力测试是一种软件测试,用于验证软件应用程序的稳定性和可靠性。压力测试的目标是在极其沉重的负载条件下测量软件的健壮性和错误处理能力&…...

矩阵-矩阵置零
矩阵置零 给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为0 。请使用 原地 算法。在计算机科学中,一个原地算法(in-place algorithm)是一种使用小的,固定数量的额外之空间来转…...
【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-Chapter19-表单脚本
十九、表单脚本 表单脚本 JavaScript 较早的一个用途是承担一部分服务器端表单处理的责任。虽然 Web 和 JavaScript 都已经发展了很多年,但 Web 表单的变化不是很大。由于不能直接使用表单解决问题,因此开发者不得不使用JavaScript 既做表单验证…...
【C# 数据结构】队列 FIFO
目录 队列的概念FIFO (First-In, First-Out)Queue<T> 的工作原理:示例:解释: 小结: 环形队列1. **FIFO?**2. **环形缓冲队列如何实现FIFO?**关键概念: 3. **环形缓冲队列的工作过程**假设…...

论文笔记-WWWCompanion2024-LLM as Data Augmenters for Cold-Start Item Recommendation
论文笔记-WWW Companion 2024-Large Language Models as Data Augmenters for Cold-Start Item Recommendation 大语言模型作为冷启动项目推荐的数据增强器摘要1.引言2.前言3.LLMs作为数据增强3.1增强数据生成3.2成对比较损失 4.实验4.1实验设置4.2结果和分析4.3超参数实验 5.总…...
Java 语法新特性(Records、Pattern Matching、Sealed Classes)深度解析(11/17/21)✨
一、Records(Java 16) 📝 核心价值:简化不可变数据载体的定义 // 传统POJO vs Record public record User(String name, int age) {} // 自动生成:构造方法/equals()/hashCode()/toString() User user new User(&qu…...
QUdpSocket的readyRead信号只触发一次
问题 QUdpSocket的readyRead信号只触发一次。 原因 on_readyRead槽函数里必须读出现有数据后,才能触发新的事件。 解决办法 在on_readyRead槽函数里取出数据。 void MainWindow::on_readyRead() {qDebug() << "on_readyRead in";while (m_udp…...

jsherp importItemExcel接口存在SQL注入
一、漏洞简介 很多人说管伊佳ERP(原名:华夏ERP,英文名:jshERP)是目前人气领先的国产ERP系统虽然目前只有进销存财务生产的功能,但后面将会推出ERP的全部功能,有兴趣请帮点一下 二、漏洞影响 …...
测试data_management函数
测试data_management函数 这是我最近正在开发的AI工具信息平台的部门功能模块测试,基于streamlit架构。整理出来与大家分享,也为我以后自己回溯找到资源。 为了测试 data_management 函数并结合 Excel 文件中的 “Tools” 表单内容,我们需要…...
微信小程序---计划时钟设计与实现
微信小程序-计划时钟已上线,欢迎各位小伙伴的测试和使用~(微信小程序搜计划时钟即可使用) 在这篇博客中,我们将探讨如何在微信小程序中设计和实现一个任务管理功能,该功能允许用户添加、删除和查看任务。任务管理系统的核心是基于日期和时间的任务管理,可以设置任务的开…...

深度学习之图像回归(二)
前言 这篇文章主要是在图像回归(一)的基础上对该项目进行的优化。(一)主要是帮助迅速入门 理清一个深度学习项目的逻辑 这篇文章则主要注重在此基础上对于数据预处理和模型训练进行优化前者会通过涉及PCA主成分分析 特征选择 后…...

深入理解HttpSecurity的设计
一、HttpSecurity的应用 在前章节的介绍中我们讲解了基于配置文件的使用方式,也就是如下的使用。 也就是在配置文件中通过 security:http 等标签来定义了认证需要的相关信息,但是在SpringBoot项目中,我们慢慢脱离了xml配置文件的方式,在SpringSecurity中提供了HttpSecurity…...

15增减字符串匹配(贪心)思路解析+源码
文章目录 题目[](https://leetcode.cn/problems/di-string-match/)算法原理贪心证明源码总结题目 假设s="I D I D"也就是增降增降,在0-4中,每两个数存在这种方式数组为【1, 3,2, 4,0】;(如下图) 算法原理 解法:贪心 1.当遇到“I”:选择当前最小的那个数 2…...

Java NIO与传统IO性能对比分析
Java NIO与传统IO性能对比分析 在Java中,I/O(输入输出)操作是开发中最常见的任务之一。传统的I/O方式基于阻塞模型,而Java NIO(New I/O)引入了非阻塞和基于通道(Channel)和缓冲区&a…...
14.7 LangChain Experimental 模块解析:解锁 Auto-GPT 开发新范式
LangChain Experimental 模块解析:解锁 Auto-GPT 开发新范式 关键词:LangChain Experimental、Auto-GPT 实现、自主智能体开发、Agent 架构设计、实验性功能实践 1. LangChain Experimental 模块的定位与核心能力 模块定位解析: #mermaid-svg-4xz2OlZBUFjkBmqw {font-fami…...

wps中的js开发
严格区分大小写 /*** learn_js Macro*/ function test() {Range(D7).Value2Selection.Value2; // Selection.formula "100" }function Workbook_SheetSelectionChange(Sh, Target) {if(Sh.Name Sheet1) {test();}}function test2() {// 把I4单元格及其周边有数的单…...

day16_推荐系统和总结
文章目录 day16_推荐系统和总结一、推荐实现1、基于流行度推荐(掌握)1.1 近期热门商品推荐1.2 个人热门商品推荐 2、基于隐语义模型的协同过滤推荐(了解)2.1 ALS算法介绍2.2 推荐代码 3、基于物品的协同过滤推荐(了解&…...

一文说清楚编码、摘要、加密、公钥、私钥、解密、签名、验签
编码 对信息进行编码,没有信息损失,任何人都能通过编码方式对信息进行解码。例如 ASCII 码,base64 编码。 例如下面是 ASCII 编码表: 摘要 对信息计算摘要值,有信息损失,例如 md5 摘要,sh…...

Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)
考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...