当前位置: 首页 > news >正文

分布式ID生成方案总结

什么是分布式 ID

分布式 ID 是指,在分布式环境下可用于对数据进行标识且易存储的全局唯一的 ID 标识。

为什么需要分布式 ID

对于单体系统来说,主键ID可能会常用主键自动的方式进行设置,这种ID生成方法在单体项目是可行的。

对于分布式系统,分库分表之后,就不适应了,比如订单表数据量太大了,分成了多个库,如果还采用数据库主键自增的方式,就会出现在不同库或表中id一致的情况。

分布式 ID 需要满足的条件

分布式 ID 是我们在非常多的场景下用到的组件,对其要求比较高,其一般需要满足以下条件:

  • 全局唯一性:ID是作为唯一的标识,不能出现重复
  • 高性能:高可用低延时,ID 生成速度要快,否则反倒会成为业务瓶颈
  • 高可用:尽量保证服务的可用性,多实例化,避免因一个实例挂掉影响整个业务应用的运行
  • 容易接入:要秉着拿来即用的设计原则,在系统设计和实现上要尽可能的简单,避免增加开发人员的使用成本
  • 趋势递增:互联网比较喜欢MySQL数据库,而MySQL数据库默认使用InnoDB存储引擎,其使用的是聚集索引,使用有序的主键ID有利于保证写入的效率
  • 单调递增:保证下一个ID大于上一个ID,这种情况可以保证事务版本号,排序等特殊需求实现
  • 信息安全:前面说了ID要递增,但是最好不要连续,如果ID是连续的,容易被恶意爬取数据,指定一系列连续的,所以ID递增但是不规则是最好的


常用分布式 ID 生成方案

下面列出的这几种方案都是生成 ID 的常用方法:

  • 使用 UUID 生成 ID
  • 使用数据库自增生成 ID
  • 使用数据库号段模式生成 ID
  • 使用 Redis 实现生成 ID
  • 使用 Zookeeper 生成 ID
  • 根据雪花算法(Snowflake)算法生成 ID
  • 百度Uidgenerator
  • 美团Leaf
  • 滴滴TinyID


使用 UUID 生成 ID

UUID 是通用唯一识别码的缩写(Universally Unique Identifier)。UUID 一般是由一组 32 位数的 16 进制数字所构成,以连字号分为五段,形式为8-4-4-4-12的36个字符,常包含时间戳和 MAC 地址信息这些元素,标准的 UUID 格式为:

xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

优点

  • 高性能
  • 实现简单
  • 不需要第数据库等第三方组件依赖

缺点

  • 并不是趋势递增,不方便排序
  • 生成的 ID 只能用字符串类型存储,占用空间大
  • 生成的串没有规律,出问题时不易根据 ID 进行排查

使用数据库自增生成 ID

在分布式系统中我们可以多部署几台机器,每台机器设置不同的初始值,且步长和机器数相等。比如有两台机器:设置步长step为2,Server1的初始值为1(1,3,5,7,9,11…)、Server2的初始值为2(2,4,6,8,10…)。

这种方案看起来是可行的,但是如果要扩容,步长step等要重新设置,假如只有一台机器,步长就是1,比如1,2,3,4,5,6,这时候如果要进行扩容,就要重新设置,机器2可以挑一个偶数的数字,这个数字在扩容时间内,数据库自增要达不到这个数的,然后步长就是2,机器1要重新设置step为2,然后还是以一个奇数开始进行自增。这个过程看起来不是很杂,但是,如果机器很多的话,那就要花很多时间去维护重新设置。

优点

  • 实现简单
  • 趋势递增

缺点

  • ID没有了单调递增的特性,只能趋势递增,有些业务场景可能不符合
  • 数据库压力还是比较大,每次获取ID都需要读取数据库,只能通过多台机器提高稳定性和性能
  • 水平扩展比较麻烦,需要手动调整集群数据库中的初始值与步长

使用数据库号段模式生成 ID

这种模式也是现在生成分布式ID的一种方法,在使用号码模式时,我们通常会先建立一张表用于记录上述的 ID 号段范围,一般表内容如下:

CREATE TABLE id_generator (id int(10) NOT NULL AUTO_INCREMENT,max_id bigint(20) NOT NULL COMMENT '当前最大id',step int(20) NOT NULL COMMENT '号段的布长',biz_type    int(20) NOT NULL COMMENT '业务类型',version int(20) NOT NULL COMMENT '版本号',PRIMARY KEY (`id`)
) 

每次从数据库中获取号段 ID 的范围时,都会执行更新语句,其中计算新号段范围最大值 max_id 的公式是 max_id + step 组成,所以 SQL 中设置 max_id = max_id+step 来执行更新语句,更新数据库中这个范围最大值 max_id,然后再通过查询语句查询更新后 ID 最大值,再根据最大值 max_id 与步长 step 计算出待生成的 ID 的范围,其中操作的 SQL 如下:

update id_generator set max_id = #{max_id+step}, version = version + 1 where version = # {version} and biz_type = #{biz_type};SELECT `max_id`, `step`, `version` FROM `myid` WHERE `biz_type` = #{biz_type};

优点

  • 使用缓存机制,容灾性高,即使数据库不可用还能撑一段时间。
  • 可以自定义每次扩展的大小,控制 ID 生成速度;
  • 可以设置生成 ID 的初始范围,方便业务从原有的 ID 方式上迁移过来。
  • 有比较成熟的方案,像百度Uidgenerator,美团Leaf

缺点

  • 依赖于数据库实现,数据库宕机会造成整个系统不可用。
  • ID 号码不够随机,可能够泄露发号数量的信息,不太安全。
     

使用 Redis 实现生成 ID

Redis分布式ID实现主要是通过提供像 INCR 和 INCRBY 这样的自增原子命令,由于Redis单线程的特点,可以保证ID的唯一性和有序性。

优点

  • 实现简单;
  • 有序递增,方便排序;

缺点

  • 强依赖于 Redis,可能存在单点问题;
  • 如果 Redis 超时,可能会对业务造成影响;
  • 占用宽带,而且需要考虑网络延时等问题带来地性能冲击。

使用 Zookeeper 生成 ID

在 Zookeeper 中主要通过节点数据版本号来生成序列号,可以生成 32 位和 64 位的数据版本号,客户端可以使用这个版本号来作为唯一的序列号。在 Zookeeper 中本身就是支持集群模式,所以能保证高可用性,且生成的 ID 为趋势递增且有序,不过在实际使用中很少用 Zookeeper 来充当 ID 生成器,因为 Zookeeper 中存在强一致性,在高并发场景下其性能可能很难满足需求。

不过由于使用 Zookeeper 节点的版本号来充当 ID 号是比较繁琐,需要创建节点获取生成的 ID,然后去掉节点命令前缀,只截取数字部分,最后还要异步执行删除节点(启动新的线程执行删除节点操作,防止占用生成ID线程执行的实际)。过程比较耗时且繁琐,所以,在操作 Zookeeper 时经经常不会采用该方案,常使用 Curator 客户端提供的基于乐观锁的计数器来自增实现 ID 生成,这个过程和数据库自增生成 ID 类似。

优点

  • 高可用
  • 趋势递增

缺点

  • 性能差
  • 定期删除之前生成的节点,比较繁琐

根据雪花算法(Snowflake)算法生成 ID

Snowflake,雪花算法是由 Twitter 开源的分布式ID生成算法,以划分命名空间的方式将
64-bit位分割成多个部分,每个部分代表不同的含义,64位,在java中Long类型是64位的,所以java程序中一般使用Long类型存储
 

其结构组成:

  • 第一部分:第一位占用1bit,始终是0,是一个符号位,不使用
  • 第二部分:第2位开始的41位是时间戳。41-bit位可表示241个数,每个数代表毫秒,那么雪花算法可用的时间年限是(241)/(1000606024365)=69 年的时间
  • 第三部分:10-bit位可表示机器数,即2^10 = 1024台机器。通常不会部署这么多台机器
  • 第四部分:12-bit位是自增序列,可表示2^12 = 4096个数。觉得一毫秒个数不够用也可以调大点

优点:

  • 高性能
  • 趋势递增
  • 可以灵活调整结构
  • 不需要第数据库等第三方组件依赖

缺点:

  • 强依赖时钟,可能发生时钟回拨导致生成的 ID 重复

百度 Uidgenerator

百度的 UidGenerator 是百度开源基于Java语言实现的唯一ID生成器,是在雪花算法 snowflake 的基础上做了一些改进。

详细介绍请看官网。

美团 Leaf

Leaf 提供两种生成的ID的方式:号段模式(Leaf-segment)和 snowflake 模式(Leaf-snowflake)。你可以同时开启两种方式,也可以指定开启某种方式,默认两种方式为关闭状态。

详细介绍请看官网。

滴滴 TinyID

Tinyid 是用Java开发的一款分布式id生成系统,基于数据库号段算法实现。Tinyid 扩展了 leaf-segment 算法,支持了多数据库和 tinyid-client。

详细介绍请看官网。

参考

SmileNicky的博客

myf008的博客

相关文章:

分布式ID生成方案总结

什么是分布式 ID 分布式 ID 是指,在分布式环境下可用于对数据进行标识且易存储的全局唯一的 ID 标识。 为什么需要分布式 ID 对于单体系统来说,主键ID可能会常用主键自动的方式进行设置,这种ID生成方法在单体项目是可行的。 对于分布式系统…...

极智AI | 百度推出文心一言,对标ChatGPT功力几成

欢迎关注我,获取我的更多经验分享,极智传送《极智AI | 百度推出文心一言,对标 ChatGPT 功力几成》 大家好,我是极智视界,本文介绍一下 百度今日推出文心一言,对标ChatGPT功力几成。 邀您加入我的知识星球「极智视界」,星球内有超多好玩的项目实战源码下载,链接:https…...

CleanMyMac X最新版本4.12.6

系统要求macOS 10.12及更高,M1机型及最新macOS 13 CleanMyMac可以为Mac腾出空间,软件已经更新到CleanMyMac X支持最新版Mac系统。CleanMyMac具有一系列巧妙的新功能,可让您安全,智能地扫描和清理整个系统,删除大量未使…...

替代notepad++,notepad--介绍及插件cmake编译

Notepad 是一个文本编辑器小软件,用来替代windows自带的记事本。然而Notepad软件的作者是台湾省人,其具有明显的gd/jd/td倾向,如果你不赞同他的观点,Notepad将会在你的源码里面插入随机字符。推荐一款国产的开源跨平台软件NDD(not…...

机器学习笔记之集成学习(四)Gradient Boosting

机器学习笔记之集成学习——Gradient Boosting引言回顾:Boosting\text{Boosting}Boosting算法思想与AdaBoost\text{AdaBoost}AdaBoostGradient Boosting\text{Gradient Boosting}Gradient Boosting算法介绍场景构建算法过程迭代过程与梯度下降法之间的关联关系引言 …...

WPA渗透-pyrit:batch-table加速attack_db模块加速_“attack_db”模块加速

WPA渗透-pyrit:batch-table加速attack_db模块加速_“attack_db”模块加速 1.渗透WIFI 1.导入密码字典 pyrit -i 字典文件 import_passwords -i:输入的文件名 import_passwords:从类文件源导入密码。pyrit -i pwd.txt import_passwords2.导…...

kotlin第二部分复习纪要

扩展函数。 例如: fun Context.toast(msg: String, length: Int Toast.LENGTH_SHORT){Toast.makeText(this, msg, length).show() } 使用 val activity: Context? getActivity() activity?.toast("Hello world!") activity?.toast("Hello worl…...

代码随想录--链表--删除链表第n个节点题型、链表相交题型

删除链表第n个节点题型 链表遍历学清楚! | LeetCode:19.删除链表倒数第N个节点 (opens new window) 这道题我一开始想的是,倒数第n个节点,链表不方便往前找,那就从链表头结点开始找链表长度减n,这时候就是…...

一起来学5G终端射频标准(In-band emissions-2)

上一篇我们列出了IBE的测试要求表格,今天我们详细说一下IBE如何测量计算,以及CA/NR-DC/SUL/UL-MIMO/V2X/Tx Diversity模式下的IBE情况。01—IBE如何测量和计算IBE的测试是对落入到未被分配的RB的干扰的测量,为12个子载波的平均发射功率&#…...

硬刚ChatGPT,中国版ChatGPT“狂飙”的机会在哪儿?

整体来讲,个人的态度是积极的。 ChatGPT、文心一言 都是在多重因素及大量 AI 模型/数据 长时间累积的成果,不是一蹴而就,立竿见影的功能产品。两者产生的基础和背景均不相同,各有优劣,不存在强行对比的概念。 以下是 …...

ReactNative——导航器createBottomTabNavigator(底部标签导航器篇)

上一篇有讲到堆栈式导航器的写法,点这里->堆栈式导航器标签导航器官网链接先安装依赖包yarn add react-navigation/bottom-tabs接着在src/navigator文件夹下新建BottomTabs.tsx文件,写法跟堆栈式导航器类似的~import React from react; import { NavigationConta…...

【数据结构】带头双向循环链表的实现

🌇个人主页:平凡的小苏 📚学习格言:别人可以拷贝我的模式,但不能拷贝我不断往前的激情 🛸C语言专栏:https://blog.csdn.net/vhhhbb/category_12174730.html 🚀数据结构专栏&#xff…...

软件开发的权限系统功能模块设计,分享主流的九种常见权限模型

软件系统的权限控制几乎是非常常见且必备的,这篇文章整理下常见的九种模型,几乎基本够你用了,主流的权限模型主要有以下9种: 1、ACL模型 访问控制列表 2、DAC模型 自主访问控制 3、MAC模型 强制访问控制 4、ABAC模型 基于属性的访…...

CSS3-数据可视化

2D动画 - transform CSS3 transform属性允许你旋转,缩放,倾斜或平移给定元素。 Transform是形变的意思(通常也叫变换),transformer就是变形金刚 常见的函数transform function有: 平移:transl…...

硬件系统工程师宝典(15)-----PCB上的EMC设计,“拿捏了”

各位同学大家好,欢迎继续做客电子工程学习圈,今天我们继续来讲这本书,硬件系统工程师宝典。上篇我们说到PCB常用的多层板叠层结构,综合成本、性能、需求考虑选择不同的叠层结构。今天我们来看看为提高EMC性能,在PCB设计…...

vue3滚动条滚动后元素固定

代码地址&#xff1a;https://gitee.com/zzhua195/easyblog-web-vuee Framework.vue 在这个布局组件中&#xff0c;监听main的滚动事件&#xff0c;获取滚动的距离&#xff0c;将它存入store&#xff0c;以便其它组件能够共享&#xff0c;监听到 <template><div c…...

新吲哚菁绿染料IR-825 NHS,IR825 NHS ester,IR825 SE,IR-825 活性酯,用于科研实验研究和临床

IR825 NHS理论分析&#xff1a;中文名&#xff1a;新吲哚菁绿-琥珀酰亚胺酯&#xff0c;IR-825 琥珀酰亚胺酯&#xff0c;IR-825 活性酯英文名&#xff1a;IR825 NHS&#xff0c;IR-825 NHS&#xff0c;IR825 NHS ester&#xff0c;IR825 SECAS号&#xff1a;N/AIR825 NHS产品详…...

GO语言--接口(interface)的定义及使用

接口定义 接口也是一种数据类型&#xff0c;它代表一组方法的集合。 接口是非侵入式的。即接口设计者无需知道接口被哪些类型实现&#xff0c;而接口使用者只需知道实现怎样的接口&#xff0c;并且无须指明实现哪一个接口。编译器在编译时就会知道哪个类型实现哪个接口&#…...

【Python语言基础】——Python MongoDB 查询

Python语言基础——Python MongoDB 查询 文章目录 Python语言基础——Python MongoDB 查询一、Python MongoDB 查询一、Python MongoDB 查询 筛选结果 在集合中查找文档时,您能够使用 query 对象过滤结果。 find() 方法的第一个参数是 query 对象,用于限定搜索。 实例 查找地…...

第十四届蓝桥杯模拟赛【第三期】Python

1 进制转换 问题描述   请找到一个大于 2022 的最小数&#xff0c;这个数转换成十六进制之后&#xff0c;所有的数位&#xff08;不含前导 0&#xff09;都为字母&#xff08;A 到 F&#xff09;。   请将这个数的十进制形式作为答案提交。 答案&#xff1a;2730 def ch…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

flow_controllers

关键点&#xff1a; 流控制器类型&#xff1a; 同步&#xff08;Sync&#xff09;&#xff1a;发布操作会阻塞&#xff0c;直到数据被确认发送。异步&#xff08;Async&#xff09;&#xff1a;发布操作非阻塞&#xff0c;数据发送由后台线程处理。纯同步&#xff08;PureSync…...

UE5 音效系统

一.音效管理 音乐一般都是WAV,创建一个背景音乐类SoudClass,一个音效类SoundClass。所有的音乐都分为这两个类。再创建一个总音乐类&#xff0c;将上述两个作为它的子类。 接着我们创建一个音乐混合类SoundMix&#xff0c;将上述三个类翻入其中&#xff0c;通过它管理每个音乐…...

李沐--动手学深度学习--GRU

1.GRU从零开始实现 #9.1.2GRU从零开始实现 import torch from torch import nn from d2l import torch as d2l#首先读取 8.5节中使用的时间机器数据集 batch_size,num_steps 32,35 train_iter,vocab d2l.load_data_time_machine(batch_size,num_steps) #初始化模型参数 def …...

虚幻基础:角色旋转

能帮到你的话&#xff0c;就给个赞吧 &#x1f618; 文章目录 移动组件使用控制器所需旋转&#xff1a;组件 使用 控制器旋转将旋转朝向运动&#xff1a;组件 使用 移动方向旋转 控制器旋转和移动旋转 缺点移动旋转&#xff1a;必须移动才能旋转&#xff0c;不移动不旋转控制器…...