【分布式系统】唯一性ID的实现
1、UUID(通用唯一标识符)
1、UUID本身
一种用于标识信息的标准化方法。一个128位的数字,常表示为32个十六进制数字,以连字符分隔成五组:8-4-4-4-12。
版本: UUID有不同的版本,最常见的是基于时间戳和随机数生成的版本1和版本4。
唯一性: 由于UUID的长度和生成机制,可以保证在大多数情况下生成的UUID是唯一的。
应用: 在各种系统中广泛应用,用于唯一标识实体、会话、交易等。
2、设计方法:
时间戳: 将当前时间戳作为UUID的一部分,以确保在同一时刻生成的UUID是唯一的。
节点标识: 在分布式系统中,将每个节点的唯一标识符(如机器ID)纳入UUID的生成过程,以防止在不同节点上生成相同的UUID。
随机数生成器: 将随机数作为UUID的一部分,以增加唯一性,但在分布式系统中要确保随机数生成器是足够随机的。
考虑时钟回拨问题: 如果使用时间戳作为UUID的一部分,需要考虑时钟回拨可能导致的重复UUID问题。可以采用一些机制来解决时钟回拨带来的潜在问题,比如使用递增序列号。
一致性哈希算法: 基于节点信息和数据内容计算哈希值,然后将哈希值转换为UUID。这样可以确保相同的数据在不同节点上生成的UUID是一致的。
时钟回拨问题:
指在分布式系统中,当某个节点的系统时间发生回拨(即向过去跳跃)时可能导致的一系列问题。
引起的原因:手动调整时间;网络时间协议(NTP)校准;系统重启或故障;虚拟机迁移;
解决方向:使用逻辑时钟;增加容错机制;使用稳定的时钟;时间校正算法;设计时避免依赖绝对时间;
package mainimport ("fmt""github.com/google/uuid"
)func main() {// 生成一个新的 UUIDnewUUID := uuid.New()fmt.Printf("Generated UUID: %s\n", newUUID)
}
2、数据库序列(自增ID)
简单,工作方式:基于中央数据库的序列生成器,如自增ID,每次请求时递增序列值。顺序性:保证了生成ID的顺序性和唯一性。
package mainimport ("database/sql""fmt"_ "github.com/mattn/go-sqlite3"
)func main() {// 连接到 SQLite 数据库db, err := sql.Open("sqlite3", "test.db")if err != nil {fmt.Println(err)return}defer db.Close()// 创建一个包含自增ID的表_, err = db.Exec("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)")if err != nil {fmt.Println(err)return}fmt.Println("Table created successfully")
}
//连接到 SQLite 数据库,并创建了一个名为 users 的表,该表包含一个自增的整数类型的ID列和一个文本类型的 name 列。
//不同的数据库(如 MySQL、PostgreSQL 等)可能有不同的语法和方式来实现自动递增的ID列
3、雪花算法(Twitter Snowflake)
Twitter开发的一种生成64位ID的服务,基于时间戳、机器ID和序列号。
时间戳(41位): 用于表示ID生成的时间戳,通常精确到毫秒级。
机器ID(10位): 标识生成ID的机器的唯一标识,通常使用数据中心ID与机器ID的组合。
序列号(12位): 在同一毫秒内,通过累加的方式生成序列号,确保在同一节点上生成的ID是唯一的。
雪花算法的优点包括高性能、高可用性和ID趋势递增。在实际应用中,可根据需求调整时间戳的位数、机器ID的位数和序列号的位数来适应不同的场景。
一般用于替代传统自增ID的方式。
package mainimport ("fmt""sync""time"
)const (epoch time.Duration = 1609459200000 // 2021-01-01 的时间戳,用于生成时间戳部分workerIDBits = 5 // 机器 ID 的位数sequenceBits = 12 // 序列号的位数maxWorkerID = -1 ^ (-1 << workerIDBits)maxSequence = -1 ^ (-1 << sequenceBits)
)type Snowflake struct {mu sync.MutexlastTime int64workerID uintsequence uint
}func NewSnowflake(workerID uint) *Snowflake {if workerID > maxWorkerID {panic("worker ID 超出范围")}return &Snowflake{lastTime: 0,workerID: workerID,sequence: 0,}
}func (s *Snowflake) GenerateID() uint64 {s.mu.Lock()defer s.mu.Unlock()currentTime := time.Now().UnixNano() / 1e6 // 获取当前时间的毫秒数if s.lastTime == currentTime {s.sequence = (s.sequence + 1) & maxSequenceif s.sequence == 0 {for currentTime <= s.lastTime {currentTime = time.Now().UnixNano() / 1e6}}} else {s.sequence = 0}s.lastTime = currentTimeid := uint64((currentTime-epoch)<<22 | int64(s.workerID)<<17 | int64(s.sequence))return id
}func main() {sf := NewSnowflake(1) // 设定一个机器 IDid := sf.GenerateID()fmt.Println(id)
}
4、使用Redis实现分布式ID生成
Redis是一个高性能的键值数据库,它可以用于生成分布式唯一标识符。
不同Redis实例通过配置不同的起始步长来区分。
这个的实现原理利用了Redis的原子操作。
package mainimport ("fmt""github.com/go-redis/redis/v8""log""time"
)var redisClient *redis.Clientfunc init() {redisClient = redis.NewClient(&redis.Options{Addr: "localhost:6379", // Redis 服务器地址Password: "", // Redis 密码,如果有的话DB: 0, // 选择使用的数据库})
}func generateID(key string) (int64, error) {val, err := redisClient.Incr(key).Result()if err != nil {return 0, err}return val, nil
}func main() {key := "distributed_id_generator" // Redis 中的键名// 生成 5 个分布式 IDfor i := 0; i < 5; i++ {id, err := generateID(key)if err != nil {log.Fatalf("Failed to generate ID: %v", err)}fmt.Printf("Generated ID: %d\n", id)time.Sleep(time.Millisecond) // 可选的延迟,以避免生成相同的 ID}
}
package mainimport ("fmt""github.com/go-redis/redis/v8""log""time"
)var redisClients map[string]*redis.Clientfunc init() {redisClients = make(map[string]*redis.Client)redisClients["instance1"] = redis.NewClient(&redis.Options{Addr: "localhost:6379", // Redis 实例1的地址Password: "", // Redis 密码,如果有的话DB: 0, // 选择使用的数据库})redisClients["instance2"] = redis.NewClient(&redis.Options{Addr: "localhost:6380", // Redis 实例2的地址Password: "", // Redis 密码,如果有的话DB: 0, // 选择使用的数据库})
}func generateID(key string, start int64) (int64, error) {val, err := redisClients[key].IncrBy(key, start).Result()if err != nil {return 0, err}return val, nil
}func main() {key1 := "distributed_id_generator_instance1" // Redis 实例1中的键名key2 := "distributed_id_generator_instance2" // Redis 实例2中的键名// 生成 5 个分布式 IDfor i := 0; i < 5; i++ {id1, err := generateID(key1, 1000) // 指定实例1的起始步长为1000if err != nil {log.Fatalf("Failed to generate ID: %v", err)}fmt.Printf("Instance 1 - Generated ID: %d\n", id1)id2, err := generateID(key2, 2000) // 指定实例2的起始步长为2000if err != nil {log.Fatalf("Failed to generate ID: %v", err)}fmt.Printf("Instance 2 - Generated ID: %d\n", id2)time.Sleep(time.Millisecond) // 可选的延迟,以避免生成相同的 ID}
}
5、使用数据库分段(Database Segment)
6、分布式键生成服务(如Zookeeper、etcd)
分布式协调服务在集群中生成唯一ID。
也是利用这些服务提供的分布式锁和原子性操作来生成唯一的ID。还有集群协调机制。
相关文章:
【分布式系统】唯一性ID的实现
1、UUID(通用唯一标识符) 1、UUID本身 一种用于标识信息的标准化方法。一个128位的数字,常表示为32个十六进制数字,以连字符分隔成五组:8-4-4-4-12。 版本: UUID有不同的版本,最常见的是基于时…...
哪里能找到好用的动物视频素材 优质网站推荐
想让你的短视频增添些活泼生动的动物元素?无论是搞笑的宠物瞬间,还是野外猛兽的雄姿,这些素材都能让视频更具吸引力。今天就为大家推荐几个超实用的动物视频素材网站,不论你是短视频新手还是老手,都能在这些网站找到心…...
SRAM芯片数据采集解决方案
SRAM芯片数据采集解决方案致力于提供一种高效、稳定且易于操作的方法,以确保从静态随机存取存储器SRAM芯片中准确无误地获取数据。 这种解决方案通常包括硬件接口和软件工具,它们协同工作,以实现对SRAM芯片的无缝访问和数据传输。 在硬件方…...
【贪心算法第七弹——674.最长连续递增序列(easy)】
目录 1.题目解析 题目来源 测试用例 2.算法原理 3.实战代码 代码分析 1.题目解析 题目来源 674.最长递增子序列——力扣 测试用例 2.算法原理 贪心思路 3.实战代码 class Solution { public:int findLengthOfLCIS(vector<int>& nums) {int n nums.size();in…...
[AI] 知之AI推出3D智能宠物:助力语言学习与口语提升的新选择
Hello! 知之AI官网 [AI] 知之AI推出3D智能宠物:助力语言学习与口语提升的新选择 随着人工智能技术的飞速发展,虚拟助手和智能设备不断进入我们的生活。近日,知之AI重磅推出了一款创新产品——3D智能宠物。这一产品不仅具备多国语言交流能力&…...
Android 14之HIDL转AIDL通信
Android 14之HIDL转AIDL通信 1、interface接口1.1 接口变更1.2 生成hidl2aidl工具1.3 执行hidl2aidl指令1.4 修改aidl的Android.bp文件1.5 创建路径1.6 拷贝生成的aidl到1和current1.7 更新与冻结版本1.8 编译模块接口 2、服务端代码适配hal代码修改2.1 修改Android.bp的hidl依…...
【R库包安装】R库包安装总结:conda、CRAN等
【R库包安装】R studio 安装rgdal库/BPST库 R studio 安装rgdal库解决方法 R studio 安装BPST库(github)解决方法方法1:使用devtools安装方法2:下载安装包直接在Rstudio中安装 参考 基础 R 库包的安装可参见另一博客-【R库包安装】…...
学习PMC要不要去培训班?
在当今快速变化的商业环境中,PMC作为供应链管理的核心环节之一,其重要性日益凸显。PMC不仅关乎产品的物料计划、采购、库存控制及物流协调,还直接影响到企业的生产效率、成本控制以及市场竞争力。面对这一专业领域的学习需求,许多…...
前端 用js封装部分数据结构
文章目录 Stack队列链表Setset 用来数组去重set用来取两个数组的并集set用来取两个数组的交集set用来取两个数组的差集 字典 Stack 栈,先进后出,后进先出。用数组来进行模拟,通过push存入,通过pop取出。 class Stack {// 带#表示…...
cocoscreator-doc-TS:目录
cocoscreator-doc-TS-脚本开发-访问节点和组件-CSDN博客 cocoscreator-doc-TS-常用节点和组件接口-CSDN博客 cocoscreator-doc-TS-脚本开发-创建和销毁节点-CSDN博客 cocoscreator-doc-TS-脚本开发-加载和切换场景-CSDN博客 cocoscreator-doc-TS-脚本开发-获取和设置资源-CS…...
理解Java集合的基本用法—Collection:List、Set 和 Queue,Map
本博文部分参考 博客 ,强烈推荐这篇博客,写得超级全面!!! 图片来源 Java 集合框架 主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合(单列…...
IOC容器实现分层解耦
文章开始之前,先引入软件开发的两个名词:耦合和内聚。耦合是指:衡量软件中各个层(三层架构)/各个模块的依赖关联程度;内聚是指:软件中各个功能模块内部的功能联系。三层架构中Controller、Servi…...
Flutter 共性元素动画
在 Flutter 中,共性元素动画(Shared Element Transitions)用于在页面导航或组件切换时创建视觉上更流畅和连贯的动画效果。这种动画可以使用户感受到两个界面之间的“物理联系”,比如图片从缩略图到全屏的扩大效果。 前置知识点整…...
K8s内存溢出问题剖析:排查与解决方案
文章目录 一、背景二、排查方案:1. 可能是数据量超出了限制的大小,检查数据目录大小2. 查看是否是内存溢出2.1 排查数据量(查看数据目录大小是否超过limit限制)2.2 查看pod详情发现问题 三、解决过程 一、背景 做redis压测过程中…...
乌班图单机(不访问外网)部署docker和服务的方法
面向对象:Ubuntu不能访问外网的机子,部署mysql、redis、jdk8、minio 过程: 1、安装docker(照着图去这里找对应的下载下来https://download.docker.com/linux/static/stable/),将7个docker官网下载的文件下载下来后,传上去服务器随便一个文件夹或者常用的opt或者/usr/lo…...
使用 pycharm 新建使用 conda 虚拟 python 环境的工程
1. conda 常见命令复习: conda env list // 查看 conda 环境列表 conda activate xxxenv // 进入指定 conda 环境2. 环境展示: 2.1. 我的物理环境的 Python 版本为 3.10.9: 2.2. 我的 conda 虚拟环境 env_yolov9_python_3_8 中的 pyth…...
Docker的save和export命令的区别,load和import的区别 笔记241124
Docker的save和export命令的区别,load和import的区别 解说1: Docker的save和export命令,以及load和import命令,在功能和使用场景上存在显著的区别。以下是对这两组命令的详细对比和解释: Docker save和export命令的区别 使用方式和目的&am…...
通俗理解人工智能、机器学习和深度学习的关系
最近几年人工智能成为极其热门的概念和话题,可以说彻底出圈了。但人工智能的概念在1955年就提出来了,可以说非常古老。我在上小学的时候《科学》课本上就有人工智能的概念介绍,至今还有印象,但那些年AI正处于“寒冬”,…...
使用 pycharm 新建不使用 python 虚拟环境( venv、conda )的工程
有时候我们发现一个好玩的 demo,想赶快在电脑上 pip install 一下跑起来,发现因为 python 的 venv、conda 环境还挺费劲的,因为随着时间的发展,之前记得很清楚的 venv、conda 的用法,不经常使用,半天跑不起…...
【大数据学习 | Spark-SQL】SparkSQL读写数据
我们使用sparksql进行编程,编程的过程我们需要创建dataframe对象,这个对象的创建方式我们是先创建RDD然后再转换rdd变成为DataFrame对象。 但是sparksql给大家提供了多种便捷读取数据的方式。 //原始读取数据方式 sc.textFile().toRDD sqlSc.createDat…...
STM32F4-正点原子探索者-SYSTEM文件夹下delay.c延时函数优化技巧与实践
1. 深入理解STM32F4的延时函数机制 在正点原子探索者开发板的SYSTEM文件夹中,delay.c文件承担着精确延时的重要任务。这个文件看似简单,但里面藏着不少值得深挖的技术细节。我第一次接触这个文件时,就被它的精妙设计所吸引。 delay.c的核心是…...
ROS2——RQT:模块化调试利器(十九)
1. RQT:ROS2开发者的调试瑞士军刀 第一次接触ROS2的时候,我被它复杂的调试过程搞得焦头烂额。直到发现了RQT这个神器,才真正体会到什么叫"模块化调试"的快感。简单来说,RQT就像乐高积木,你可以根据需要自由组…...
挑中年大叔头像AI头像时,看着精致不代表后面能细修
在实际设计任务中,千图网的AI生成头像功能已成为许多门店和内容团队的首选工具。日前接到需求,需要为社群活动物料快速输出一批中年大叔形象的社交头像,要求风格沉稳、辨识度高,并能方便后续调整细节。首轮构思时决定,…...
从二维地图到UE5数字孪生:GIS的‘升维’之路与未来应用场景漫谈
从二维地图到UE5数字孪生:GIS的‘升维’之路与未来应用场景漫谈 当我们打开手机导航,二维地图已经像空气一样自然地融入日常生活。但很少有人意识到,这些看似简单的线条背后,正经历着一场从平面到立体、从静态到动态、从观察到交互…...
嵌入式调光控制库:轻量级软启/渐变/记忆逻辑实现
1. 项目概述DimmerControl 是一个面向嵌入式平台的轻量级调光控制库,专为可控硅(TRIAC)或 MOSFET/IGBT 驱动的交流/直流调光系统设计。其核心目标并非实现完整驱动硬件,而是提供一套可复用、可配置、具备工程鲁棒性的调光行为逻辑…...
【多微电网】计及碳排放的基于交替方向乘子法(ADMM)的多微网电能交互分布式运行策略研究附Matlab代码
✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。 🍎 往期回顾关注个人主页:Matlab科研工作室 👇 关注我领取海量matlab电子…...
Vivado+VCS+Verdi三件套实战:如何快速搭建高效仿真环境(附详细配置步骤)
VivadoVCSVerdi三件套实战:如何快速搭建高效仿真环境 在FPGA开发流程中,功能仿真是验证设计正确性的关键环节。传统单一工具链往往面临仿真速度慢、波形分析效率低等痛点。本文将分享如何通过Vivado、VCS和Verdi三款工具的协同使用,构建一个高…...
LaTeX超链接颜色自定义全攻略:从基础配置到elsarticle文档类冲突解决
LaTeX超链接颜色自定义全攻略:从基础配置到elsarticle文档类冲突解决 在学术论文和技术报告的排版过程中,超链接颜色的精细控制往往被忽视,却直接影响文档的专业性和可读性。当引用文献、图表或外部资源时,默认的蓝色链接可能不符…...
PyTorch模型训练必备技巧:detach().clone()和clone().detach()到底该用哪个?
PyTorch模型训练必备技巧:detach().clone()和clone().detach()到底该用哪个? 在PyTorch模型训练过程中,我们经常需要复制或截断计算图来优化内存使用或控制梯度传播。detach().clone()和clone().detach()这两种组合操作看似相似,但…...
全任务零样本学习-mT5分类增强版-中文-base实战教程:WebUI一键文本增强部署
全任务零样本学习-mT5分类增强版-中文-base实战教程:WebUI一键文本增强部署 你是不是经常遇到这样的烦恼?手头有一堆文本数据,想用来训练模型,但数量太少,效果总是不理想。或者,写好的文案想换个说法&…...
