全网最全的分布式ID生成方案解析

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
注册配置 MSE Nacos/ZooKeeper,182元/月
简介: 全网最全的分布式ID生成方案解析

通过本文可以学到什么

  • 什么是全局唯一ID
  • 全局唯一ID特点
  • 常见的全局唯一ID策略

什么是全局唯一ID

全局唯一ID也就是分布式ID,拿MySQL举个例子,在我们项目初期,数据量不大的时候,单库单表已经可以满足我们的业务需求,数据库稍微在增加些使用MySQL主从也读写分离也可以满足。

随着数据量的增加,在主从同步也无法抗住业务压力的时候,此时我们对数据库进行了分库分表,而分库分表就需要一个全局的唯一ID来满足业务的需求,很显然数据库本身的自增ID是无法满足我们的需求的,所以此时就出现了全局唯一ID这个概念,也就是对应于我们分布式系统中的分布式ID

下面让我们看一下全局唯一ID的特点都是有什么?

全局唯一ID的特点

  • 全局唯一:全局(分库分表之后的全局唯一),不能出现重复的ID,这是最基本的要求
  • 单调递增或者趋势递增:在主键的选择上面我们应该尽量使用有序的主键保证写入性能,保证下一个ID一定大于上一个ID,可以满足我们业务中的大部分特殊需求,比如排序,事务版本号
  • 高性能/高可用:ID生成响应要快,不能有单点故障,否则会成为业务瓶颈
  • 信息安全:如果ID是连续的,容易暴漏业务量,所以个别场景下需要ID无规则
  • 好接入:最好是拿来即用,在系统设计和实现上尽可能的简单
  • 分片支持:最后能够控制分片,比如某一个用户的所有内容都路由到同一个分片
  • 长度适中

上面了解了全局唯一ID的特点之后,下一步就应该知道我们业务中现在常用的全局唯一ID策略都是有哪几种,下面跟随我的脚步带你熟悉常见的全局唯一ID策略

常见全局唯一ID策略

数据库自增长序列或字段

最常见的方式,利用数据库实现全数据库唯一

优点:

  • 简单,代码实现方便,性能也能接受
  • 生成的ID天然有序,对分页或者需要排序的业务结果很有帮助

缺点:

  • 不同数据库语法或实现不同,数据库迁移的时候需要处理
  • 在单个数据库或读写分离或一主多从多情况下,只有一个主库可以生成ID,有单点故障的风险
  • 在性能达不到要求的情况下比较难以扩展
  • 数据迁移或者系统数据合并比较麻烦
  • 分库分表时会比较麻烦

优化方案:

针对主库单点问题,如果有多个主库,可以让每个主库单起始数字不一样,步长一样,可以是主库的个数。比如主库1生成1,4,7,10,主库2生成2,5,8,11,主库3生成3,6,9,12.这样就可以生成集群中的唯一ID,也可以大大降低ID生成数据库的负载。

  • 基于数据库集群模式

单点数据库性能不够好,容易有宕机风险的话此时就可以改为集群模式,双主模式或者主从模式,也就是两个数据库实例都可以单独生成ID

此时,还会有另一个问题,就是两个数据都生成id,生成的ID重复怎么办,此时就可以使用设置自增步长和起始值

实例1设置起始值1,步长为2

实例2设置起始值2,步长2

这样两个数据库实例生成的ID就为

1,3,5,7,9
2,4,6,8,10

此时,如果双主集群还是无法扛住高并发,就要考虑增加数据库节点,此时的自增步长就要设置为数据库实例的数量

此时还能再优化就是基于数据库的号段模式

  • 基于数据库的号段模式
    号段模式是当下分布式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`)
)
  • Bit_type :代表不同的业务类型
    max_id:当前最大的可用ID
    step:代表号段的长度
    version:乐观锁,每次都更新version,保证并发时数据正确性
id Bit_type Max_id Step Version
1 1001 1000 2000 0
  • 等这批号段用完,在向数据库申请新号段,对max_id做一次更新操作,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="具体业务代码"
  • 由于会有多业务端同时操作,所以采用乐观锁的方式更新,这种分布式id生成方式不强依赖数据库,不会频繁的访问数据库,对数据库的压力小很多
  • 基于Redis模式
    原理是使用redis的incr命令实现原子自增
    使用redis,要考虑的就是redis的持久化问题,redis有两种持久化方式,AOF和RDB
    AOF:会对每条命令进行持久化,但是由于incr,会造成aof文件很大,初始化加载缓慢,不过Redis有aof文件重写优化,命令合并重写aof文件
    RDB:redis定时做一个快照,在redis宕机之后,会有ID重复的问题

UUID

常见的 主键生成方式,可以利用数据库生成或者程序生成

优点:

  • 简单,代码方便
  • 生成ID性能好,基本不会有性能问题
  • 全局唯一,遇见数据迁移的场景,系统数据合并,或者数据库变更的情况下,可以从容应对。

缺点:

  • 没有排序,无法保证递增
  • UUID一般是字符串存储,查询效率较低
  • 存储占用空间大,如果是海量数据库,还需要考虑存储量的问题
  • 传输数据量大
  • 可读性差

UUID的变种

  • 为了解决UUID的不可读性,可以使用生成有序的UUID

Zookeeper生成ID

  • zookeeper主要通过其znode版本号来生成序列号,客户端可以使用这个版本号当作分布式id
  • 也可以根据zookeeper的持久顺序节点的特性,多个客户端同时创建一个节点,zk能保证有序的创建,此时创建成功之后返回的path就可以取出来当作分布式id

很少会选用zk来生成分布式id,主要是由于需要依赖zookeeper,如果在竞争较大时,还需要考虑使用分布式锁,因此,在高并发环境中,并不是很理想

Mongdb ObjectId

官网Objectid链接

Objectid 很小,可能是唯一的,生成速度快,有序,长度12个字节,包括

  • 一个4字节的时间戳,代表创建时间,以Unix依赖的秒数为单位
  • 没个进程生成一个5字节的随机数,这个随机值对于机器和过程是唯一的
  • 一个3字节的递增计数器,初始化为随机值

雪花算法

github地址

  • 描述snowflake 是Twitter开源的分布式ID生成算法,结果是一个long型的ID,核心思想是:
  • 41bit毫秒数
  • 10bit机器id(5个bit数据中心,5个bit机器id)
  • 12bit毫秒内的流水号(就是说支持每个节点每毫秒产生4096个序列号,1<<12=4096)
  • 第一位符号位,永远是0
  • 优点
    雪花算法是使用数据中心id和机器id来作为标识,不会产生重复的id,并且也是在本地生成,效率高。
  • 缺点
  • 缺点就是有可能发生时钟回拨,因为雪花算法的计算依赖与实践,若是发生系统时间回拨,就会产生重复id情况。id可能不是全局递增,在单机上面是递增的,但是由于涉及到分布式环境,每台机器上的时钟不可完全同步,也许有时候也会出现不是全局递增的情况
  • 机器id分配与回收问题:机器id需要每台机器不一样,这样的分配方式需要有方案进行处理,同时也要考虑宕机之后的处理,如果宕机了对应的id分配后的回收问题
  • 机器id的上限问题,机器id是固定的bit,那么对应的机器个数是有上限的,在有些业务场景下,需要所有的机器共享同一个业务空间,那么机器的数量是有限制的
  • 解决
  • 时钟回拨
  • 直接抛异常,很粗暴,不友好
  • 采用等待跟上次时间的一段范围,这种算是简单解决,可以接受的情况,但是要是等待一段时间之后又发生了时钟回拨,则抛异常,可以接受只能说是不算完全解决
  • 机器id分配与回收
  • 采用zookeeper的顺序节点分配,解决分配。回收采用zookeeper临时节点回收,但是临时节点不可靠,存在无故消失问题,因为也不是很可靠
  • 采用中数据库中插入数据作为节点值,解决了分配,但是没有解决回收
  • 机器id上限
    如果采用雪花算法这也是不可避免的。不过这种场景也只有在大量的业务机器在一个共享的场景才会出现,这种情况可以采用客户端双buffer+db的这种非雪花算法也并不是不行

百度UidGenerator

github地址

uid-generator是基于snowflake算法实现的,与snowflake算法不同的是uid-generator支持自定义时间戳,工作机器id和序列号等各部分的位数,而且uid-generator采用用户自定义workid的生成策略

uid-generator需要与数据库配合使用,需要新增一个worker_node表,当应用启动时会向数据库表中插入一条数据,插入成功后返回的自增id就是该机器的workid,数据有host,port组成

  • 组成
  • sign(1bit)
    固定1bit符号标识,即生成的UID为正数。
  • delta seconds (28 bits)
    当前时间,相对于时间基点"2016-05-20"的增量值,单位:秒,最多可支持约8.7年
  • worker id (22 bits)
    机器id,最多可支持约420w次机器启动。内置实现为在启动时由数据库分配,默认分配策略为用后即弃,后续可提供复用策略。
  • sequence (13 bits)
    每秒下的并发序列,13 bits可支持每秒8192个并发
  • workId,占用了22个bit位,时间占用了28个bit位,序列化占用了13个bit位,需要注意的是,和原始的snowflake不太一样,时间的单位是秒,而不是毫秒,workId也不一样,而且同一应用每次重启就会消费一个workId

美团Leaf

github地址

Leaf支持两种方式,号段方式和snowflake模式,可以同时开启两种模式,也可以指定开启哪种模式,默认两种关闭

滴滴Tinyid

github

Tinyid是用Java开发的一款分布式id生成系统,基于数据库号段算法实现,关于这个算法可以参考美团leaf或者tinyid原理介绍。Tinyid扩展了leaf-segment算法,支持了多db(master),同时提供了java-client(sdk)使id生成本地化,获得了更好的性能与可用性。Tinyid在滴滴客服部门使用,均通过tinyid-client方式接入,每天生成亿级别的id。

特点

  • 全局唯一的long型id
  • 趋势递增的id,即不保证下一个id一定比上一个大
  • 非连续性
  • 提供http和java client方式接入
  • 支持批量获取id
  • 支持生成1,3,5,7,9…序列的id
  • 支持多个db的配置,无单点

适用场景:只关心id是数字,趋势递增的系统,可以容忍id不连续,有浪费的场景

不适用场景:类似订单id的业务(因为生成的id大部分是连续的,容易被扫库、或者测算出订单量)

原文链接

关注公众号 获取更多学习资料

回复面试获取面试宝典


目录
相关文章
|
5月前
|
安全 JavaScript 前端开发
HarmonyOS NEXT~HarmonyOS 语言仓颉:下一代分布式开发语言的技术解析与应用实践
HarmonyOS语言仓颉是华为专为HarmonyOS生态系统设计的新型编程语言,旨在解决分布式环境下的开发挑战。它以“编码创造”为理念,具备分布式原生、高性能与高效率、安全可靠三大核心特性。仓颉语言通过内置分布式能力简化跨设备开发,提供统一的编程模型和开发体验。文章从语言基础、关键特性、开发实践及未来展望四个方面剖析其技术优势,助力开发者掌握这一新兴工具,构建全场景分布式应用。
507 35
|
9月前
|
数据可视化 前端开发 测试技术
接口测试新选择:Postman替代方案全解析
在软件开发中,接口测试工具至关重要。Postman长期占据主导地位,但随着国产工具的崛起,越来越多开发者转向更适合中国市场的替代方案——Apifox。它不仅支持中英文切换、完全免费不限人数,还具备强大的可视化操作、自动生成文档和API调试功能,极大简化了开发流程。
|
5月前
|
人工智能 负载均衡 Java
Spring AI Alibaba 发布企业级 MCP 分布式部署方案
本文介绍了Spring AI Alibaba MCP的开发与应用,旨在解决企业级AI Agent在分布式环境下的部署和动态更新问题。通过集成Nacos,Spring AI Alibaba实现了流量负载均衡及节点变更动态感知等功能。开发者可方便地将企业内部业务系统发布为MCP服务或开发自己的AI Agent。文章详细描述了如何通过代理应用接入存量业务系统,以及全新MCP服务的开发流程,并提供了完整的配置示例和源码链接。未来,Spring AI Alibaba计划结合Nacos3的mcp-registry与mcp-router能力,进一步优化Agent开发体验。
2000 15
|
5月前
|
NoSQL 算法 安全
redis分布式锁在高并发场景下的方案设计与性能提升
本文探讨了Redis分布式锁在主从架构下失效的问题及其解决方案。首先通过CAP理论分析,Redis遵循AP原则,导致锁可能失效。针对此问题,提出两种解决方案:Zookeeper分布式锁(追求CP一致性)和Redlock算法(基于多个Redis实例提升可靠性)。文章还讨论了可能遇到的“坑”,如加从节点引发超卖问题、建议Redis节点数为奇数以及持久化策略对锁的影响。最后,从性能优化角度出发,介绍了减少锁粒度和分段锁的策略,并结合实际场景(如下单重复提交、支付与取消订单冲突)展示了分布式锁的应用方法。
369 3
|
8月前
|
机器学习/深度学习 人工智能 自然语言处理
企业级API集成方案:基于阿里云函数计算调用DeepSeek全解析
DeepSeek R1 是一款先进的大规模深度学习模型,专为自然语言处理等复杂任务设计。它具备高效的架构、强大的泛化能力和优化的参数管理,适用于文本生成、智能问答、代码生成和数据分析等领域。阿里云平台提供了高性能计算资源、合规与数据安全、低延迟覆盖和成本效益等优势,支持用户便捷部署和调用 DeepSeek R1 模型,确保快速响应和稳定服务。通过阿里云百炼模型服务,用户可以轻松体验满血版 DeepSeek R1,并享受免费试用和灵活的API调用方式。
506 12
|
8月前
|
存储 人工智能 并行计算
2025年阿里云弹性裸金属服务器架构解析与资源配置方案
🚀 核心特性与技术创新:提供100%物理机性能输出,支持NVIDIA A100/V100 GPU直通,无虚拟化层损耗。网络与存储优化,400万PPS吞吐量,ESSD云盘IOPS达100万,RDMA延迟<5μs。全球部署覆盖华北、华东、华南及海外节点,支持跨地域负载均衡。典型应用场景包括AI训练、科学计算等,支持分布式训练和并行计算框架。弹性裸金属服务器+OSS存储+高速网络综合部署,满足高性能计算需求。
|
9月前
|
机器学习/深度学习 传感器 人工智能
穹彻智能-上交大最新Nature子刊速递:解析深度学习驱动的视触觉动态重建方案
上海交大研究团队在Nature子刊发表论文,提出基于深度学习的视触觉动态重建方案,结合高密度可拉伸触觉手套与视觉-触觉联合学习框架,实现手部与物体间力量型交互的实时捕捉和重建。该方案包含1152个触觉感知单元,通过应变干扰抑制方法提高测量准确性,平均重建误差仅1.8厘米。实验结果显示,其在物体重建的准确性和鲁棒性方面优于现有方法,为虚拟现实、远程医疗等领域带来新突破。
202 32
|
7月前
|
开发框架
osharp集成Yitter.IdGenerator并实现分布式ID
本文介绍了在 osharp 框架中集成 Yitter.IdGenerator 实现分布式 ID 的方法。osharp 是一个基于 .NET Core 的快速开发框架,而 Yitter.IdGenerator 是一种高效的分布式 ID 生成器。通过实现 `IKeyGenerator&lt;long&gt;` 接口并创建 `YitterSnowKeyGenerator` 类,结合 `YitterIdGeneratorPack` 模块化配置,实现了分布式环境下唯一 ID 的生成。
141 0
|
10月前
|
存储 SpringCloudAlibaba Java
【SpringCloud Alibaba系列】一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论
一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论。
【SpringCloud Alibaba系列】一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论
|
9月前
|
存储 分布式计算 Hadoop
基于Java的Hadoop文件处理系统:高效分布式数据解析与存储
本文介绍了如何借鉴Hadoop的设计思想,使用Java实现其核心功能MapReduce,解决海量数据处理问题。通过类比图书馆管理系统,详细解释了Hadoop的两大组件:HDFS(分布式文件系统)和MapReduce(分布式计算模型)。具体实现了单词统计任务,并扩展支持CSV和JSON格式的数据解析。为了提升性能,引入了Combiner减少中间数据传输,以及自定义Partitioner解决数据倾斜问题。最后总结了Hadoop在大数据处理中的重要性,鼓励Java开发者学习Hadoop以拓展技术边界。
281 7

热门文章

最新文章

推荐镜像

更多
  • DNS