微服务+分库分表的自增主键ID该如何设计?

一. 前言

分布式ID 是分布式系统里面非常重要的一个组成部分,那么我们在设计分布式ID的时候,需要考虑什么问题呢?

  • ❓简单结构下是怎么实现 ID 的控制的?

  • 单实例系统 :通过时间戳,系统内自增,上锁等方式保证ID的唯一性

  • 单数据库实例 : 通过自增字段(不谈性能)实现ID的唯一

  • ❓微服务 + 分库分表了 ,又该如何进行控制?

  • 问题 : 单个系统没办法直接感知到其他系统的ID情况,哪怕通信也要付出极大的代价

二. 来理解分布式ID的原则

2.1 分布式 ID 的本质是什么 ?

  • 全局唯一 : 要保证的是在任何场景下,任何系统,任何库,同一业务场景中生成的ID一定是唯一的

  • 递增 : 有的文章里面会谈到单调递增和趋势递增,这讲到的是2个维度:

  • 一个要求ID是有序增长的(趋势递增 ,用于排序

  • 一个是要求ID是正向增长的(单调递增 ,下一个一定比上一个大

  • 无规则 : 无规则是指不能按照MySQL主键自增这种方式进行 + 1 自增,简单的自增方式会带来安全层面的风险

最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。这是大佬写的,7701页的BAT大佬写的刷题笔记,让我offer拿到手软

2.2 有哪些相同性质的问题?

对于分布式 ID 的实现 ,在某些思路上和很多业务是通用的 ,例如 :

  • 订单编号的生成逻辑 :有序 + 反映时间
  • 券码的生成逻辑 : 有序 + 不可推测
  • 动态码 : 付款码,会员动态码等等

这些码的生产一般都会包含上述的2项原则,一定会要求全局唯一 ,同时根据情况来进行有序或者无序的控制。

其实无序一般也是看起来无序,在底层逻辑的生成上不可能完全无序,否则总会出现冲突的场景。

2.3 分布式 ID 的根本实现方式是什么 ?

ID的生成本质上只需要关注两个核心 :

  • 区域的划分 :我们需要保证每台机器是一个固定的区域 ,一般称之为机器ID
  • 锁的控制 : 不止是不同服务之间的分布式锁,还包括同一个服务的线程锁

来简单解读下 ,服务之间的通信很消耗资源 ,所以能不通信实现分布式ID的生成效率是最高的 , 那么一般会在服务启动的时候就计算出对应的工作区间。

同时要理解的是 ,锁往往和性能是对立关系,锁越多 ,则性能会相对越差,所以如何控制锁的粒度,则是分布式ID生成的一大核心。

三. 来探讨一下实现的思路

3.1 常规的分布式ID 算法

可用但是有限制的方案

// 简易版 - 基于时间戳的ID算法 :
- 方案 : 使用时间戳作为ID的前缀,然后通过机器的IP地址或MAC地址进行哈希计算得到剩余部分
- 问题 : 过于简单 , 只能实现单机毫秒级的并发
// 低效版 - 数据库自增
- 方案 : 没有方案 ,交给数据库来
- 问题 : 性能低 , 不支持分库分表
// 升级版 - 基于UUID
- 方案 :- 基于时间的UUID:主要依赖当前的时间戳及机器mac地址,因此可以保证全球唯一性- 分布式安全的UUID:将版本1的时间戳前四位换为POSIXUIDGID- 基于随机数的UUID:基于随机数或伪随机数生成- 基于名字空间的UUIDMD5版):基于指定的名字空间/名字生成MD5散列值得到
- 问题 : 长度过长 ,无序 ,不可读

常规的方案 :

  • 基于雪花算法的ID算法

雪花算法是由Twitter开发的一种分布式ID算法,它由几部分组成:时间戳、数据中心ID和机器ID以及序列ID。该算法可以保证ID的唯一性和稳定性,但需要较为复杂的计算和管理。

  • 基于LeaseSet的ID算法

LeaseSet是一种分布式ID系统,它通过将ID划分为多个片段,然后将这些片段分配给不同的机器来生成ID。该算法可以实现高可用和可扩展性,但需要较为复杂的实现和管理。

  • 总结一下

雪花ID一般是常见的分布式ID的方案 ,很多厂商都有这种算法的变种,操作灵活性能也比较理想。我生成主键ID时就是这种方案。

而通过分段的方案性能会很高,会在分布式锁的基础上 一次拿多个ID序列 ,然后在本地消耗这些ID序列。

比如生成订单码的时候 ,会一次性取出100个码,然后本地(单机上)逐步使用这些码。

雪花ID比较通用 。分段方式性能会更好,有序性会更强,毕竟都是连着的。

最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。这是大佬写的,7701页的BAT大佬写的刷题笔记,让我offer拿到手软

四. 分布式 ID 的简化方案

不同的业务场景对于分布式ID的要求不同 ,所以这里不说业务相关的,只谈实现流程,也没有什么代码

4.1 为你的 ID 定义格式

  • 起始位 : 起始位一般都是 1 ,在日常使用中一般不会变动,除非系统发生了整体的重做又需要保留之前数据时 ,才可以考虑通过这个来进行扩展

  • 总长度 : 位数一般基于具体的业务场景 , 和关联的内容以及数据总量息息相关。

  • 案例一 : 内含时间戳 ,一般 ID 里面会包含一个毫秒精度的时间戳,具体看业务

  • 案例二 : 插入随机数 ,在并发比较高的情况下 ,则需要通过随机数减少ID冲突的概率

  • 总结 : 一般情况下都是 64 位的纯数字 ,短了信息少,并发低。 长了浪费空间,浪费性能,库不支持。

  • 机器ID : 用来描述对应的服务器 , 一般支持1024位(也就是 1024台服务器,大多数情况下够用了)

👉 来看一下最常见的雪花算法的格式 :

0                                       41     51         64
+---------------------------------------+------+-----------+
| 时间戳(以毫秒为单位)                  |机器ID|    递增数  |
+---------------------------------------+------+-----------+

最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。这是大佬写的,7701页的BAT大佬写的刷题笔记,让我offer拿到手软

👉 来解析下里面的一些具体的细节 :

问题一 : 关于时间戳从什么时候开始

一般我们看到的雪花算法都会以当前时间减去过去一个纪元时间 (参考时间点), 有的可能是 1970 年 1 月 1 日 00:00:00 , 有的可能是上线时间或者一个特殊的时间点

通过这种方式既可以减少整体的长度,让数据变得紧凑 。又可以混淆 ID 的含义,让ID 没有那么容易被解析。

比如上面那个案例 , 可以看到最开始还空了4位数 ,所以时间戳的总空间是一定够的

问题二 : 关于机器ID

机器ID 的目的主要是为了区别不同的机器,从而避免在不同机器上面生成的数据冲突,一般都是通过分布式锁的方式来启动时获取 :

  • Redis 原子获取 : 适用于服务器Pod数不高的场景,启动不频繁,流程比较规范的情况下,用 Redis 完全是足够的
  • 数据库自增 : 一般这些ID的获取都是在系统启动时完成,所以数据库里面通过自增键去做也能实现我们的需求
  • Zookeeper : Zookeeper持久顺序节点的特性也可以实现类似的功能

这3种方式也是传统的分布式锁的获取方式 ,通过自增这种实现保证机器ID每个都不一样。

但是需要避免下面几个问题 :

  • 集群过大或者不同业务使用了同一个表生成 (机器ID一般就1024 ,超过了需要从 0 开始,一般是取模的方式)
  • 避免某个节点长期不重启带来的机器ID冲突
  • 避免某个机器频繁的重启导致机器ID被击穿

问题三 : 关于 sequence 序列ID

重点一 : sequence ID 是先要比对时间戳的 ,时间戳一样这个值才会增加
重点二 : 注意并发的影响 ,要么在生成 ID 的方法上添加 synchronized 控制并发 ,要么使用原子变量

问题四 : 时钟回拨 切记切记

由于上述的分布式 ID 是基于时间来实现的,这种方案最大的问题在于时钟回拨,如果服务器的时间回滚了,而机器又没重启 ,就可能会出现ID的冲突。

也有相关的解决方案 ,最常见的就是启动时校验时钟,比较其他的机器上的时间,方案就不详述了。

再一个就是换种思路 ,时间不是依赖的系统时间 ,而是一个自增的时间位。 这个是百度那边的一种算法,下一章单独讲。

最后总结: ❗❗❗❗

位数不是绝对 ,在保持64位总长度的情况下 ,机器ID 和 最后的自增数都可以随便调节。

包括整体的 64 位也不是完全绝对的 ,业务不同比 64 小几位也完全是可以的。

4.2 简单的实现方案

// S1 : 不管用什么方案 ,Redis 原子自增什么的,拿到一个 机器ID
public long getMechineId() {// 伪代码,方案自寻return redisService.incr("MECHINE_ID:" + prefixName);
}
// S2 : 构建分布式ID
private static Long lastTimestamp;// 注意并发问题 ,加锁或者原子变量
public static synchronized long buildId(){long timestamp = System.currentTimeMillis();// 如果时间一致 ,则需要增加 sequenceIDif (lastTimestamp == timestamp) {sequence = sequence + 1L & 1023L;} else {// 瞎写的 ,目的就是拿到一个 ID ,从 0 开始也可以sequence = (long)random.nextInt(128);}// 设置时间戳为最新时间戳lastTimestamp = timestamp;// tenantCode 是初始位 ,可以是0 ,也可以是 1// 如果为 0 则可能导致 ID 长度不统一 ,所以这里要根据具体的情况去设置// - 这里偏移多少位取决于后续的 sequence 想要留多少空间 ,只要时间戳偏移不要超过总数就行// - MechineId 留了 10 位 ,也就是 1024 个机器// - sequence 留了 12位 ,也就是每毫秒 4095 个return tenantCode << 60 | timestamp - 1288834974657L << 22 | getMechineId() << 12 | sequence;
}// S3 : 入库时使用
略 ,这就不用说了吧 ,写数据库的时候设置到ID里面就行了

最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。这是大佬写的,7701页的BAT大佬写的刷题笔记,让我offer拿到手软

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

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

相关文章

[Algorithm][动态规划][两个数组的DP][正则表达式匹配][交错字符串][两个字符串的最小ASCII删除和][最长重复子数组]详细讲解

目录 1.正则表达式匹配1.题目链接2.算法原理详解3.代码实现 2.交错字符串1.题目链接2.算法原理详解3.代码实现 3.两个字符串的最小ASCII删除和1.题目链接2.算法原理详解3.代码实现 4.最长重复子数组1.题目链接2.算法原理详解3.代码实现 1.正则表达式匹配 1.题目链接 正则表达…

《令狐带你阅读JDK源码之简单集合ArrayList》

文章目录 Java简单集合ArrayList继承体系源码解析 总结 大家好哈&#xff0c;欢迎来到令狐小哥本期专栏&#xff0c;这期专栏主要是带着大家阅读JDK源码&#xff0c;我会分几期篇幅来介绍这个jdk源码、会进行剖析、梳理&#xff0c;欢迎大家指正阅读。后面我会配套自己的视频进…

计算机网络 期末复习(谢希仁版本)第2章

物理层考虑的是怎样才能在连接各种计算机的传输媒体上传输数据比特流&#xff0c;而不是指具体的传输媒体。4 个特性&#xff1a; 机械特性&#xff1a;指明接口所用接线器的形状和尺寸、引线数目和排列、固定和锁定装置等。 电气特性&#xff1a;指明在接口电缆的各条线上出现…

【python进阶】python图形化编程之美--tkinter模块初探

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

白酒:茅台镇白酒的地域特色与环境优势

茅台镇&#xff0c;位于中国贵州省仁怀市&#xff0c;因其与众不同的自然环境和酿酒工艺而成为世界著名的白酒产区。作为茅台镇的品牌&#xff0c;云仓酒庄豪迈白酒以其卓着的品质和口感赢得了广大消费者的喜爱。而这一切&#xff0c;都离不开茅台镇的地域特色和环境优势。 茅台…

Python 知识图谱补全,Knowledge Graph Completion,基于大模型的知识图谱补全,基于LLMs的KGC任务

今天讲一篇文章《Exploring Large Language Models for Knowledge Graph Completion》 &#xff0c;这篇文章主题&#xff1a;基于大模型做知识图谱补全 1.文章主要思想&#xff1a; 本章描述知识图谱补全中的三个任务&#xff1a;三元组分类、关系预测和实体(链接)预测&…

C++初阶学习第十一弹——探索STL奥秘(六)——深度刨析list的用法和核心点

前言&#xff1a; 在前面&#xff0c;我们已经学习了STL中的string和vector&#xff0c;现在就来讲解STL中的最后一个部分——list的使用及其相关知识点&#xff0c;先说明一点&#xff0c;因为我们之前已经讲过了string和vector的接口函数等用法&#xff0c;list的这些用法与它…

python_将二维列表转换成HTML格式_邮件相关

python_将二维列表转换成HTML_邮件相关 data[["理想","2"],["理想2","3"]]def list_to_html_table(data):"""将二维列表转换为HTML表格格式的字符串。参数:data -- 二维列表&#xff0c;表示表格的数据。返回:一个字符…

美财长耶伦警告:金融行业广泛应用AI带来潜在“重大风险”

内容概述 耶伦承认&#xff0c;人工智能用在金融领域可降低交易成本、提高效率、检测欺诈和增加服务可及性&#xff0c;但也伴随风险。AI模型的复杂性和不透明度、供应商高度集中、产生数据缺陷或偏见等AI相关风险&#xff0c;已成为美国金融监管机构的首要议题。 6月6日周四&…

2024年全国青少信息素养大赛图形化编程挑战赛集训第一天编程题分享

大家如果不想阅读前边的比赛内容介绍,可以直接跳过:拉到底部看集训第一天题目 (一)比赛内容: 【小学低年级组】 1、图形化编程软件的使用:熟悉图形化编程软件中舞台区、角色列表区、功能区、脚本编 -3- 辑区的功能及使用。 2、基础功能模块的使用: a.运动模块:角…

Spring Boot 开发 -- 集成 Prometheus 进行高效监控

引言 随着微服务架构的流行&#xff0c;对服务的监控和管理变得尤为重要。Prometheus作为一个开源的监控和告警工具&#xff0c;以其强大的数据采集、存储和查询能力&#xff0c;受到了众多开发者的青睐。Spring Boot作为Java领域快速构建微服务的框架&#xff0c;与Prometheu…

单轮对话和多轮对话

参考&#xff1a;数据集对应关系说明 - 千帆大模型平台 | 百度智能云文档 (baidu.com) 什么是单轮对话 单轮对话和多轮对话是两种不同的对话形式&#xff0c;它们分别指的是在一次对话中只涉及一个问题和对应的回答&#xff0c;以及在一次对话中涉及多个问题和对应的回答。 …

暑假打工兼职首选——千行赏金

考虑暑假打工兼职该怎么选&#xff1f;加入千行赏金这样的平台确实是一个值得考虑的选择。以下是一些关于此问题的分析&#xff1a; 首先&#xff0c;暑假打工兼职的好处是显而易见的。它不仅可以为学生提供一定的经济收入&#xff0c;减轻家庭的经济负担&#xff0c;还可以帮…

【教程】从0开始搭建大语言模型:文本预处理

从0开始搭建大语言模型&#xff1a;文本预处理 参考仓库&#xff1a;LLMs-from-scratch 理解Word embedding 深度神经网络模型&#xff0c;包括LLM&#xff0c;不能直接处理原始文本&#xff0c;因此需要一种方法将它转换为连续值的向量&#xff0c;也就是embedding。如下图…

1782java英语陪学记词系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java英语陪学记词系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助采用了java设计&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统采用web模式&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&…

AI大底座核心平台:百度百舸AI异构计算平台(AI IaaS)与AI中台(AI PaaS)

AI大底座正是整合了以上端到端全要素技术能力&#xff0c;将基础架构IaaS与应用平台PaaS能力深度融合&#xff0c;面向企业和产业AI生 产与应用的全生命周期提供完整解决方案。 百舸AI异构计算平台是AI IaaS层的核心平台&#xff0c;包括AI计算、AI存储、AI加速、AI容器四层套件…

shell(一)

shell 既是脚本语言又是应用程序 查看自己linux系统的默认解析&#xff1a;echo $SHELL 创建第一个shell 文件 touch 01.sh编辑 vi 01.sh01.sh 文件内容 #!/bin/bash echo felicia保存 按Esc 然后输入:wq 定义以开头&#xff1a;#!/bin/bash #!用来声明脚本由什么shell解释…

idea maven 执行 控制台乱码

这是没加出现的问题 上方案

【HTTP系列】TCP/IP协议

文章目录 一、是什么二、划分五层体系应用层传输层网络层数据链路层物理层 四层体系 三、总结参考文献 一、是什么 TCP/IP&#xff0c;传输控制协议/网际协议&#xff0c;是指能够在多个不同网络间实现信息传输的协议簇 TCP&#xff08;传输控制协议&#xff09; 一种面向连…

【YOLOv5/v7改进系列】替换上采样层为Dysample

一、导言 介绍了一种名为DySample的超轻量级且高效的动态上采样器。DySample旨在解决当前动态上采样技术如CARAFE、FADE和SAPA虽然性能提升显著但带来大量计算负担的问题&#xff0c;这些问题主要来源于动态卷积的时间消耗以及用于生成动态核的额外子网络。此外&#xff0c;FA…