分布式ID生成方案

UUID

  • UUID由本地生成,没有网络消耗,而且代码实现简单,但它存储空间大,而且是无序的,不能保证趋势递增,mysql默认使用的是InnoDB存储引擎,它的主键索引采用的是B+树索引,无序而且过长的UUID不适合作为主键。

数据库自增ID

  • 通过MySQL的主键自增,也就是 auto_increment 来实现,以此来生成自增ID,优点是用现有的数据库系统来实现,成本小,实现简单;缺点是业务系统每次需要ID时,都要请求数据库,性能较低,对数据库压力大,高并发抗不住,而且由于强依赖于数据库,如果 mysql 挂了,就没法生成iD了。
  • 可以对这种方法进行改进:这种方法主要的问题是每次获取id,都要去数据库请求一次,性能较低,而且对数据库压力较大,可以修改为生成一个区间的id,放进JVM的内存中,这样就不需要每次都去请求数据库了,而是从JVM内存中获取id,比如这个区间先是1到1000,也就是步长是1000,等这个区间的id请求完后,再请求生成id服务,生成1001到2000区间的id,放到JVM内存中。这个改进方案在高并发场景下会存在问题,比如多个用户同时请求id,当它们同时请求完区间里的id时,会同时去请求id生成服务,此时就存在竞争了,只能有一个用户去请求id生成服务,其他用户服务被阻塞,导致性能降低。解决办法是采用双 buffer 的方案,首先请求生成id服务,比如生成1到1000范围的id,buffer1表示申请到了这个区间,并采用两个 int 来记录区间端点,每次获取id在 buffer1 表示的区间中获取,当 buffer1 中的id使用了10%后,请求生成id服务,生成1001到2000范围的id,由 buffer2 表示,如果 buffer1 用完了,就切换到 buffer2 表示的区间,buffer2 中的id使用了10%后,再次请求生成id服务,生成2001到3000范围的id,由 buffer1 表示,如此反复,这样就缓解了阻塞问题。

数据库多主模式

  • 指的是两个或多个主库都能单独生产自增ID,auto_increment_offset 设置起始值,auto_increment_increment 设置自增步长,给他们配置不同的起始值和自增步长,比如有两个主库的话,一个设置起始值为1,步长为2,一个设置起始值为2,步长为2,这样他们的自增id分别为奇数和偶数,不会重复,即使某一个主库挂掉了,也不会影响另外一个主库来生成id。缺点是扩展性不好,比如想再添加一个主库来提高性能的话,那么之前主库的自增规则都需要修改,避免和新主库产生的id重复。

Redis 生成

  • 利用 redis 的 incr 和 incrby 命令来实现原子性的自增,其中 incr 命令将 key 中存储的值加1,incrby 命令将 key 中存储的值加上指定的增量值。
  • 优点:有序,效率高。
  • 缺点:每次要向redis进行请求,有网络请求耗时,如果Redis挂了,就没法生成iD了,而且存在安全性问题,因为id是递增的,所以可以预测下一个id是多少;需要考虑持久化问题,redis支持RDB和AOF两种持久化方式。RDB持久化相当于定时打一个快照进行持久化,如果打完快照后,又连续自增了几次,但还没来得及打下一次快照,这个时候Redis挂掉了,重启Redis后会出现ID重复。AOF持久化相当于对每条写命令进行持久化,如果Redis挂掉了,不会出现ID重复的现象,但是会由于 incr 命令过多,导致重启恢复数据时间过长。

雪花算法

它是一种算法,不依赖数据库,核心思想是基于一个long类型的数来生成分布式id,一个long类型占8个字节,也就是64位,它划分为4个部分:

  • 第一部分是标识符,占1位,一般id为正数,所以始终为0;
  • 第二部分是时间戳,占41位,毫秒级别,存储的是当前时间和开始时间的差值,这样可以使产生的id从更小值开始。
  • 第三部分是工作机器id,占10位,可以部署1024个节点,如果机器分机房(IDC)部署,这10位可以由 5位机房ID + 5位机器ID 组成。
  • 第四部分是序列号,占12位,支持每个节点每毫秒可以生成4096个id序号。
  • 优点:性能好;时间戳在高位,自增序列在低位,整个ID是趋势递增的;灵活度高,可以根据业务需求调整 bit 位的划分。
  • 缺点:依赖机器的时钟,如果服务器时钟回拨,会导致重复ID生成。

在这里插入图片描述
在这里插入图片描述

<think>嗯,用户让我介绍分布式ID生成方案。我需要先理清楚分布式ID生成的基本概念常见方法。首先,分布式系统中生成唯一ID的挑战是什么?传统的自增ID在单机数据库中可以保证唯一,但在分布式环境下,多节点同时生成ID时会有冲突的可能,所以需要一种分布式的解决方案。 接下来,常见的方案有哪些呢?我记得有UUID、数据库自增、Snowflake算法、Redis生成,还有像Leaf这样的开源项目。需要逐一分析它们的优缺点。比如UUID虽然简单,但过长且无序,可能影响数据库索引效率。数据库自增需要维护一个中央数据库,可能成为单点故障,性能也有瓶颈。Snowflake算法利用时间戳、机器ID序列号,生成有序的ID,但机器ID的分配管理需要额外处理。 然后,用户可能需要了解每个方案的具体实现细节。比如Snowflake的结构,时间戳占多少位,机器ID如何分配,序列号的作用是什么。还有可能遇到的问题,比如时钟回拨对Snowflake的影响,以及如何解决这个问题,比如使用NTP同步或者预留位处理。 另外,用户可能关心不同方案的优缺点比较,以及适用场景。比如高并发下哪种方案更合适,是否需要趋势递增的特性,对存储空间的要求等等。可能需要举例说明,比如订单ID、日志跟踪等不同场景下的选择。 还要注意用户可能对某些技术细节不太清楚,需要用通俗易懂的语言解释,避免使用过多专业术语。同时,结构要清晰,分点说明,方便用户理解。比如分方案介绍,每个方案的结构、流程、优缺点,最后总结对比。 最后,是否需要提到一些新的方案或者变种,比如改进版的Snowflake,或者结合数据库缓存的方案,如Leaf-segmentLeaf-snowflake。可能还要提到第三方服务如美团的Leaf,百度的UidGenerator,避免重复造轮子。 需要检查是否符合用户给的系统级指令,比如数学公式是否正确用$包裹,独立公式用$$,中文回答,结构清晰。同时确保LaTeX语法正确,比如时间戳、机器ID序列号的位数表示是否正确,使用等宽字体或者代码块显示可能更好,但用户要求用LaTeX的话,需要用数学公式格式。 总结思考步骤:先介绍分布式ID的需求挑战,再分点讲解各方案的结构、流程、优缺点,最后对比总结,给出选型建议。确保每个部分都符合用户的格式要求,正确使用LaTeX,结构清晰。</think>以下是分布式ID生成方案的详细介绍,按常见方案分类说明: ### 一、需求背景 在分布式系统中,需要满足: 1. 全局唯一性 2. 趋势递增(利于数据库索引) 3. 高可用(QPS 10万+) 4. 可控制暴露信息(如避免连续数字暴露订单量) ### 二、常见方案对比 | 方案 | 优点 | 缺点 | |--------------------|-----------------------------|-----------------------------| | UUID | 简单、无中心化 | 无序、存储空间大(36字符) | | 数据库自增 | 绝对有序、易实现 | 存在单点故障风险、扩展性差 | | Snowflake | 高性能、可排序 | 依赖时钟、需管理机器ID | | Redis生成 | 高性能、可定制 | 依赖额外组件、维护成本高 | | Leaf-segment | 缓冲优化、高可用 | 需维护DB、存在号码段浪费 | ### 三、核心方案详解 #### 1. UUID $$ UUID示例:550e8400-e29b-41d4-a716-446655440000 $$ - 生成方式:标准RFC规范生成128位数字 - 缺点:无序性导致索引效率下降(B+树分裂) #### 2. 数据库自增 ```sql CREATE TABLE id_generator ( id int NOT NULL AUTO_INCREMENT, stub char(1) NOT NULL DEFAULT '', PRIMARY KEY (id), UNIQUE KEY stub (stub) ) ``` - 通过REPLACE INTO获取ID - 改进方案:多实例设置不同步长 $$ ID = n \times k + m $$ (n为实例数,k为步长,m为实例偏移量) #### 3. Snowflake算法 $$ ID = 时间戳 \times 2^{22} + 机器ID \times 2^{12} + 序列号 $$ - 位分配(64位): - 时间戳:41位(约69年) - 机器ID:10位(1024节点) - 序列号:12位(4096/ms) - 时钟回拨解决方案: - 物理时钟+逻辑时钟混合 - 故障时切换备用ID生成器 #### 4. Leaf方案(美团) **4.1 Leaf-segment** ```plantuml 客户端 -> Proxy: 获取ID段 Proxy -> DB: 更新max_id DB -> Proxy: 返回新号段 Proxy -> 客户端: 分配号段 ``` - 双Buffer优化:提前加载下一个号段 **4.2 Leaf-snowflake** - 改进点: - 使用ZK分配workerID - 时钟同步校验 - 异常时降级为号段模式 ### 四、选型建议 | 场景 | 推荐方案 | |----------------------|---------------------| | 中小型系统 | 改进版数据库自增 | | 高并发互联网业务 | Snowflake/Leaf | | 非结构化数据标识 | UUIDv4 | | 高可用性要求 | Redis集群+ Lua脚本 | ### 五、特殊场景处理 1. **环形缓冲区**:提前生成ID池应对突发流量 2. **业务标识嵌入**: $$ ID = 业务码 \times 10^n + 分布式ID $$ 3. **跨机房方案**:在机器ID中分配3位机房标识 ### 六、性能指标参考 - Snowflake单机吞吐量:约400万ID/秒 - Leaf-segment性能:1.2万QPS(号段长度1000) - Redis集群:可达10万+ QPS 建议根据实际业务规模选择方案,大型系统推荐优先考虑Snowflake及其改进方案
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值