分布式ID生成方案详解

                         ✨✨ 祝屏幕前的您天天开心 ,每天都有好运相伴。我们一起加油!✨✨ 
                                           🎈🎈作者主页: 喔的嘛呀🎈🎈

目录

引言

一. UUID(Universally Unique Identifier)

UUID版本

版本1 UUID

版本4 UUID

UUID用途

二、数据库自增ID

三. 基于Redis的方案

四. Twitter的snowflake算法

五、百度UidGenerator

结语


引言

在分布式系统中,生成唯一标识符(ID)是一个常见的需求。在这篇博客中,我们将介绍几种常见的分布式ID生成方案,包括UUID、Snowflake算法、基于数据库的方案和基于Redis的方案。我们将深入探讨每种方案的原理、优缺点,并提供相应的代码示例。

一. UUID(Universally Unique Identifier)

UUID(Universally Unique Identifier)是一种标准化的128位数字(16字节)格式,通常用32个十六进制数字表示。UUID的目的是让分布式系统中的多个节点生成的标识符在时间和空间上都是唯一的。

UUID通常由以下几部分组成:

  1. 时间戳:占据前32位,表示生成UUID的时间戳。
  2. 时钟序列号:占据接下来的16位,保证在同一时刻生成的UUID的唯一性。
  3. 全局唯一的节点标识符:占据最后的48位,通常是机器的MAC地址。

UUID的生成方法有多种,其中比较常见的是基于当前时间戳和随机数生成。Java中可以使用java.util.UUID类来生成UUID,示例如下:

import java.util.UUID;public class UUIDGenerator {public static void main(String[] args) {UUID uuid = UUID.randomUUID();System.out.println("Generated UUID: " + uuid.toString());}
}

这段代码将生成一个类似于550e8400-e29b-41d4-a716-446655440000的UUID。由于UUID的唯一性和随机性,通常用于分布式系统中的唯一标识符,例如作为数据库表的主键。 

二、数据库自增ID


使用数据库的id自增策略,如 MySQL 的 auto_increment。并且可以使用两台数据库分别设置不同
步长,生成不重复ID的策略来实现高可用。
优点:数据库生成的ID绝对有序,高可用实现方式简单
缺点:需要独立部署数据库实例,成本高,有性能瓶颈

在许多关系型数据库中,自增ID是一种常见的用于唯一标识表中记录的方式。下面我将以MySQL为例,介绍如何在数据库中使用自增ID。

首先,我们需要创建一个带有自增ID的表。以下是一个简单的示例表的创建语句:

CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(50) NOT NULL,email VARCHAR(100) NOT NULL
);

在这个例子中,id 列被定义为自增列,并且被指定为主键。每次向表中插入一条记录时,id 列都会自动递增,确保每个记录都有唯一的ID。

接下来,我们可以通过插入数据来演示自增ID的工作原理:

INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');
INSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com');
INSERT INTO users (name, email) VALUES ('Charlie', 'charlie@example.com');

查询表中的数据:

SELECT * FROM users;

输出应该类似于:

+----+---------+------------------+
| id | name    | email            |
+----+---------+------------------+
| 1  | Alice   | alice@example.com|
| 2  | Bob     | bob@example.com  |
| 3  | Charlie | charlie@example.com|
+----+---------+------------------+

每次插入一条记录时,id 列都会自动递增。这就是自增ID的基本工作原理。

三. 基于Redis的方案

Redis的所有命令操作都是单线程的,本身提供像 incr 和 increby 这样的自增原子命令,所以能保
证生成的 ID 肯定是唯一有序的。
优点:不依赖于数据库,灵活方便,且性能优于数据库;数字ID天然排序,对分页或者需要排
序的结果很有帮助。
缺点:如果系统中没有Redis,还需要引入新的组件,增加系统复杂度;需要编码和配置的工作
量比较大。
考虑到单节点的性能瓶颈,可以使用 Redis 集群来获取更高的吞吐量。假如一个集群中有5台
Redis。可以初始化每台 Redis 的值分别是1, 2, 3, 4, 5,然后步长都是 5。

在 Redis 中生成自增 ID 通常可以通过使用 INCR 命令实现。INCR 命令会将存储在指定键中的数字递增 1,并返回递增后的值。你可以利用这个特性来实现一个简单的自增 ID 生成器。以下是一个基本的示例:

import redis.clients.jedis.Jedis;public class RedisIdGenerator {private Jedis jedis;public RedisIdGenerator() {this.jedis = new Jedis("localhost");}public long getNextId(String key) {return jedis.incr(key);}public static void main(String[] args) {RedisIdGenerator idGenerator = new RedisIdGenerator();String key = "my_id_counter";// 使用示例for (int i = 0; i < 5; i++) {long id = idGenerator.getNextId(key);System.out.println("Generated ID: " + id);}}
}

在这个示例中,我们首先创建了一个 RedisIdGenerator 类,该类包含一个 getNextId 方法,用于生成下一个自增 ID。在 main 方法中,我们创建了一个实例,并连续调用 getNextId 方法来生成 ID。

需要注意的是,这只是一个简单的示例。在实际应用中,你可能需要考虑并发访问时的线程安全性,以及如何处理 Redis 连接的创建和关闭等问题。

四. Twitter的snowflake算法

Twitter的Snowflake算法是一种用于生成分布式唯一ID的算法,它可以在分布式系统中生成全局唯一的ID。Snowflake算法的核心思想是将一个64位的long型的ID分成多个部分,包括时间戳、机器ID和序列号。具体来说,Snowflake算法的ID结构如下:

 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unused |   timestamp   |   worker ID  | sequence
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • 位表示未使用的位,可根据需要保留或用于其他用途。
  • 41位表示时间戳,可以表示的时间范围为2^41 / 1000 / 60 / 60 / 24 = 69年左右。
  • 10位表示机器ID,可以用来区分不同的机器。
  • 12位表示序列号,可以用来区分同一机器同一时间戳内生成的不同ID。

Snowflake算法生成ID的过程如下:

  1. 获取当前时间戳,单位是毫秒。
  2. 使用配置的机器ID。
  3. 如果当前时间戳与上一次生成ID的时间戳相同,则使用序列号加1;否则序列号重置为0。
  4. 将时间戳、机器ID和序列号合并生成最终的ID。

Snowflake算法的优点是生成的ID是递增的、趋势递增的,并且可以根据需要提取出生成ID的时间戳和机器ID。然而,Snowflake算法也有一些缺点,例如在高并发情况下可能会出现ID重复的情况,需要适当的措施来避免这种情况的发生。

Snowflake 算法是 Twitter 开源的一种分布式唯一 ID 生成算法,用于生成全局唯一的 ID。它的核心思想是将 ID 分为不同的部分,包括时间戳、机器 ID 和序列号。下面是一个详细的实现:

public class SnowflakeIdGenerator {private final long twepoch = 1288834974657L; // 起始时间戳,可以根据实际需求调整private final long workerIdBits = 5L; // 机器 ID 的位数private final long datacenterIdBits = 5L; // 数据中心 ID 的位数private final long maxWorkerId = -1L ^ (-1L << workerIdBits); // 最大机器 IDprivate final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); // 最大数据中心 IDprivate final long sequenceBits = 12L; // 序列号的位数private final long workerIdShift = sequenceBits; // 机器 ID 左移位数private final long datacenterIdShift = sequenceBits + workerIdBits; // 数据中心 ID 左移位数private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; // 时间戳左移位数private final long sequenceMask = -1L ^ (-1L << sequenceBits); // 序列号掩码private long workerId;private long datacenterId;private long sequence = 0L;private long lastTimestamp = -1L;public SnowflakeIdGenerator(long workerId, long datacenterId) {if (workerId > maxWorkerId || workerId < 0) {throw new IllegalArgumentException("Worker ID 必须介于 0 和 " + maxWorkerId + " 之间");}if (datacenterId > maxDatacenterId || datacenterId < 0) {throw new IllegalArgumentException("Datacenter ID 必须介于 0 和 " + maxDatacenterId + " 之间");}this.workerId = workerId;this.datacenterId = datacenterId;}public synchronized long nextId() {long timestamp = timeGen();if (timestamp < lastTimestamp) {throw new RuntimeException("时钟回拨发生在 " + (lastTimestamp - timestamp) + " 毫秒内");}if (timestamp == lastTimestamp) {sequence = (sequence + 1) & sequenceMask;if (sequence == 0) {timestamp = tilNextMillis(lastTimestamp);}} else {sequence = 0L;}lastTimestamp = timestamp;return ((timestamp - twepoch) << timestampLeftShift)| (datacenterId << datacenterIdShift)| (workerId << workerIdShift)| sequence;}private long tilNextMillis(long lastTimestamp) {long timestamp = timeGen();while (timestamp <= lastTimestamp) {timestamp = timeGen();}return timestamp;}private long timeGen() {return System.currentTimeMillis();}public static void main(String[] args) {SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 1);// 使用示例for (int i = 0; i < 5; i++) {long id = idGenerator.nextId();System.out.println("Generated ID: " + id);}}
}

在这个实现中,我们首先定义了 Snowflake 算法中需要用到的各种参数和位移操作。然后,我们实现了一个 nextId 方法来生成下一个 ID。在 main 方法中,我们创建了一个 SnowflakeIdGenerator 实例,并连续调用 nextId 方法来生成 ID。

需要注意的是,Snowflake 算法中的时间戳部分可以根据实际需求进行调整,以确保生成的 ID 在不同时间内仍然是唯一的。

五、百度UidGenerator

百度的 UIDGenerator 是一个分布式唯一 ID 生成器,类似于 Twitter 的 Snowflake 算法,但在细节上有所不同。以下是一个简化的实现,展示了其基本原理:

import java.util.concurrent.atomic.AtomicLong;public class BaiduUidGenerator {private final long twepoch = 1288834974657L; // 起始时间戳,可以根据实际需求调整private final long workerIdBits = 10L; // 机器 ID 的位数private final long sequenceBits = 12L; // 序列号的位数private final long workerIdShift = sequenceBits; // 机器 ID 左移位数private final long timestampLeftShift = sequenceBits + workerIdBits; // 时间戳左移位数private final long sequenceMask = -1L ^ (-1L << sequenceBits); // 序列号掩码private final long workerId;private volatile long lastTimestamp = -1L;private volatile long sequence = 0L;public BaiduUidGenerator(long workerId) {if (workerId < 0 || workerId >= (1 << workerIdBits)) {throw new IllegalArgumentException("Worker ID 必须介于 0 和 " + ((1 << workerIdBits) - 1) + " 之间");}this.workerId = workerId;}public synchronized long nextId() {long timestamp = timeGen();if (timestamp < lastTimestamp) {throw new RuntimeException("时钟回拨发生在 " + (lastTimestamp - timestamp) + " 毫秒内");}if (timestamp == lastTimestamp) {sequence = (sequence + 1) & sequenceMask;if (sequence == 0) {timestamp = tilNextMillis(lastTimestamp);}} else {sequence = 0L;}lastTimestamp = timestamp;return ((timestamp - twepoch) << timestampLeftShift)| (workerId << workerIdShift)| sequence;}private long tilNextMillis(long lastTimestamp) {long timestamp = timeGen();while (timestamp <= lastTimestamp) {timestamp = timeGen();}return timestamp;}private long timeGen() {return System.currentTimeMillis();}public static void main(String[] args) {BaiduUidGenerator uidGenerator = new BaiduUidGenerator(1);// 使用示例for (int i = 0; i < 5; i++) {long id = uidGenerator.nextId();System.out.println("Generated ID: " + id);}}
}

在这个实现中,我们首先定义了 BaiduUidGenerator 类,其中包含了与 Snowflake 算法类似的参数和位移操作。然后,我们实现了一个 nextId 方法来生成下一个 ID。在 main 方法中,我们创建了一个 BaiduUidGenerator 实例,并连续调用 nextId 方法来生成 ID。

需要注意的是,这只是一个简化的实现,实际应用中可能需要根据具体需求进行调整和优化。

结语

以上是几种常见的分布式ID生成方案,每种方案都有其适用的场景,开发人员可以根据实际需求选择合适的方案。

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

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

相关文章

开发者利器: 从 Amazon CodeWhisperer 到 Amazon Q

自 ChatGPT 火爆以来&#xff0c;生成式 AI 助手也是层出不穷&#xff0c;目前自然是以 Microsoft Copilot&#xff08;基于 GPT&#xff09;普及度最高了吧。看着微软风光了这么久&#xff0c;其他云厂商怎么可能会甘愿落后&#xff1f; 最近&#xff0c;来自亚马逊云科技的 …

阿里云国际云解析DNS如何开启/关闭流量分析?

流量分析服务会涉及产生日志费用&#xff0c;所以开通内网DNS解析服务后&#xff0c;默认不会主动开启流量分析&#xff0c;需要您手动开启流量分析。对于未开启流量分析的用户&#xff0c;进入界面会提示您展示的都是模拟数据&#xff0c;您可以点击开启流量分析服务&#xff…

B站项目-基于Pytorch的ResNet垃圾图片分类

基于Pytorch的ResNet垃圾图片分类 项目链接 数据集下载链接 1. 数据集预处理 1.1 画图片的宽高分布散点图 import osimport matplotlib.pyplot as plt import PIL.Image as Imagedef plot_resolution(dataset_root_path):image_size_list []#存放图片尺寸for root, dirs, fi…

实验室储样瓶耐强酸强碱PFA材质试剂瓶适用新材料半导体

PFA&#xff0c;全名可溶性聚四氟乙烯&#xff0c;试剂瓶又叫取样瓶、样品瓶、广口瓶、储样瓶等。主要用于痕量分析、同位素分析等实验室&#xff0c;广泛应用于新兴的半导体、新材料、多晶硅、硅材、微电子等行业。 规格参考&#xff1a;30ml、60ml、100ml、125ml、250ml、30…

使用keil移植freerots简结

1.安装keil 5.0 2.安装 keil device 软件包&#xff1a;具体单片机软件包下载地址&#xff1a; Arm Keil | Deviceshttps://www.keil.arm.com/devices/ &#xff0c;选择自己单片机所属型号.下载后导入即可. 3.新建工程时选择对应device&#xff1a; 选择CMISIS的CORE即可.其…

ABBYY FineReader16文档转换、PDF管理与文档比较功能介绍

ABBYY FineReader 16作为一款OCR和PDF一体化程序&#xff0c;其强大的功能使得文档处理变得简单高效。在众多功能中&#xff0c;文档转换、PDF管理和文档比较这三大功能尤为突出&#xff0c;成为了众多企业和个人用户的首选工具。 ABBYY Finereader 16-安装包下载如下&#xff…

kafka学习笔记三

第二篇 外部系统集成 Flume、Spark、Flink、SpringBoot 这些组件都可以作为kafka的生产者和消费者&#xff0c;在企业中非常常见。 Flume官网&#xff1a;Welcome to Apache Flume — Apache Flume Flink&#xff1a;Apache Flink_百度百科 Spark&#xff1a;Apache Spark…

openEuler2203 LTS环境下docker容器的配置与应用

一、说明 本文配置环境为VMware虚拟机&#xff08;4核CPU&#xff0c;8 GB内存&#xff0c;40GB磁盘&#xff09;&#xff0c;OS为openEuler 22.03 LTS &#xff0c;虚拟机要求能联网。 二、安装docker 1、安装docker软件包 [rootnode1 ~]# dnf -y install docker2、查看do…

高性能API云原生网关 APISIX安装与配置指南

Apache APISIX是Apache软件基金会下的顶级项目&#xff0c;由API7.ai开发并捐赠。它是一个高性能的云原生API网关&#xff0c;具有动态、实时等特点。 APISIX网关可作为所有业务的流量入口&#xff0c;为用户提供了丰富的功能&#xff0c;包括动态路由、动态上游、动态证书、A…

autocrlf和safecrlf

git远程拉取及提交代码&#xff0c;windows和linux平台换行符转换问题&#xff0c;用以下两行命令进行配置&#xff1a; git config --global core.autocrlf false git config --global core.safecrlf true CRLF是windows平台下的换行符&#xff0c;LF是linux平台下的换行符。…

SpringBoot源码解读与原理分析(三十三)SpringBoot整合JDBC(二)声明式事务的生效原理和控制流程

文章目录 前言10.3 声明式事务的生效原理10.3.1 TransactionAutoConfiguration10.3.2 TransactionManagementConfigurationSelector10.3.3 AutoProxyRegistrar10.3.4 InfrastructureAdvisorAutoProxyCreator10.3.5 ProxyTransactionManagementConfiguration10.3.5.1 Transactio…

基于springboot+vue的抗疫物资管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

C 嵌入式系统设计模式 12:去抖动模式

本书的原著为&#xff1a;《Design Patterns for Embedded Systems in C ——An Embedded Software Engineering Toolkit 》&#xff0c;讲解的是嵌入式系统设计模式&#xff0c;是一本不可多得的好书。 本系列描述我对书中内容的理解。本文章描述访问硬件的设计模式之五&…

(undone) 如何计算 Hessian Matrix 海森矩阵 海塞矩阵

参考视频1&#xff1a;https://www.bilibili.com/video/BV1H64y1T7zQ/?spm_id_from333.337.search-card.all.click 参考视频2&#xff08;正定矩阵&#xff09;&#xff1a;https://www.bilibili.com/video/BV1Ag411M76G/?spm_id_from333.337.search-card.all.click&vd_…

【Datawhale组队学习:Sora原理与技术实战】Sora技术原理

Sora能力边界探索 最大支持60秒高清视频生成&#xff0c;以及基于已有短视频的前后扩展&#xff0c;同时保持人物/场景的高度一致性如奶茶般丝滑过渡的视频融合能力同一场景的多角度/镜头的生成能力具有动态摄像机运动的视频。随着摄像机的移动和旋转&#xff0c;人和其 他场景…

SpaceX 首次通过星链 从太空向社交平台 X 上发帖

2 月 26 日&#xff0c;伊隆马斯克旗下太空探索技术公司 SpaceX 宣布&#xff0c;该公司已成功地通过「星链」卫星网络&#xff0c;从太空向社交平台 X 上发布了第一个帖子。 这一次的发布&#xff0c;是通过手机卫星服务——「卫星直连蜂窝网络」&#xff08;Direct to Cell&…

vscode不能远程连接ubuntu18.04.6

目录 问题解决Portable Mode 安装vscode 补充说明学习资料 问题 vscode远程ssh连接ubuntu18.04.6时&#xff0c;出现如下提示框&#xff0c;单击Learn More后&#xff0c;定位到问题。Can I run VS Code Server on older Linux distributions? 原始是&#xff1a;需要glibc …

递归和迭代【Py/Java/C++三种语言详解】LeetCode每日一题240218【树DFS】LeetCode 589、 N 叉树的前序遍历

有LeetCode算法/华为OD考试扣扣交流群可加 948025485 可上全网独家的 欧弟OJ系统 练习华子OD、大厂真题 绿色聊天软件戳 od1336了解算法冲刺训练 文章目录 题目描述解题思路代码方法一&#xff1a;递归法PythonJavaC时空复杂度 方法二&#xff1a;迭代法PythonJavaC时空复杂度 …

北邮毕业论文Latex模板使用教程(Windows)

1latex模板下载 下载地址&#xff1a; https://github.com/rioxwang/BUPTGraduateThesis2安装编译环境 TEX Live 2014 或者CTEX 2.9.2.164&#xff0c;以及更高的版本. 下载其中一个即可 &#xff08;1&#xff09;TEX Live下载地址&#xff1a; https://tug.org/texlive/acq…

JAVA学习笔记12

1.键盘输入语句 1.1 介绍 ​ *在编程中&#xff0c;需要接收用户输入的数据&#xff0c;就可以使用键盘输入语句来获取。 1.2 步骤 ​ 1.导入该类的所在包&#xff0c;java.util.* ​ 2.创建该类对象&#xff08;声明变量&#xff09; ​ 3.调用里面的功能 import java.…