深入探讨分布式ID生成方案

🎈🎈作者主页: 喔的嘛呀🎈🎈
🎈🎈所属专栏:python爬虫学习🎈🎈
✨✨谢谢大家捧场,祝屏幕前的小伙伴们每天都有好运相伴左右,一定要天天开心哦!✨✨ 

目录

引言

一. UUID(Universally Unique Identifier)

二、数据库自增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://www.hqwc.cn/news/573137.html

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

相关文章

OSPF-区域间路由计算

一、概述 前面学习了我们学习了Router-LSA和Network-LSA&#xff0c;它们都只能在区域内进行泛洪&#xff0c;而且我们之前一直主要是单区域学习。OSPF的核心是骨干区域Area 0&#xff0c;其它都为非骨干区域。但是在大型网络中&#xff0c;单区域OSPF会存在一定的问题&#xf…

HCIA-Datacom实验_03_实验一:华为VRP系统基本操作

1.运行eNSP&#xff0c;设置-界面设置-自定义界面-设备标签&#xff0c;“总显示接口标签” 打钩。 2.按照实验拓扑添加设备 注&#xff1a;如果是真实环境&#xff0c;需要接两条线&#xff1a; &#xff08;1&#xff09;串口线&#xff1a;电脑USB口到网络设备Console口&am…

EdgeGallery开发指南

API接口 简介 EdgeGallery支持第三方业务系统通过北向接口网关调用EdgeGallery的业务接口。调用流程如下图所示&#xff08;融合前端edgegallery-fe包含融合前端界面以及北向接口网关功能&#xff0c;通过浏览器访问时打开的是融合前端的界面&#xff0c;通过IP:Port/urlPref…

免费SSL证书和付费SSL证书的区别点

背景&#xff1a; 在了解免费SSL证书和付费SSL证书的区别之前&#xff0c;先带大家了解一下SSL证书的概念和作用。 SSL证书的概念&#xff1a; SSL证书就是基于http超文本传输协议的延伸&#xff0c;在http访问的基础上增加了一个文本传输加密的协议&#xff0c;由于http是明…

第十篇【传奇开心果系列】Python自动化办公库技术点案例示例:深度解读Python自动化操作Excel

传奇开心果博文系列 系列博文目录Python自动化办公库技术点案例示例系列博文目录 前言一、重要作用解说二、Python操作Excel的常用库介绍三、数据处理和分析示例代码四、自动化报表生成示例代码五、数据导入和导出示例代码六、数据可视化示例代码八、数据校验和清洗示例代码九、…

【Java程序设计】【C00386】基于(JavaWeb)Springboot的校运会管理系统(有论文)

基于&#xff08;JavaWeb&#xff09;Springboot的校运会管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;已经做了六年的毕业设计程序开发&#xff0c;开发过上…

【学习心得】Jupyter常用操作与魔法方法

一、安装与打开 Jupyter是什么我就不啰嗦了&#xff0c;直接安装&#xff1a; pip install jupyter 安装完后&#xff0c;在你想要打开的项目路径下&#xff0c;唤出CMD执行下面命令就可以使用jupyter notebook了 jupyter notebook 也可以用更加好用的jupyter lab&#xff0…

LabVIEW无人机大气数据智能测试系统

LabVIEW无人机大气数据智能测试系统 随着无人机技术的迅速发展&#xff0c;大气数据计算机作为重要的机载设备&#xff0c;在确保飞行安全性方面发挥着重要作用。设计了一套基于LabVIEW的无人机大气数据智能测试系统&#xff0c;通过高效、稳定的性能测试&#xff0c;及时发现…

Memcached非关系型数据库介绍

使用背景 Memcached 不是一个数据库&#xff0c;而是一个高性能的分布式内存对象缓存系统。它主要用于减轻数据库负载&#xff0c;提高动态Web应用的速度、可扩展性和性能。Memcached 的工作原理是将数据存储在内存中&#xff0c;以提供快速的数据访问。当应用程序需要访问数据…

【Spring Boot 源码学习】共享 MetadataReaderFactory 上下文初始化器

《Spring Boot 源码学习系列》 共享 MetadataReaderFactory 上下文初始化器 一、引言二、往期内容三、主要内容3.1 源码初识3.2 CachingMetadataReaderFactoryPostProcessor3.2.1 register 方法3.2.1 configureConfigurationClassPostProcessor 方法 3.3 ConfigurationClassPos…

架构师之路--Docker的技术学习路径

Docker 的技术学习路径 一、引言 Docker 是一个开源的应用容器引擎&#xff0c;它可以让开发者将应用程序及其依赖包打包成一个可移植的容器&#xff0c;然后在任何支持 Docker 的操作系统上运行。Docker 具有轻量级、快速部署、可移植性强等优点&#xff0c;因此在现代软件开…

ubuntu22.04系统安装Opencv4.8.0+Opencv-contrib4.8.0

一、安装下载所需工具 1.打开终端&#xff0c;输入以下命令来更新软件源&#xff1a; sudo apt-get update 2.安装wget&#xff1a; sudo apt-get install wget 3.下载opencv和opencv-contrib包&#xff1a; wget -O opencv-4.8.0.zip https://github.com/opencv/opencv/…