当前位置: 首页 > news >正文

分布式ID生成方案详解与实战

分布式ID生成方案详解与实战

一、分布式ID概述

在分布式系统中,全局唯一ID是核心需求之一,用于标识业务实体。

1.1 ID生成要求

特性说明
唯一性全局唯一,永不重复
递增性按时间递增,便于排序
高性能高并发下低延迟
可扩展性支持水平扩展
安全性不可预测,防止枚举攻击

1.2 常见ID生成方案对比

方案优点缺点适用场景
数据库自增简单可靠单点瓶颈中小型系统
UUID无中心依赖无序、过长对ID有序性要求低
Snowflake高性能、有序依赖时钟分布式高并发
Redis自增高性能需要部署Redis缓存场景
数据库分段高可用实现复杂大型分布式系统

二、Snowflake算法

2.1 Snowflake结构

┌─────────────────────────────────────────────────────────────────────┐ │ 64位Snowflake ID │ ├─────────────────────────────────────────────────────────────────────┤ │ 1位 │ 41位时间戳 │ 10位机器ID │ 12位序列号 │ │ 符号 │ (毫秒级) │ (5位数据中心+5位工作节点) │ │ │ │ 可表示约69年 │ 支持1024个节点 │ 每毫秒4096个ID │ └─────────────────────────────────────────────────────────────────────┘

2.2 Java实现

public class SnowflakeIdGenerator { private final long twepoch = 1609459200000L; // 2021-01-01 00:00:00 private final long workerIdBits = 5L; private final long datacenterIdBits = 5L; private final long maxWorkerId = -1L ^ (-1L << workerIdBits); private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); private final long sequenceBits = 12L; private final long workerIdShift = sequenceBits; private final long datacenterIdShift = sequenceBits + workerIdBits; private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; private final long sequenceMask = -1L ^ (-1L << sequenceBits); private long workerId; private long datacenterId; private long sequence = 0L; private long lastTimestamp = -1L; public SnowflakeIdGenerator(long workerId, long datacenterId) { if (workerId > maxWorkerId || workerId < 0) { throw new IllegalArgumentException("Worker ID out of range"); } if (datacenterId > maxDatacenterId || datacenterId < 0) { throw new IllegalArgumentException("Datacenter ID out of range"); } this.workerId = workerId; this.datacenterId = datacenterId; } public synchronized long nextId() { long timestamp = timeGen(); if (timestamp < lastTimestamp) { throw new RuntimeException("Clock moved backwards"); } if (timestamp == lastTimestamp) { sequence = (sequence + 1) & sequenceMask; if (sequence == 0) { timestamp = tilNextMillis(lastTimestamp); } } else { sequence = 0L; } lastTimestamp = timestamp; return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence; } private long timeGen() { return System.currentTimeMillis(); } private long tilNextMillis(long lastTimestamp) { long timestamp = timeGen(); while (timestamp <= lastTimestamp) { timestamp = timeGen(); } return timestamp; } }

2.3 时钟回拨处理

public synchronized long nextId() { long timestamp = timeGen(); if (timestamp < lastTimestamp) { long offset = lastTimestamp - timestamp; if (offset <= 5) { try { wait(offset << 1); timestamp = timeGen(); if (timestamp < lastTimestamp) { throw new RuntimeException("Clock moved backwards"); } } catch (InterruptedException e) { throw new RuntimeException(e); } } else { throw new RuntimeException("Clock moved backwards too much"); } } if (timestamp == lastTimestamp) { sequence = (sequence + 1) & sequenceMask; if (sequence == 0) { timestamp = tilNextMillis(lastTimestamp); } } else { sequence = 0L; } lastTimestamp = timestamp; return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence; }

三、数据库自增ID

3.1 单库自增

CREATE TABLE `sequence` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `biz_type` VARCHAR(64) NOT NULL COMMENT '业务类型', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_biz_type` (`biz_type`) ) ENGINE=InnoDB AUTO_INCREMENT=100000 DEFAULT CHARSET=utf8mb4;

3.2 分段ID生成

public class SegmentIdGenerator { private volatile long currentId; private volatile long maxId; private final Object lock = new Object(); private final JdbcTemplate jdbcTemplate; public long nextId(String bizType) { if (currentId >= maxId) { synchronized (lock) { if (currentId >= maxId) { fetchSegment(bizType); } } } return ++currentId; } private void fetchSegment(String bizType) { String sql = "UPDATE sequence SET id = LAST_INSERT_ID(id + ?) WHERE biz_type = ?"; jdbcTemplate.update(sql, 1000, bizType); String querySql = "SELECT LAST_INSERT_ID()"; long newId = jdbcTemplate.queryForObject(querySql, Long.class); this.currentId = newId; this.maxId = newId + 1000 - 1; } }

3.3 多库多表方案

┌─────────────────────────────────────────────────────────────────┐ │ ID生成器集群 │ ├─────────────────────────────────────────────────────────────────┤ │ DB1: sequence_0 DB2: sequence_1 DB3: sequence_2 │ │ step=3, start=0 step=3, start=1 step=3, start=2 │ │ IDs: 0,3,6,9... IDs: 1,4,7,10... IDs: 2,5,8,11... │ └─────────────────────────────────────────────────────────────────┘

四、Redis自增ID

4.1 基本实现

public class RedisIdGenerator { private final StringRedisTemplate redisTemplate; private final String keyPrefix = "sequence:"; private final long step = 100; public long nextId(String bizType) { String key = keyPrefix + bizType; Long current = redisTemplate.opsForValue().increment(key); if (current <= step) { redisTemplate.opsForValue().set(key, String.valueOf(current + step * 10)); } return current; } }

4.2 Lua脚本保证原子性

local key = KEYS[1] local step = tonumber(ARGV[1]) local current = redis.call('INCR', key) if current <= step then redis.call('SET', key, current + step * 10) end return current

五、UUID方案

5.1 UUID生成

// 标准UUID String uuid = UUID.randomUUID().toString(); // 去除横线 String compactUuid = uuid.replace("-", ""); // 简化UUID(前8位) String shortUuid = compactUuid.substring(0, 8);

5.2 基于时间戳的UUID

public class TimeBasedUUIDGenerator { public String generate() { long timestamp = System.currentTimeMillis(); String timestampHex = Long.toHexString(timestamp); String randomPart = UUID.randomUUID().toString().substring(16); return timestampHex + randomPart; } }

六、美团Leaf方案

6.1 Leaf架构

┌─────────────────────────────────────────────────────────────┐ │ Leaf ID Generator │ ├─────────────────────────────────────────────────────────────┤ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Segment │ │ Snowflake │ │ DB Backup │ │ │ │ Mode │ │ Mode │ │ │ │ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ │ │ │ │ └──────────────────┴──────────────────┘ │ │ │ │ │ ▼ │ │ ┌───────────────┐ │ │ │ REST API │ │ │ └───────────────┘ │ └─────────────────────────────────────────────────────────────┘

6.2 Segment模式配置

leaf: segment: enable: true datasource: url: jdbc:mysql://localhost:3306/leaf?useUnicode=true&characterEncoding=utf-8 username: root password: password

6.3 Snowflake模式配置

leaf: snowflake: enable: true zk: address: localhost:2181 path: /leaf/snowflake

七、实战建议

7.1 方案选择策略

场景推荐方案原因
中小型系统数据库自增简单可靠,无需额外组件
高并发系统Snowflake高性能,毫秒级生成数万ID
跨数据中心Leaf/Snowflake支持多节点部署
对ID有序性要求高SegmentID连续递增

7.2 性能对比

方案QPS延迟(ms)优点缺点
Snowflake100万+<1极高性能依赖时钟
Redis50万+1-5高性能需要Redis
Segment10万+5-10ID连续依赖DB
UUID10万+<1无依赖无序、长

7.3 部署建议

  1. Worker ID分配:通过配置中心或ZK自动分配
  2. 时钟同步:使用NTP服务同步时间
  3. 容灾备份:部署多节点,支持故障转移
  4. 监控告警:监控ID生成速率、异常情况

八、总结

分布式ID生成方案需要根据业务场景选择:

  • Snowflake适合高并发、对ID有序性有要求的场景
  • Segment适合需要连续ID的场景
  • UUID适合对ID无特殊要求的场景
  • Redis适合缓存场景或已有Redis集群的系统

通过合理选择和配置,可以构建可靠、高性能的分布式ID生成系统。

http://www.jsqmd.com/news/864525/

相关文章:

  • Go 微服务必备:服务发现、配置中心、中间件是怎么协作的?
  • ElevenLabs接入云南话语音合成:从零部署到商用上线的7大关键配置(含昆明/大理/红河三地方言音素映射表)
  • 潮州话TTS落地最后一公里:ElevenLabs音频后处理秘技(含潮汕童谣节奏建模与语义停顿注入)
  • Python Selenium 瀏覽器自動化測試工具
  • 职场新人不会写自我介绍怎么办?AI三分钟帮你搞定,面试邀约直接翻倍!
  • 分享一个专门用于 SAP 开发的 Claude Code Skill 插件集合
  • 端侧AI基础设施:核心环节与代表企业
  • 裸辞转行AI大模型:我的探索与收获,收藏这份经验助你启程!
  • 大模型赋能政务审批:从 “人工审” 到 “智能核”
  • 如果你还在为CAD、SolidWorks的许可发愁,看看这八家
  • 406_C++_磁盘检查流程安全重构分析:从 system/popen 到 fork/exec 的防命令注入升级
  • 观察不同模型在 Taotoken 平台上的响应速度与效果差异
  • 独立开发者如何借助taotoken以更低成本启动ai项目
  • 时序例外:false_path / multicycle_path / max_delay
  • 新手程序员必备:收藏这份GPT大模型学习指南,从入门到精通!
  • 2026企业网盘选型指南:外部协作可控、合规审计、版本追溯的8款测评盘点
  • 昇腾CANN实战:FlashAttention 在昇腾NPU上的实现与性能调优
  • Spek音频频谱分析器:完整指南与实用技巧
  • GitLab CI|CD 配置笔记
  • 游戏化编程教学系统CodeCombat本地化部署实战:构建高效稳定的离线学习环境
  • 2026网盘怎么选:别只盯“不限速”,更该看同步稳定性与数据安全
  • 我用可视化工作流搭了一个发票识别助手,顺便聊聊 AI Agent 落地的那些弯路
  • 2026年AI编程助手综合实力排行榜
  • MySQL 索引数据结构与算法
  • 终极免费桌面分区工具NoFences:告别Windows桌面混乱的完整解决方案
  • 前端工程化:React + TypeScript + Tailwind CSS 的组件化实践
  • AI多模态时代来临:Google引领变革,Minimax有望成投资新宠
  • 免费专业浏览器扩展:Markdown Viewer的7大实用功能全解析
  • APP聊天服务器基本配置完成
  • 企业网盘怎么选?从同步效率、权限、安全合规到协作:2025横评清单