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

分布式ID的实现方案

1. 什么是分布式ID

​ 对于低访问量的系统来说,无需对数据库进行分库分表,单库单表完全可以应对,但是随着系统访问量的上升,单表单库的访问压力逐渐增大,这时候就需要采用分库分表的方案,来缓解压力。

​ 在实际的业务场景中,我们常常需要一个唯一ID来确保数据的唯一性,对于单表单库来说,我们通常采用自增ID来作为标识,但是分库分表之后,自增ID的唯一性就无法保证。

分布式ID的实现方案-01

​ 如上图所示,同一业务下的3张数据表,可能存在相同的ID,导致无法根据ID来确保数据的唯一性,因此,在分库分表的架构中,我们就需要使用分布式ID,来确保同一业务下的多张数据表或者多张数据库,数据的唯一性。

2. 分布式ID的实现方案

1. 基于UUID生成

​ UUID是一组由32位的16进制数据所构成,所以可以生成16^32个数据,也就是说,平均每纳秒可以生成1兆组数据,约100亿年才可以使用完。

​ UUID的格式为8-4-4-4-12,如:62f51e7e-a3ca-45ab-bf3f-2c3279f2991e,在JDK中,可以通过如下方式生成一组UUID:

    public static void main(String[] args) {UUID uuid = UUID.randomUUID();System.out.println("UUID:" + uuid);}

UUID:e27cc5fa-8655-4095-b682-e12d178791dd

​ 虽然UUID的实现方案简单便捷,但是由于其长度较长,在数据库中存储会占用过多资源,并且如果作为主键,由于UUID的无序性,会导致其存储的数据位置频繁变动,对性能影响较大。

2. 基于数据库生成
1. 基于特定起始值和步长分配ID

​ 例如现在分了3张表,分别是table_1、table_2、table_3,那么可以给table_1分配自增ID的起始值是1;为table_2分配自增ID的起始值是2,为table_3分配自增ID的起始值是3,步长均为3,这样同一业务下的这3张表,也可以确保其ID的唯一性。

以MySQL为例,可以在MySQL的配置文件中,设置自增ID起始值和步长

自增ID起始值:auto_increment_increment = value

自增ID步长:auto_increment_offset = value

​ 以上方式,虽然可以实现全局唯一ID的生成,但是该方案高度依赖数据库,一旦数据库发生异常,便直接影响业务,并且在主库发生异常,主从切换不一致时,可能会出现ID重复的异常。

2. 基于特定数据表分配ID

​ 可以新建一张数据表,专门存放当前最新的ID,每次需要获取ID值时,都将该数据表中的ID自增一次,并返回最新的ID值。

副本-分布式ID的实现方案-03

​ 以上方式,同样可以生成全局唯一ID,但是也同样高度依赖数据库,在进行实际的业务场景中,增加了一次与业务无关的读写操作,在高并发场景下,ID数据表的压力很大,对系统的QPS影响较大,并且当数据库发生异常时,也会直接影响原有的业务执行。

3. 基于Redis生成

​ 可以通过Redis的INCRINCRBY指令来实行分布式ID的生成,每次请求时,都从Redis中获取一次分布式ID。

分布式ID的实现方案-04

​ 当QPS较小时,此种方案可以应对,但是对于高并发场景,此种方案对于单台Redis服务器的性能要求较高,因此,需要搭建Redis集群,来缓解单台Redis服务器的压力,但是对于Redis集群来说,分布式ID的生成又会出现MySQL集群出现的问题,并且此种方案同样高度依赖Redis,一旦Redis服务器出现异常,就会影响到整个业务流程,同时此种方案引入了Redis中间件,增加了系统的复杂度。

4. 基于雪花算法生成

​ 雪花算法是由Twitter开源的一个分布式ID生成的解决方案,该分布式ID总共占用64bit存储空间,对于Java来说,正好使用long类型来进行存储。

第1位:始终是0,可以看做是符号位,不使用。

第2-42位:总共41位,表示时间戳,单位是毫秒,总共可以表示2^41个数字,即69年的时间。

第43-52位:总共10位,表示机器数,总共可以表示2^10=1024台机器,通常情况下,不需要部署这么多台机器,因此,一般将前5位表示数据中心,后5位表示机器数,即总共可以表示32个数据中心,每个数据中心有32台机器。

第53-64位:总共12位,表示自增序列,可以表示2^12=4096个数。

​ 这样划分之后,相当于在1ms之内,一个数据中心的一台服务器中,可以产生4096个不重复的有序ID。

分布式ID的实现方案-05

​ 具体的Java代码实现如下:

/**** 雪花算法** @author niutucode*/
public class Snowflake {/*** 开始时间戳*/private static final long START_TIMESTAMP = 1736820033851L;/*** 机器位数*/private static final long MACHINE_BIT = 10L;/*** 序列号位数*/private static final long SEQUENCE_BIT = 12L;/*** 机器最大值 1023*/private static final long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT);/*** 序列号最大值 4095*/private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);/*** 机器标识向左移动的位数*/private static final long MACHINE_LEFT = SEQUENCE_BIT;/*** 时间戳向左移动的位数*/private static final long TIMESTAMP_LEFT = SEQUENCE_BIT + MACHINE_BIT;/*** 机器ID*/private long machineId;/*** 序列号*/private long sequence = -1L;/*** 上一次时间戳*/private long lastTimeStamp = 0L;/*** 构造器** @param machineId 机器ID*/public Snowflake(long machineId) {if (machineId > MAX_MACHINE_NUM || machineId < 0) {throw new IllegalArgumentException("机器ID不能大于" + MAX_MACHINE_NUM + "或者小于0");}this.machineId = machineId;}/*** 产生下一个时间戳** @param lastTimeStamp 上一次生成的时间戳* @return 下一个时间戳*/private long nextTimestamp(long lastTimeStamp) {long timestamp = System.currentTimeMillis();while (timestamp <= lastTimeStamp) {timestamp = System.currentTimeMillis();}return timestamp;}/*** 获取分布式ID* 该方法需线程安全,如果在分布式系统中,应该使用分布式锁来保证该方法的线程安全,如果不设置,在高并发场景中,      * 可能会出现多个线程生成同一ID的异常* @return 分布式ID*/public synchronized long nextId() {long timestamp = System.currentTimeMillis();if (timestamp < lastTimeStamp) {throw new RuntimeException("时钟回拨异常");}if (timestamp == lastTimeStamp) {// 相同毫秒内,序列号自增sequence = (sequence + 1) & MAX_SEQUENCE;// 同一毫秒的序列数已经达到最大if (sequence == 0) {timestamp = nextTimestamp(lastTimeStamp);}} else {sequence = 0L;}lastTimeStamp = timestamp;return (timestamp - START_TIMESTAMP) << TIMESTAMP_LEFT | machineId << MACHINE_LEFT | sequence;}
}
public static void main(String[] args) {Snowflake snowflake = new Snowflake(0);System.out.println("分布式ID:" + snowflake.nextId());
}

分布式ID:9161748250624

​ 通过雪花算法生成分布式ID,生成的ID是有序递增的,不依赖于第三方系统,在高并发场景下,依然具有良好的性能,相较于UUID方式生成分布式ID,该方式性能更高,占用空间小,且递增有序,可读性更好。

​ 但是雪花算法也存在一定的局限性,当系统发生时钟回拨时,该方法就会处于不可用的状态,可以使用百度的UidGenerator或者美团的Leaf规避这一风险,在实际的开发中,可以根据需要,选择合适的方案,来实现分布式ID的生成。

相关文章:

分布式ID的实现方案

1. 什么是分布式ID ​ 对于低访问量的系统来说&#xff0c;无需对数据库进行分库分表&#xff0c;单库单表完全可以应对&#xff0c;但是随着系统访问量的上升&#xff0c;单表单库的访问压力逐渐增大&#xff0c;这时候就需要采用分库分表的方案&#xff0c;来缓解压力。 ​…...

Py之cv2:cv2(OpenCV,opencv-python)库的简介、安装、使用方法(常见函数、图像基本运算等)

1. OpenCV简介 1.1 OpenCV定义与功能 OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库。它为计算机视觉应用程序提供了一个通用的基础设施&#xff0c;并加速了在商业产品中使用机器感知。作为BSD许可的产品&…...

如何学习网络安全?有哪些小窍门?

学好网络安全其实没有所谓的捷径&#xff0c;也没有什么小窍门。 入门网络安全首先要有浓厚的学习兴趣&#xff0c;不然很容易就变成了从入门到放弃了。 其次要能静下心&#xff0c;踏踏实实的打好基础。如果你是零基础&#xff0c;建议从Web安全入手&#xff0c;课程难度相对…...

Dart语言的数据结构

Dart语言中的数据结构探讨 引言 Dart是一种现代化的编程语言&#xff0c;主要用于构建移动应用、Web应用和服务端应用。随着应用程序的复杂性日益增加&#xff0c;选择合适的数据结构显得尤为重要。数据结构不仅影响程序的性能&#xff0c;也影响程序的可维护性和可扩展性。本…...

TabPFN - 表格数据基础模型

文章目录 一、关于 TabPFN&#x1f310;TabPFN生态系统 二、快速入门&#x1f3c1;1、安装2、基本用法 三、使用技巧&#x1f4a1;四、开发&#x1f6e0;️1、设置环境2、在提交之前3、运行测试 一、关于 TabPFN TabPFN是表格数据的基础模型&#xff0c;它优于传统方法&#x…...

AOF日志:宕机了Redis如何避免数据丢失?

文章目录 AOF 日志是如何实现的&#xff1f;三种写回策略日志文件太大了怎么办&#xff1f;AOF 重写会阻塞吗?小结每课一问 更多redis相关知识 如果有人问你&#xff1a;“你会把 Redis 用在什么业务场景下&#xff1f;”我想你大概率会说&#xff1a;“我会把它当作缓存使用&…...

MAC上安装Octave

1. 当前最新版Octave是9.3版本&#xff0c;需要把mac os系统升级到14版本&#xff08;本人之前的版本是10版本&#xff09; https://wiki.octave.org/Octave_for_macOS octave的历史版本参考此文档&#xff1a;Octave for macOS (outdated) - Octavehttps://wiki.octave.org/Oc…...

C 语言中二维数组的退化

目录 1. 一维数组的退化 2.字符串数组的退化 3. 二维数组的退化 3.1 为什么退化为 int (*)[4] 而不是 int **&#xff1f; 3.2举例说明 3.3 .总结 在 C 语言中&#xff0c;数组名在大多数情况下会退化为指向其第一个元素的指针&#xff0c;这种机制称为数组退化&#xf…...

Notion 推出捏脸应用 | Deving Weekly #15

CEF-Detector-X 现在 Chromium 占据了桌面应用的大壁江山&#xff0c;典型的有 Electron 框架&#xff0c;底层就是基于 Chromium 内核&#xff0c;上百 M 的臃肿包体积一直别人诟病。 CEF-Detector-X 可以检测你电脑有多少个 基于 Chromium 应用&#xff0c;并且会生成一份「…...

C# Linq 查询

1.Linq 查询表达式基础 Linq 查询应用程序始终将源数据视为 IEnumerable<T> 或 IQueryable<T> 集合。 LINQ查询表达式包含8个基本子句,分别为from、select、group、where、orderby、join、let和into。 子 句备注from指定数据源和范围变量select指定当执行查询…...

ES7【2016】、ES8【2017】新增特性

ES7【2016】新增特性 幂指数操作符 在ES7【2016】中新增了幂指数操作&#xff0c;幂指数操作符是**。它用于指数计算 基本语法&#xff1a;baseValue ** exponent 参数说明&#xff1a;baseValue是基数&#xff0c;exponent是指数。 let base 2; let exponent 4; let resul…...

64细分步进电机驱动器TMC2209

封装和丝印 典型电路1 典型电路2 应用 兼容设计升级 3D 打印机 打印机、POS 办公和家庭自动化 纺织、缝纫机 闭路电视&#xff0c; 安保 ATM&#xff0c; 现金回收机 暖 通 空调 电池供电设备 特点和优势 2 相步进电机&#xff0c;线圈电流&#xff08;峰值&#xff09;高达…...

C# 获取PDF文档中的字体信息(字体名、大小、颜色、样式等

在设计和出版行业中&#xff0c;字体的选择和使用对最终作品的质量有着重要影响。然而&#xff0c;有时我们可能会遇到包含未知字体的PDF文件&#xff0c;这使得我们无法准确地复制或修改文档。获取PDF中的字体信息可以解决这个问题&#xff0c;让我们能够更好地处理这些文件。…...

linux 安装PrometheusAlert配置钉钉告警

在 Linux 上安装 PrometheusAlert 并配置钉钉告警的步骤如下: 1. 准备工作 钉钉机器人: 在钉钉群中创建一个机器人,获取 Webhook URL。示例 Webhook URL:https://oapi.dingtalk.com/robot/send?access_token=your_dingtalk_token。PrometheusAlert 安装包: 从 Prometheus…...

【华为路由/交换机的ssh远程设置】

华为路由/交换机的ssh远程设置 R1&#xff08;client&#xff09;&#xff1a;10.1.1.1 R2&#xff08;server&#xff09;&#xff1a;10.1.1.2 R2服务端配置&#xff1a; 生成本机密钥 查看生成的密钥 设置AAA授权验证方式&#xff0c;并设置支持SSH协议 创建本地用户&…...

性能测试 - Locust WebSocket client

Max.Bai 2024.10 0. 背景 Locust 是性能测试工具&#xff0c;但是默认只支持http协议&#xff0c;就是默认只有http的client&#xff0c;需要其他协议的测试必须自己扩展对于的client&#xff0c;比如下面的WebSocket client。 1. WebSocket test Client “”“ Max.Bai W…...

html中鼠标位置信息

pageX&#xff1a;鼠标距离页面的最左边的距离&#xff0c;包括滚动条的长度。clientX&#xff1a;鼠标距离浏览器视口的左距离&#xff0c;不包括滚动条。offsetX&#xff1a;鼠标到事件源左边的距离。movementX&#xff1a;鼠标这次触发的事件的位置相对于上一次触发事件的位…...

kubernetes v1.29.XX版本HPA、KPA、VPA并压力测试

序言&#xff1a; 在大型电商、购物、直播活动期间&#xff0c;对于火爆流量的激增&#xff0c;如何保障业务稳定并且做到资源不浪费&#xff0c;自动回收。 场景&#xff1a;kubernetes 原生容器化承载业务流量&#xff08;非云环境&#xff09; 方案&#xff1a;kubernetes自…...

flutter 常用UI组件

文章目录 1. Toast 文本提示框oktoastbot_toast2. loading 加载窗flutter_easyloading3. 对话框gex dialog4.下拉刷新pull_to_refresh5. pop 窗custom_pop_up_menu6. pin code 密码框pinput7. 二维码qr_flutter8. swiper 滚动组件carousel_sliderflutter_swiper_view9. Badge 角…...

HarmonyOS NEXT应用开发边学边玩系列:从零实现一影视APP (五、电影详情页的设计实现)

在上一篇文章中&#xff0c;完成了电影列表页的开发。接下来&#xff0c;将进入电影详情页的设计实现阶段。这个页面将展示电影的详细信息&#xff0c;包括电影海报、评分、简介以及相关影人等。将使用 HarmonyOS 提供的常用组件&#xff0c;并结合第三方库 nutpi/axios 来实现…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下&#xff0c;风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

NPOI Excel用OLE对象的形式插入文件附件以及插入图片

static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...

MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用

文章目录 一、背景知识&#xff1a;什么是 B-Tree 和 BTree&#xff1f; B-Tree&#xff08;平衡多路查找树&#xff09; BTree&#xff08;B-Tree 的变种&#xff09; 二、结构对比&#xff1a;一张图看懂 三、为什么 MySQL InnoDB 选择 BTree&#xff1f; 1. 范围查询更快 2…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验

Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...

深入浅出Diffusion模型:从原理到实践的全方位教程

I. 引言&#xff1a;生成式AI的黎明 – Diffusion模型是什么&#xff1f; 近年来&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;领域取得了爆炸性的进展&#xff0c;模型能够根据简单的文本提示创作出逼真的图像、连贯的文本&#xff0c;乃至更多令人惊叹的…...

C++实现分布式网络通信框架RPC(2)——rpc发布端

有了上篇文章的项目的基本知识的了解&#xff0c;现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...