分布式ID生成方案

2023-11-09

分布式ID生成方案

在业务系统中很多场景下需要生成不重复的 ID,比如订单编号、支付流水单号、优惠券编号等都需要使用到。在我们业务数据量不大的时候,单库单表完全可以支撑现有业务,数据再大一点搞个MySQL主从同步读写分离也能对付。但随着数据日渐增长,主从同步也扛不住了,就需要对数据库进行分库分表,但分库分表后需要有一个唯一ID来标识一条数据,数据库的自增ID显然不能满足需求;特别一点的如订单、优惠券也都需要有唯一ID做标识。此时一个能够生成全局唯一ID的系统是非常必要的。那么这个全局唯一ID就叫分布式ID

一、mysql ID生成

1、基础版: 基于数据库的auto_increment自增ID完全可以充当分布式ID,具体实现:需要一个单独的MySQL实例用来生成ID,建表结构如下:

CREATE DATABASE `SEQ_ID`;
CREATE TABLE SEQID.SEQUENCE_ID (
    id bigint(20) unsigned NOT NULL auto_increment, 
    value char(10) NOT NULL default '',
    PRIMARY KEY (id),
) ENGINE=MyISAM;
insert into SEQUENCE_ID(value)  VALUES ('values');

当我们需要一个ID的时候,向表中插入一条记录返回主键ID,但这种方式有一个比较致命的缺点,访问量激增时MySQL本身就是系统的瓶颈,用它来实现分布式服务风险比较大,不推荐!

优点:

  • 实现简单,ID单调自增,数值类型查询速度快

缺点:

  • 系统不能水平扩展,DB单点存在宕机风险
  • 每次获取ID都需要获取数据库字段,加表锁,无法扛住高并发场景

2、改进版:号段模式

号段模式是当下分布式ID生成器的主流实现方式之一,号段模式可以理解为从数据库批量的获取自增ID,每次从数据库取出一个号段范围,例如 (1,1000] 代表1000个ID,具体的业务服务将本号段,生成1~1000的自增ID并加载到内存。表结构如下:

CREATE TABLE id_generator (
  id int(10) NOT NULL,
  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字段做一次update操作,update max_id= max_id + step,update成功则说明新号段获取成功,新的号段范围是(max_id ,max_id +step]

update id_generator set max_id = #{max_id+step}, version = version + 1 where version = # {version} and biz_type = XXX

由于多业务端可能同时操作,所以采用版本号version乐观锁方式更新,这种分布式ID生成方式不强依赖于数据库,不会频繁的访问数据库,对数据库的压力小很多。

二、redis ID生成

当使用数据库来生成ID性能不够要求的时候,我们可以尝试使用Redis来生成ID。这主要依赖于Redis是单线程的,所以也可以用生成全局唯一的ID。可以用Redis的原子操作 INCR和INCRBY来实现。redis incr操作最大支持在64位有符号的整型数字。提醒:这是一个string操作,因为Redis没有专用的数字类型。key对应的 string都被解释成10进制64位有符号的整型来执行这个操作。

redis实现需要注意一点,要考虑到redis持久化的问题。redis有两种持久化方式RDBAOF

  • RDB会定时打一个快照进行持久化,假如连续自增但redis没及时持久化,而这会Redis挂掉了,重启Redis后会出现ID重复的情况。
  • AOF会对每条写命令进行持久化,即使Redis挂掉了也不会出现ID重复的情况,但由于incr命令的特殊性,会导致Redis重启恢复的数据时间过长。

缺点:

  • redis 宕机后不可用,RDB重启数据丢失会重复ID
  • 自增,数据量易暴露。

优点:

  • 使用内存,并发性能好

三、UUID

UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。通常平台会提供生成的API。按照制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和随机数

UUID由以下几部分的组合:

  • 当前日期和时间,UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同
  • 时钟序列
  • 全局唯一的IEEE机器识别号,如果有网卡,从网卡MAC地址获得,没有网卡以其他方式获得
  • 在 hibernate(Java orm框架)中, 采用: IP-JVM启动时间-当前时间右移32位-当前时间-内部计数(8-8-4-8-4)来组成UUID

UUID的唯一缺陷在于生成的结果串会比较长。UUID具有以下涵义:

  • 经由一定的算法机器生成

为了保证UUID的唯一性,规范定义了包括网卡MAC地址、时间戳、名字空间(Namespace)、随机或伪随机数、时序等元素,以及从这些元素生成UUID的算法。UUID的复杂特性在保证了其唯一性的同时,意味着只能由计算机生成

  • 非人工指定,非人工识别

UUID是不能人工指定的,除非你冒着UUID重复的风险。UUID的复杂性决定了一般人不能直接从一个UUID知道哪个对象和它关联

  • 在特定的范围内重复的可能性极小

UUID的生成规范定义的算法主要目的就是要保证其唯一性。但这个唯一性是有限的,只在特定的范围内才能得到保证,这和UUID的类型有关(参见UUID的版本)。

缺点:

  • 不易于存储:UUID太长,16字节128位,通常以36长度的字符串表示,很多场景不适用。
  • 信息不安全:基于MAC地址生成UUID的算法可能会造成MAC地址泄露,这个漏洞曾被用于寻找梅丽莎病毒的制作者位置。
  • ID作为主键时在特定的环境会存在一些问题,比如做DB主键或者索引的场景下,UUID就非常不适用

四、雪花算法

SnowFlake可以保证所有生成的ID按时间趋势递增整个分布式系统内不会产生重复ID
在这里插入图片描述

  • 1.第一位 占用1bit,其值始终是0,确保ID是正数。
  • 2.时间戳 占用41bit,精确到毫秒,总共可以容纳约69年的时间。
  • 3.工作机器id 占用10bit,其中高位5bit是数据中心ID,低位5bit是工作节点ID,做多可以容纳1024个节点。
  • 4.序列号 占用12bit,每个节点每毫秒0开始不断累加,最多可以累加到4095,一共可以产生4096个ID。以表示的最大正整数是4095,即可以用0、1、2、3、…4094这4095个数字,来表示同一机器同一时间截(毫秒)内产生的4095个ID序号。用来表示在同一毫秒内产生ID的个数,最多产生4095个ID,多余的需要等到下一毫秒生成

雪花算法缺点:

​ 1)依赖机器时钟,如果机器时钟回拨,会导致重复ID生成

​ 2)在单机上是递增的,但是由于设计到分布式环境,每台机器上的时钟不可能完全同步,有时候会出现不是全局递增的情况(此缺点可以认为无所谓,一般分布式ID只要求趋势递增,并不会严格要求递增~90%的需求都只要求趋势递增)

时钟回拨解决方案:
在这里插入图片描述

  • 算法中记录上一次生成的时间戳,发现有时间回退时,将时间回拨位加 1,继续生成 ID。这样虽然时间戳字段的值可能和之前的一样,但是回拨位的值不一样,生成的 ID 是不会重复的。如果系统的时间超过了上一次的回退时间后可以把回拨位归 0。一位回拨位可以允许系统时间回退一次,两位回拨位可以允许系统时间连续回退三次。一般设置一位回拨位就够用了。
  • 算法记录上一次生成的时间戳,发现有时间回退时,降级为数据库形式获取。

五、ID缓冲环

为了提高 SnowflakeID 的并发性能和可用性,可以使用 ID 缓冲环(即 ID Buffer Ring)。提高并发性提现在通过使用缓冲环能够充分利用毫秒时间戳,提高可用性提现在可以相对缓解由时钟回拨导致的服务不可用。缓冲环是通过定长数组加游标哈希实现的,相比于链表会不需要频繁的内存分配。

  • 在 ID 缓冲环初始化的时候会请求 ID 生成器将 ID 缓冲环填满。
  • 当业务需要获取 ID 时,从缓冲环的头部依次获取 ID。
  • 当 ID 缓冲环中剩余的 ID 数量少于设定的阈值百分比时,比如剩余 ID 数量少于整个 ID 缓冲环的 30% 时,触发异步 ID 填充加载。异步 ID 填充加载会将新生成的 ID 追加到 ID 缓冲环的队列末尾,然后按照哈希算法映射到 ID 缓冲环上。
  • 另外有一个单独的定时器异步线程来定时填充 ID 缓冲环。
    在这里插入图片描述
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

分布式ID生成方案 的相关文章

  • 映射 mysql 中同一个表的多个值

    您好 我必须使用另一个表中的值 id 获取文本值 表 1 包含值 ID 表 2 包含名称和值 ID 表 1 SEVERITY OCCURENCE DETECTABILITY 2 3 4 表 2 id name value 1 Very Hi
  • 在 MySQL 中存储表情符号的编码问题:如何使用 Prisma ORM 在 NodeJS 中定义字符排序规则?

    亲爱的 Nodejs 专家和数据库专家 我们在 MySQL 数据库中存储表情符号和其他特殊字符时遇到问题 我们使用 Prisma 得到一个错误 这是我们使用的 ORM 参数无法从排序规则 utf8 general ci 转换为 utf8mb
  • POINT 列上的 MySQL INSERT/UPDATE

    我正在尝试用我国家的地理位置填充我的数据库 我的一张表有 4 个字段 ID PK 纬度 经度和地理点 EDIT SCDBs Punto Geografico SET lat 18 469692 SET lon 63 93212 SET g
  • PHP MYSQL文件内容转义问题

    我正在尝试使用 php 将 pdf 文件上传到 mysql 数据库中 除了文件内容之外 一切都很好 无论我如何尝试转义特殊字符 查询总是失败 主要是 未知命令 n 我使用过addslashes mysql real escape strin
  • PHP 和 MySQL - 高效处理多个一对多关系

    我正在寻求一些有关使用 MySQL 和 PHP 检索和显示数据的最佳方法的建议 我有 3 个表 所有一对多关系如下 Each SCHEDULE有很多覆盖每个覆盖都有很多地点 我想检索这些数据 以便它可以全部显示在单个 PHP 页面上 例如列
  • 无法在 Mac 上启动 MySQL

    使用 Brew 安装后 我无法运行 MySQL 我使用的是 OS X El Capitan 版本 10 11 3 和 MySQL Server 版本 5 7 11 当我启动服务器时 我收到 启动 MySQL 错误 服务器退出而不更新 PID
  • 如何在 MySQL 中测试 Select for Update

    我正在表演SELECT FOR UPDATE或 InnoDB 表的行级锁定 我的目的是只有一个请求可以读取同一行 因此 如果两个用户同时请求相同的数据 其中只有一个人获取数据 即第一个触发查询的人 但是我如何测试锁定是否已放置 因为我正在通
  • 非常大的字段会对 MySQL 数据库产生负面影响吗?

    我目前正在使用 Django 构建一个网站 并希望托管用户生物样式页面 该页面可能长达几 KB 这些字段不一定需要搜索 但在查找用户名时确实需要提供 将这些数据存储在数据库中会产生负面影响吗 如果我使用带有数据库链接的静态文本文件 我的服务
  • MySQL中如何声明变量?

    如何在mysql中声明一个变量 以便我的第二个查询可以使用它 我想写一些类似的东西 SET start 1 SET finish 10 SELECT FROM places WHERE place BETWEEN start AND fin
  • 用 pandas DataFrame 替换 mysql 数据库表中的行

    Python 版本 2 7 6 熊猫版本 0 17 1 MySQLdb 版本 1 2 5 在我的数据库中 PRODUCT 我有一张桌子 XML FEED 表 XML FEED 很大 数百万条记录 我有一个 pandas DataFrame
  • 让登录更安全

    我已使用此代码进行管理员登录 仅当用户输入正确的用户名和密码时才应打开loginhome php 但后来我意识到这根本不安全 任何人都可以直接访问 mywebsite loginhome php 而无需登录 注销后 可以使用后退按钮打开 l
  • ORDER BY 字段内的 MySQL 子查询。 (没有内连接)

    有很多与此相关的问题 但都具有使用内部联接的相同答案 这 我认为 在这里是不可能的 如果我错了请告诉我 我现在正在做的是调用两个不同的 mysql 查询来获取结果 它工作完美 db gt query SELECT FROM meta WHE
  • 在 SQL 中,如何从 SELECT * FROM ... 中排除结果?

    我知道我的标题不太具有描述性 让我在这里详细解释一下 假设一个表有 26 个字段 例如字段 a 字段 z 我只想要一个选择查询只返回 15 个字段 所以 通常 我会执行 SELECT field a field b field o FROM
  • PHP MySQL 使用选项/选择 HTML 表单标签进行多重搜索查询

    我正在尝试使用两个搜索字段设置基本的 MySQL LIKE 搜索 我不想拥有它 所以它有多个可选搜索字段 例如if isset POST city isset POST name 我不知道如何用 HTML 来做到这一点
  • MaxListenersExceededWarning:检测到可能的 EventEmitter 内存泄漏。添加了 11 条消息列表。使用emitter.setMaxListeners()来增加限制

    我知道这可能会标记为重复的解决方案 但堆栈溢出的解决方案对我不起作用 Problem node 5716 MaxListenersExceededWarning Possible EventEmitter memory leak detec
  • 如何通过Elasticsearch模糊匹配电子邮件或电话?

    我想通过 Elasticsearch 对电子邮件或电话进行模糊匹配 例如 匹配所有以以下结尾的电子邮件 gmail com or 匹配所有电话开头136 我知道我可以使用通配符 query wildcard email gmail com
  • posts_search 中的自定义查询

    如何使用此查询作为我的自定义搜索查询 add filter posts search my search is perfect 20 2 function my search is perfect search wp query sWord
  • MySQL 与日语字符

    我试图弄清楚如何创建一个表 以便我可以在其中插入日语名字 现在我有 Type InnoDB Encoding UTF 8 Unicode utf8 Collation utf8 general ci 但是 当我插入字符时 它显示为 当我使用
  • PHP 与 MySQL 查询性能( if 、 函数 )

    我只看到这个artice http www onextrapixel com 2010 06 23 mysql has functions part 5 php vs mysql performance 我需要知道在这种情况下什么是最好的表
  • post php mysql 的拆分关键字

    我有一个表存储帖子 ID 它的标签如下 Post id Tags 1 keyword1 keyword2 keyword3 我想循环遍历该表中的每一行并执行以下操作 将关键字1 关键字2 关键字3放入新表中 word id word val

随机推荐

  • 推荐系统入门之使用协同过滤实现商品推荐

    简介 场景将使用机器学习PAI平台 指导您搭建一个基于协同过滤算法的商品推荐系统 背景知识 数据挖掘的一个经典案例就是尿布与啤酒的例子 尿布与啤酒看似毫不相关的两种产品 但是当超市将两种产品放到相邻货架销售的时候 会大大提高两者销量 很多时
  • 使用spacy库出现错误OSError: [E941] Can‘t find model ‘en‘.

    问题 运行代码 TEXT data Field tokenize spacy LABEL data LabelField dtype torch float 报错 OSError E941 Can t find model en It lo
  • 将矩阵&概率画成图

    任何一个矩阵都能画成一个图 更严谨的来说 每个矩阵对应一个加权二分图 所谓图是指点和线的集合 二分是指两种不同的类型 加权是指每条线上都有一个数字标记 上图的三个绿点代表三行 两个红点代表两列 若对应矩阵值非零 则在绿点和红点间画一条线连接
  • PHP中的电子邮件如何发送?

    PHP中的电子邮件发送是一个常见的需求 但是如果你是一个新手 可能会觉得有些棘手 别担心 我可以为你提供一些简单的步骤和代码例子 帮助你发送电子邮件 首先 你需要使用PHP的mail 函数来发送电子邮件 这个函数需要三个参数 邮件地址 邮件
  • 【解决】MFC改变窗口标题“无标题—title”

    用框架窗口类的SetWindowText L 你的标题 在应用程序类CTestApp InitInstance 中调用如下语句 m pMainWnd gt SetWindowText L 你的标题 或者在其他地方用AfxGetMainWnd
  • 图的m着色问题-回溯法

    排列树问题 给定无向连通图G和m种不同的颜色 用这些颜色为图G的各顶点着色 每个顶点着一种颜色 是否有一种着色法使G中任意相邻的2个顶点着不同颜色 输出结果 include
  • 2023年云南省职业院校技能大赛中职组“网络安全”赛项样题

    2023年云南省职业院校技能大赛 中职组 网络安全 赛项样题 一 竞赛时间 总计 180分钟 二 竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 A B模块 A 1 登录安全加固 180分钟 200分 A 2 数据库加固 A 3 服
  • OpenGL: 平面阴影投射矩阵的推导

    OpenGL 平面阴影投射矩阵的推导 OpenGL SuperBible 这本书介绍了一种阴影的实现方法 将模型视图矩阵压平 所有被绘制的物体都将位于这个平面的二维世界中 不过这本书没有介绍该平面阴影投射矩阵是如何推导的 假设平面方程 Ax
  • linux脚本调用db2存储过程,LINUX定时执行含有DB2存储过程的SHELL脚本

    LINUX定时执行含有DB2存储过程的SHELL脚本 由会员分享 可在线阅读 更多相关 LINUX定时执行含有DB2存储过程的SHELL脚本 6页珍藏版 请在人人文库网上搜索 1 LINUX下定时执行含有DB2存储过程的SHELL脚本最近项
  • 开关电源纹波的产生、测量和抑制

    一 产生分析 1 随着SWITCH 的开关 电感L 中的电流也是在输出电流的有效值上下波动的 所以在输出端也会出现一个与SWITCH 同频率的纹波 一般所说的纹波就是指这个 它与输出电容的容量和ESR 有关系 这个纹波的频率与开关电源相同
  • Windows 下 sublime text3的安装及设置

    一 安装Sublime Text3 1 下载 官网下载 http www sublimetext com 3 百度云 https pan baidu com s 1X6hD7AH giyahkCK79ZKqw 提取码 e3ai 2 安装 S
  • android recovery 升级和分区

    1 华为手机分区信息 1 shell android df df Filesystem Size Used Free Blksize dev 196M 64K 196M 4096 mnt asec 196M 0K 196M 4096 mnt
  • DBCP连接池配置参数说明

  • 【注意】C++基类的构造函数中,参数与类中已有变量同名,要加上作用域来表示类内变量

    定义一个类 class Text1 public Text1 构造函数 Text1 int pub int pri int pro 重载的构造函数 Text1 int pub void OutputValue 打印类内变量 private
  • java实现一台电脑控制多台手机_涨姿势:教你用电脑远程控制多台手机!终于可以挂手机了!...

    是不是每次坐到电脑前 你的桌面上总会摆好手机 时不时低头瞅瞅 不管是看视频 资讯都会时不时摆弄两下手机 如果你是上班族 是不是因为这个被领导骂过或者斜眼过 好吧 难道你不感觉这样很烦么 小编今天就介绍一个方法让你能用电脑挂手机 关键是过程超
  • iOS死灰复燃SDK

    iOS死灰复燃SDK功能 令iOS APP进入后台或手机锁屏下常也能常驻后台活动 定位 即使杀死APP进程也会适时自动复活APP 让APP能够在后台或进程被杀死之后也能照常发送网络请求 定位 更新数据等操作 具备自动复活功能 SDK版本 V
  • 华为OD机试真题- 找数字【2023Q2】【JAVA、Python、C++】

    题目描述 给一个二维数组nums 对于每一个元素num i 找出距离最近的且值相等的元素 输出横纵坐标差值的绝对值之和 如果没有等值元素 则输出 1 例如 输入数组nums为 0 3 5 4 2 2 5 7 8 3 2 5 4 2 4 对于
  • 2023待学习&待填的坑

    代码cherry pick时解决代码冲突 一 gdb调试 二 git教程实践部分 done 20230805 学习笔记链接 git相关 张杰萌萌哒的博客 CSDN博客 三 编译原理及makefile编写 四 C 课程 60 学习笔记链接 C
  • TOB企业如何借助生态力,实现可持续增长

    近年来 随着经济社会的高速发展 数字化转型已成为企业高质量发展 必答题 企业开始通过购买产品 解决方案或者自研的方式来进行本企业的数字化建设 但是由于内部部门墙或者是系统之间的隔阂 难以做到以整个公司为视角的全面数字化建设 就容易在企业内部
  • 分布式ID生成方案

    分布式ID生成方案 在业务系统中很多场景下需要生成不重复的 ID 比如订单编号 支付流水单号 优惠券编号等都需要使用到 在我们业务数据量不大的时候 单库单表完全可以支撑现有业务 数据再大一点搞个MySQL主从同步读写分离也能对付 但随着数据