分布式ID生成器 | 架构师之路

【强推】你可能没听过的,分布式唯一随机数ID生成器,值得收藏 作为一个IT人,分布式唯一ID耳朵都听起老茧了,什么雪花算法 (SnowFlake ) 、UUID、Mongdb objectID、美团Leaf-segment、中央数据库序列自增等等。 今天,笔者要给大家介绍的是一款,几乎很少有人知道的随机数ID生成器。随机数ID通常可用于生成合同编号、订单编号、专利编号等一系列重要业务编号场景,防止被他人恶意扫描数据或猜测数据。 阅读详情

 

原创 58沈剑 架构师之路 2017-06-25

一、需求缘起

几乎所有的业务系统,都有生成一个唯一记录标识的需求,例如:

  • 消息标识:message-id

  • 订单标识:order-id

  • 帖子标识:tiezi-id

 

这个记录标识往往就是数据库中的主键,数据库上会建立聚集索引(cluster index),即在物理存储上以这个字段排序。

 

这个记录标识上的查询,往往又有分页或者排序的业务需求,例如:

  • 拉取最新的一页消息

    select message-id/ order by time/ limit 100

  • 拉取最新的一页订单

    select order-id/ order by time/ limit 100

  • 拉取最新的一页帖子

    select tiezi-id/ order by time/ limit 100

 

所以往往要有一个time字段,并且在time字段上建立普通索引(non-cluster index)。

 

普通索引存储的是实际记录的指针,其访问效率会比聚集索引慢,如果记录标识在生成时能够基本按照时间有序,则可以省去这个time字段的索引查询:

select message-id/ (order by message-id)/limit 100

 

强调,能这么做的前提是,message-id的生成基本是趋势时间递增的。

 

这就引出了记录标识生成(也就是上文提到的三个XXX-id)的两大核心需求:

  • 全局唯一

  • 趋势有序

这也是本文要讨论的核心问题:如何高效生成趋势有序的全局唯一ID。

 

二、常见方法、不足与优化

方法一:使用数据库的 auto_increment 来生成全局唯一递增ID

 

优点:

  • 简单,使用数据库已有的功能

  • 能够保证唯一性

  • 能够保证递增性

  • 步长固定

 

缺点:

  • 可用性难以保证:数据库常见架构是一主多从+读写分离,生成自增ID是写请求,主库挂了就玩不转了

  • 扩展性差,性能有上限:因为写入是单点,数据库主库的写性能决定ID的生成性能上限,并且难以扩展

 

改进方法:

  • 冗余主库,避免写入单点

  • 数据水平切分,保证各主库生成的ID不重复


如上图所述,由1个写库变成3个写库,每个写库设置不同的auto_increment初始值,以及相同的增长步长,以保证每个数据库生成的ID是不同的(上图中库0生成0,3,6,9…,库1生成1,4,7,10,库2生成2,5,8,11…)

 

改进后的架构保证了可用性,但缺点是:

  • 丧失了ID生成的“绝对递增性”:先访问库0生成0,3,再访问库1生成1,可能导致在非常短的时间内,ID生成不是绝对递增的(这个问题不大,目标是趋势递增,不是绝对递增)

  • 数据库的写压力依然很大,每次生成ID都要访问数据库

 

为了解决上述两个问题,引出了第二个常见的方案。

 

方法二:单点批量ID生成服务

 

分布式系统之所以难,很重要的原因之一是“没有一个全局时钟,难以保证绝对的时序”,要想保证绝对的时序,还是只能使用单点服务,用本地时钟保证“绝对时序”。

 

数据库写压力大,是因为每次生成ID都访问了数据库,可以使用批量的方式降低数据库写压力。

 


如上图所述,数据库使用双master保证可用性,数据库中只存储当前ID的最大值,例如0。

 

ID生成服务假设每次批量拉取6个ID,服务访问数据库,将当前ID的最大值修改为5,这样应用访问ID生成服务索要ID,ID生成服务不需要每次访问数据库,就能依次派发0,1,2,3,4,5这些ID了。

 

当ID发完后,再将ID的最大值修改为11,就能再次派发6,7,8,9,10,11这些ID了,于是数据库的压力就降低到原来的1/6。

 

优点:

  • 保证了ID生成的绝对递增有序

  • 大大的降低了数据库的压力,ID生成可以做到每秒生成几万几十万个

 

缺点:

  • 服务仍然是单点

  • 如果服务挂了,服务重启起来之后,继续生成ID可能会不连续,中间出现空洞(服务内存是保存着0,1,2,3,4,5,数据库中max-id是5,分配到3时,服务重启了,下次会从6开始分配,4和5就成了空洞,不过这个问题也不大)

  • 虽然每秒可以生成几万几十万个ID,但毕竟还是有性能上限,无法进行水平扩展

 

改进方法:

单点服务的常用高可用优化方案是“备用服务”,也叫“影子服务”,所以我们能用以下方法优化上述缺点(1):


如上图,对外提供的服务是主服务,有一个影子服务时刻处于备用状态,当主服务挂了的时候影子服务顶上。

 

这个切换的过程对调用方是透明的,可以自动完成,常用的技术是vip+keepalived,具体就不在这里展开。

 

另外,ID-gen-service也可以实施水平扩展,以解决上述缺点(3),但会引发一致性问题,具体解决方案详见《浅谈CAS在分布式ID生成方案上的应用》。

 

方法三:uuid/guid

 

不管是通过数据库,还是通过服务来生成ID,业务方Application都需要进行一次远程调用,比较耗时。

 

有没有一种本地生成ID的方法,即高性能,又时延低呢?

 

uuid是一种常见的方案:

string ID =GenUUID();

 

优点:

  • 本地生成ID,不需要进行远程调用,时延低

  • 扩展性好,基本可以认为没有性能上限

 

缺点:

  • 无法保证趋势递增

  • uuid过长,往往用字符串表示,作为主键建立索引查询效率低,常见优化方案为“转化为两个uint64整数存储”或者“折半存储”(折半后不能保证唯一性)

 

方法四:取当前毫秒数

 

uuid是一个本地算法,生成性能高,但无法保证趋势递增,且作为字符串ID检索效率低,有没有一种能保证递增的本地算法呢?

 

取当前毫秒数是一种常见方案:

uint64 ID = GenTimeMS();

 

优点:

  • 本地生成ID,不需要进行远程调用,时延低

  • 生成的ID趋势递增

  • 生成的ID是整数,建立索引后查询效率高

 

缺点:

  • 如果并发量超过1000,会生成重复的ID

 

这个缺点要了命了,不能保证ID的唯一性。当然,使用微秒可以降低冲突概率,但每秒最多只能生成1000000个ID,再多的话就一定会冲突了,所以使用微秒并不从根本上解决问题。

 

方法五:类snowflake算法

 

snowflake是twitter开源的分布式ID生成算法,其核心思想为,一个long型的ID:

  • 41bit作为毫秒数

  • 10bit作为机器编号

  • 12bit作为毫秒内序列号

 

算法单机每秒内理论上最多可以生成1000*(2^12),也就是400W的ID,完全能满足业务的需求。

 

借鉴snowflake的思想,结合各公司的业务逻辑和并发量,可以实现自己的分布式ID生成算法。

 

举例,假设某公司ID生成器服务的需求如下:

  • 单机高峰并发量小于1W,预计未来5年单机高峰并发量小于10W

  • 有2个机房,预计未来5年机房数量小于4个

  • 每个机房机器数小于100台

  • 目前有5个业务线有ID生成需求,预计未来业务线数量小于10个

  • …

 

分析过程如下:

  • 高位取从2017年1月1日到现在的毫秒数(假设系统ID生成器服务在这个时间之后上线),假设系统至少运行10年,那至少需要10年*365天*24小时*3600秒*1000毫秒=320*10^9,差不多预留39bit给毫秒数

  • 每秒的单机高峰并发量小于10W,即平均每毫秒的单机高峰并发量小于100,差不多预留7bit给每毫秒内序列号

  • 5年内机房数小于4个,预留2bit给机房标识

  • 每个机房小于100台机器,预留7bit给每个机房内的服务器标识

  • 业务线小于10个,预留4bit给业务线标识

 

这样设计的64bit标识,可以保证:

  • 每个业务线、每个机房、每个机器生成的ID都是不同的

  • 同一个机器,每个毫秒内生成的ID都是不同的

  • 同一个机器,同一个毫秒内,以序列号区区分保证生成的ID是不同的

  • 将毫秒数放在最高位,保证生成的ID是趋势递增的

 

缺点:

  • 由于“没有一个全局时钟”,每台服务器分配的ID是绝对递增的,但从全局看,生成的ID只是趋势递增的(有些服务器的时间早,有些服务器的时间晚)

 

思路比方案重要,顺手帮转哟。

 

相关推荐:

架构师之路2016全年精选

架构师之路2017上半年精选

基于 Redis 的全局唯一性ID生成器的一些实现思路 因为公司微服务转型, 又逢开发期间 基于 Redis 的序列号服务的设计 一帅同学 泛金融技术 https://mp.weixin.qq.com/s/UzKmJnQupk4W_ZoCevd_O 干货 | 分布式架构系统生成全局唯一序列号的一个思路 丁宜人 携程技术中心 https://mp.weixin.qq.com/s?__biz=MjM5MDI3MjA5MQ==&mid= 阅读详情

相关推荐

分布式数据库基石-id中的学问-徐海峰

阅文集团首席架构师徐海峰围绕“分布式系统的基石—Id生成器中的学问”这一主题,从五大切入点入手展开讨论。

分布式.ID生成器

ID分为业务NUM和系统标识用的ID,业务ID一般都是产品给业务规则,在拼接递增序列即可,下面不在讨论ID要求全局唯一,时间增序必须考虑分布式问题。

记录 分享 成就 1355

C语言—for循环打印矩形,正三角形,倒三角形,九九乘法,等腰三角形,倒着的等腰三角形(简易版代码)(重点考察for循环嵌套)

本章节教大家如何利用for循环打印正三角形,倒三角形,九九乘法表及等腰三角形(简易版代码)说明:1、循环语句的循环体内又包含另一个完整的循环结构,称为循环结构的嵌套。内嵌的循环语句中还可以再嵌套循环结构,这样就形成多重循环结构的嵌套。2、for 语句、while 语句和 do-while 语句都允许嵌套。三种循环语句可以相互嵌套。3、内层的循环语句必须完全被包含在外层的循环体中,不能发生交叉。

m0_63501145的博客 1696

分布式系列之ID生成器

全局唯一ID生成器需求背景、应用场景、需求分析;方案:数据库、UUID、UUID的5个版本、UUID-v1改进版、Hibernate CustomVersionOneStrategy、MongoDB ObjectId、Redis、ZooKeeper;Snowflake、时钟回拨问题、解决方案;Snowflake改进版、开源ID生成器

lonelymanontheway的博客 2294

生成式引擎优化(GEO)标准化操作流程:构建高效AI生成系统的全链路指南

GEO是针对生成式AI的内容优化策略,通过提升内容在AI生成答案中的引用优先级实现品牌传播。相比传统SEO,GEO使内容直接嵌入AI答案,无需用户点击链接。核心流程包括:1)逆向拆解AI问答场景,结构化知识资产;2)生产权威内容(白皮书、专利数据)和算法适配内容(PCOE模板);3)技术实现(数据投喂、模型微调);4)331渠道分发策略;5)效果监控与动态防御。需注意采用结构化数据标记、主动提交训练数据,并避免简单复制SEO策略。2025版强调内容权威性和语义优化,通过AI原生内容工程实现高效曝光。

解锁AI流量新红利!🚀 GEO优化(生成引擎优化)助您掌控AI搜索,让AI成为您的品牌最佳代言人! 1167

Oracle恢复学习实战小结

     学习oracle10g 043课程有段时间了,前一两个星期学习了backup/restore相关的内容,刚好公司有要求要为host服务器做一个备用机以防止数据意外丢失。于是,实战开始了。     首先介绍host服务器架构。host以oracle数据库作为底层数据存储,以公司总部开发的Santorin作为应用,主要提供给测试台架数据存储、数据访问、数据导入导出、用户权限管理和数据自动备份

kseawolfk的专栏 1035

分布式全局唯一 ID生成器(百度UidGenerator)

UidGenerator是百度开源的Java语言实现,基于Snowflake算法的唯一ID生成器。它是分布式的,并克服了雪花算法的并发限制。单个实例的QPS能超过6000000。需要的环境:JDK8+,MySQL(用于分配WorkerId)

追寻心的步伐 6282

VsCode+JLink+GCC替代Keil开发GD32程序-个人总结

对个人使用vscode+Jlink开发GD32程序做了总结,供需要者参考。

MyCollege1999的博客 2768

9种分布式ID生成方式,总有一款适合你

不同于原始snowflake算法也主要是在workId的生成上,Leaf中workId是基于ZooKeeper的顺序Id来生成的,每个应用在使用Leaf-snowflake时,启动时都会都在Zookeeper中生成一个顺序Id,相当于一台机器对应一个顺序节点,也就是一个workId。epoch时间就是指集成UidGenerator生成分布式ID服务第一次上线的时间,可配置,也一定要根据你的上线时间进行配置,因为默认的epoch时间可是2016-09-20,不配置的话,会浪费好几年的可用时间。

过客2019 1717

Zemax实战录——非序列模式下的微透镜阵列仿真与优化

本文详细介绍了在Zemax非序列模式下进行微透镜阵列仿真的完整流程与优化技巧。文章重点阐述了从序列模式切换到非序列模式的必要性,并逐步指导如何搭建光源、阵列与探测器的仿真环境。核心在于通过调整圆锥系数等关键参数优化像差,并增加光线数以提升仿真精度与均匀性,为光学设计提供可靠依据。

weixin_28339967的博客 527

(实测可用)STM32L431RCT6开发板-实验1 跑马灯实验

一、开发板平台简介: 1、开发板资源简介 (1)开发板主芯片型号:STM32L431RCT6 (2)开发板主芯片封装:LQFP-64_10x10x05P (3)开发板主芯片内核:ARM® Cortex®-M4 (4)开发板主芯片主频:80MHz (5)开发板主芯片Flash大小:256KB (6)开发板主芯片RAM大小:64KB

zhej2014的博客 3169

互联网分布式ID生成器 | 架构师之路

  一、需求缘起 几乎所有的业务系统,都有生成一个唯一记录标识的需求,例如: 消息标识:message-id 订单标识:order-id 帖子标识:tiezi-id   这个记录标识往往就是数据库中的主键,数据库上会建立聚集索引(cluster index),即在物理存储上以这个字段排序。   这个记录标识上的查询,往往又有分页或者排序的业务需求,...

yangactive的专栏 998

人形机器人大语言模型 pi*0.6(π*0.6):最新从经验中学习的VLA

摘要:本文介绍了一种名为Recap的机器人学习方法,通过示范训练、纠错指导和强化学习三个步骤提升机器人执行复杂任务的能力。研究显示,仅依靠模仿学习的机器人难以解决错误累积问题,而Recap方法通过价值函数可视化和优势条件策略训练,使π*0.6模型在咖啡制作、纸箱组装和衣物折叠等任务中的成功率提升超过90%,吞吐量翻倍。该方法突破了传统依赖人工演示的局限,通过自主经验学习实现机器人性能的持续优化,为未来机器人基础模型的发展提供了新方向。

2506_90492529的博客 1321

分布式ID生成器(来源:架构师之路,2017-06-25 58沈剑 架构师之路)

一、需求缘起几乎所有的业务系统,都有生成一个唯一记录标识的需求,例如:消息标识:message-id订单标识:order-id帖子标识:tiezi-id这个记录标识往往就是数据库中的主键,数据库上会建立聚集索引(cluster index),即在物理存储上以这个字段排序。 这个记录标识上的查询,往往又有分页或者排序的业务需求,例如:拉取最新的一页消息select message-id/ order

涂作权的博客 927

【STM32Cube_14】使用硬件I2C读写环境光强度传感器(BH1750)

本篇详细的记录了如何使用STM32CubeMX配置STM32L431RCT6的硬件I2C外设读取环境光强度传感器数据(BH1750)

Mculover666的博客(嵌入式) 7243

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

青橙商城项目总结day03-04

青橙商城项目总结 day03_模板与分类管理 设计模式:SSM;分库分表 技术栈:黑马架构师;vue;Element UI 学习目标: 1)使用“黑马架构师”完成代码生成 \1. 建立数据库表,并设置字段的中文备注(中文备注用于作为生成表格的标题) \2. 双击codeutil-2.5.jar 或start.bat运行程序,输入用户名和密码,点击测试连接,选择数据库表后点击“下一步”。 \3. 选择模板,输入基本信息,注意:包名一定要3级,例如 com.itheima.goods 前两级 为模块名称,第三级

m0_51361644的博客 1069

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

4577页PDF助你拿下大厂offer的技术秘籍

Java技术体系与工程实践是进入大厂的核心竞争力。从JVM内存模型到分布式系统设计,深入理解底层原理才能应对复杂场景。HashMap扩容机制、MySQL索引优化等高频考点背后,是数据结构与算法能力的体现。这份4577页的PDF资料通过技术决策树、生产场景推演等结构化方法,将知识转化为解决实际问题的能力。文档涵盖从基础理论到工业级实现的完整闭环,如GC调优、锁升级机制等,并包含200+手写代码练习和线上故障排查案例,帮助开发者建立架构师思维,应对阿里、字节等大厂的技术面试挑战。

weixin_30920853的博客 478

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

架构师之路,季度精选40篇

2017Q3,阅读过万40篇,点击标题阅读。【特别推荐】《架构师之路2016年精选66篇》10W+《架构师之路2017上半年精选40篇》5W+【通用设计与方法论】《分布式...

shenjian58的博客 294

搞懂分布式技术12:分布式ID生成方案

分布式ID生成器 | 架构师之路 原创:58沈剑架构师之路2017-06-25 一、需求缘起 几乎所有的业务系统,都有生成一个唯一记录标识的需求,例如: 消息标识:message-id 订单标识:order-id 帖子标识:tiezi-id ...

weixin_34024034的博客 177

玩转MySQL:一站式解决分库分表后患问题方案

比如当你考虑对存储层做分库分表时,就得先考虑清楚本章中提到的所有问题,以及具体该如何解决,只考虑追求技术风潮,不考虑技术风险的做法,显然无法被称作一位合格的架构师。对单个业务库做了水平分库后,也就是又对单个业务库做了横向拓展后,一般都会将库中所有的表做水平切分,也就是不同库中的所有表,每个水平库节点中存储的数据是不同的,这时又会出现4.2阶段聊到的一些问题,如单业务的聚合操作、连表操作会无法进行,这种情况的解决思路和水平分表时一样,先确定读写的数据位于哪个库表中,然后再去生成SQL并执行。

朔月 784

分布式id生成器

分布式id生成器在稍微规模大一点的公司,基本上都会有的,网上的样例也比较多,本编主要讲的是公司内的一些使用吧,大家影响可能更深刻一点。 分布式id有哪些要求呢? 全局唯一性:不能出现重复的ID号,既然是唯一标识,这是最基本的要求。 趋势递增:在MySQL InnoDB引擎中使用的是聚集索引,由于多数RDBMS使用B-tree的数据结构来存储索引数据,在主键的选择上面我们应该尽量使用有序的主键保证写入性能。 单调递增:保证下一个ID一定大于上一个ID,例如事务版本号、IM增量消息、排序等特殊需求。

u014274324的专栏 601

如何设计一个分布式ID生成器?(如雪花算法Snowflake)

由Sony公司开源,是对雪花算法的变种。它同样是64位,但调整了位数分配:39位时间戳(单位为10毫秒,因此可用年限更长,约174年)、8位序列号、16位机器ID,以及1位预留。其时钟回拨处理策略是直接等待时钟追赶。ULID是一个128位的ID,由48位的时间戳(毫秒精度)和80位的随机数组成。它既能保证按时间排序(字典序),又因为有大量的随机数部分,使其难以被猜测。它对时钟回拨不敏感,因为同一毫秒内生成的ID因随机数不同而不同。

破损的天堂鸟博客 822

架构师究竟要不要懂细节?分布式ID生成的6种方法(第45讲)

假设系统至少运行10年,那至少需要10年*365天*24小时*3600秒*1000毫秒=320*10^9,差不多预留39bit给毫秒数。每秒的单机高峰并发量小于10W,即平均每毫秒的单机高峰并发量小于100,差不多预留7bit给每毫秒内序列号。,1024台机器(服务)每秒能生活40Y的ID,完全能满足业务的需求。其四,每个机房机器小于100台,预留7bit给每个机房内的服务器标识。是一个本地算法,生成性能高,但无法保证趋势递增,且作为字符串。,例如:消息ID,订单ID,帖子ID...

shenjian58的博客 2189

唯一Id生成器

基于 Redis 的全局唯一性ID生成器的一些实现思路 干货 | 分布式架构系统生成全局唯一序列号的一个思路 丁宜人 携程技术中心 分布式ID生成器 | 架构师之路 58沈剑 架构师之路 ...

kabcko的博客 792
上一篇: HTTPS 原理解析
下一篇: Docker安装Elasticsearch和Elasticsearch-Head以及IK分词器
王树民
博客等级 码龄10年 912粉丝 560原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值