0

0

在MySQL中生成唯一分布式ID的多种方案与对比(UUID, Snowflake)

紅蓮之龍

紅蓮之龍

发布时间:2025-09-10 09:59:01

|

671人浏览过

|

来源于php中文网

原创

答案:UUID和Snowflake是生成分布式ID的两种常见方案,UUID简单但无序且占用空间大,Snowflake趋势递增利于索引但实现复杂需处理时钟回拨;数据库自增+步长和Redis自增也适用不同场景,选择需权衡性能、有序性、可用性和复杂度。

在mysql中生成唯一分布式id的多种方案与对比(uuid, snowflake)

生成唯一分布式ID,在MySQL中,主要目标是保证在大规模分布式系统中ID的全局唯一性和高并发下的生成效率。UUID和Snowflake是两种常见的选择,但各有优劣。

UUID虽然简单易用,但其无序性可能导致数据库索引效率降低,占用存储空间也较大。Snowflake算法则能生成趋势递增的ID,有利于数据库索引优化,但实现相对复杂,需要考虑时钟回拨等问题。

解决方案

  1. UUID (Universally Unique Identifier)

    • 原理: 基于时间戳、MAC地址、随机数等生成,保证在理论上的全局唯一性。

    • 优点: 简单易用,MySQL内置函数

      UUID()
      即可生成。

    • 缺点:

      • 无序性: 插入数据库时可能导致页分裂,影响写入性能,特别是对于InnoDB引擎。
      • 空间占用: 128位,占用空间较大。
      • 可读性差: 不易于人工识别和调试。
    • 适用场景: 对ID的有序性要求不高,且数据量较小的场景。例如,作为某些非关键业务的ID。

    • 示例:

      SELECT UUID();
      -- 输出:'a1b2c3d4-e5f6-7890-1234-567890abcdef'
  2. Snowflake算法

    • 原理: 生成一个64位的Long型ID,通常由以下几部分组成:

      • 符号位 (1 bit): 通常为0,表示正数。
      • 时间戳 (41 bits): 记录毫秒级的时间戳,可以支持约69年的时间。
      • 工作机器ID (10 bits): 用于区分不同的机器节点,最多支持1024个节点。
      • 序列号 (12 bits): 用于在同一毫秒内生成不同的ID,每毫秒最多生成4096个ID。
    • 优点:

      • 趋势递增: 有利于数据库索引优化,减少页分裂。
      • 高并发: 可以在同一毫秒内生成多个ID。
      • 可扩展性: 可以通过增加机器节点来提高ID生成能力。
    • 缺点:

      • 实现复杂: 需要自己编写代码实现,或者使用现成的开源库。
      • 时钟回拨问题: 如果服务器时钟发生回拨,可能导致生成重复的ID。需要进行处理。
    • 适用场景: 对ID的有序性和性能要求较高,且数据量较大的场景。例如,订单ID、用户ID等。

    • 示例 (Java实现):

      public class SnowflakeIdWorker {
      
          private long workerId;
          private long datacenterId;
          private long sequence = 0L;
      
          private long twepoch = 1288834974657L;
      
          private long workerIdBits = 5L;
          private long datacenterIdBits = 5L;
          private long maxWorkerId = -1L ^ (-1L << workerIdBits);
          private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
          private long sequenceBits = 12L;
      
          private long workerIdShift = sequenceBits;
          private long datacenterIdShift = sequenceBits + workerIdBits;
          private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
          private long sequenceMask = -1L ^ (-1L << sequenceBits);
      
          private long lastTimestamp = -1L;
      
          public SnowflakeIdWorker(long workerId, long datacenterId) {
              if (workerId > maxWorkerId || workerId < 0) {
                  throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
              }
              if (datacenterId > maxDatacenterId || datacenterId < 0) {
                  throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
              }
              this.workerId = workerId;
              this.datacenterId = datacenterId;
          }
      
          public synchronized long nextId() {
              long timestamp = timeGen();
      
              if (timestamp < lastTimestamp) {
                  throw new RuntimeException(
                          String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
              }
      
              if (lastTimestamp == timestamp) {
                  sequence = (sequence + 1) & sequenceMask;
                  if (sequence == 0) {
                      timestamp = tilNextMillis(lastTimestamp);
                  }
              } else {
                  sequence = 0L;
              }
      
              lastTimestamp = timestamp;
      
              return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
          }
      
          protected long tilNextMillis(long lastTimestamp) {
              long timestamp = timeGen();
              while (timestamp <= lastTimestamp) {
                  timestamp = timeGen();
              }
              return timestamp;
          }
      
          protected long timeGen() {
              return System.currentTimeMillis();
          }
      }
  3. 数据库自增ID + 步长

    • 原理: 利用MySQL的自增ID特性,并设置合适的步长,分配给不同的机器节点。

    • 优点: 简单易用,不需要额外的代码实现。

    • 缺点:

      • 依赖数据库: 依赖数据库的可用性,如果数据库出现故障,则无法生成ID。
      • 扩展性有限: 扩展机器节点需要修改数据库配置。
      • ID连续性: ID不是完全连续的,因为每个节点分配的ID之间存在步长。
    • 适用场景: 对ID的连续性要求不高,且机器节点数量较少的场景。

    • 示例:

      • 节点1:
        AUTO_INCREMENT = 1, INCREMENT = 2
      • 节点2:
        AUTO_INCREMENT = 2, INCREMENT = 2

      这样,节点1生成的ID为1, 3, 5, 7...,节点2生成的ID为2, 4, 6, 8...。

      SoftGist
      SoftGist

      SoftGist是一个软件工具目录站,每天为您带来最好、最令人兴奋的软件新产品。

      下载
  4. Redis自增ID

    • 原理: 使用Redis的

      INCR
      命令,实现原子性的自增操作。

    • 优点:

      • 高性能: Redis的读写性能非常高,可以满足高并发的需求。
      • 简单易用: Redis的API非常简单,容易上手。
    • 缺点:

      • 依赖Redis: 依赖Redis的可用性,如果Redis出现故障,则无法生成ID。
      • ID连续性: ID是连续的,但如果Redis重启,可能会丢失一部分ID。
    • 适用场景: 对ID的连续性要求不高,且需要高性能的场景。

    • 示例:

      Jedis jedis = new Jedis("localhost", 6379);
      Long id = jedis.incr("order_id");
      jedis.close();
      System.out.println("Generated ID: " + id);

如何选择合适的ID生成方案?

选择哪种方案,需要综合考虑以下因素:

  • 性能要求: 高并发场景下,Snowflake或Redis自增ID更适合。
  • 有序性要求: 需要ID有序的场景,Snowflake或数据库自增ID更适合。
  • 可用性要求: 对可用性要求高的场景,需要考虑数据库或Redis的容错机制。
  • 复杂度: UUID最简单,Snowflake实现最复杂。
  • 数据量: 数据量较小的场景,UUID可能就足够了。

Snowflake算法如何解决时钟回拨问题?

时钟回拨是指服务器的时间突然倒退的现象。这可能会导致Snowflake算法生成重复的ID。常见的解决方案有:

  1. 等待: 当检测到时钟回拨时,暂停ID生成,等待时钟追赶上来。
  2. 使用备用时间戳: 记录上次正常的时间戳,当检测到回拨时,使用备用时间戳生成ID。
  3. 抛出异常: 直接抛出异常,通知开发人员处理。

具体选择哪种方案,取决于业务的容错性和对ID唯一性的要求。

数据库自增ID的步长如何设置?

步长的设置需要根据机器节点的数量来确定。假设有N个机器节点,则步长应该设置为N。这样可以保证每个节点分配的ID是唯一的。例如,如果有3个节点,则步长设置为3,每个节点的起始ID分别为1, 2, 3。

UUID作为主键的替代方案

虽然UUID作为主键有一些缺点,但也有一些优化方案可以缓解这些问题:

  1. 使用UUIDv6/v7/v8: 这些新版本的UUID尝试解决UUIDv4的无序性问题,通过将时间戳信息放在UUID的前面部分,使其具有一定的有序性。
  2. 将UUID转换为二进制存储: MySQL的
    BINARY(16)
    类型可以更高效地存储UUID,减少存储空间。
  3. 使用代理键: 使用自增ID作为主键,UUID作为唯一索引,用于外部系统集成。

除了UUID和Snowflake,还有其他方案吗?

除了上述方案,还有一些其他的ID生成方案,例如:

  • Leaf: 美团开源的分布式ID生成系统,支持多种ID生成策略。
  • UidGenerator: 百度开源的分布式ID生成器。
  • MongoDB ObjectId: MongoDB自带的ObjectId,具有一定的唯一性和有序性。

选择哪种方案,需要根据具体的业务场景和技术栈来决定。

如何监控ID生成系统的健康状况?

监控ID生成系统的健康状况非常重要,可以及时发现和解决问题。常见的监控指标包括:

  • ID生成速度: 监控每秒生成的ID数量。
  • 错误率: 监控ID生成过程中出现的错误数量。
  • 延迟: 监控ID生成的延迟。
  • 资源使用率: 监控CPU、内存、磁盘等资源的使用率。

可以使用Prometheus、Grafana等监控工具来收集和展示这些指标。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
mysql修改数据表名
mysql修改数据表名

MySQL修改数据表:1、首先查看数据库中所有的表,代码为:‘SHOW TABLES;’;2、修改表名,代码为:‘ALTER TABLE 旧表名 RENAME [TO] 新表名;’。php中文网还提供MySQL的相关下载、相关课程等内容,供大家免费下载使用。

668

2023.06.20

MySQL创建存储过程
MySQL创建存储过程

存储程序可以分为存储过程和函数,MySQL中创建存储过程和函数使用的语句分别为CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句调用存储过程智能用输出变量返回值。函数可以从语句外调用(通过引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。php中文网还提供MySQL创建存储过程的相关下载、相关课程等内容,供大家免费下载使用。

247

2023.06.21

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

281

2023.07.18

mysql密码忘了怎么查看
mysql密码忘了怎么查看

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql密码忘了怎么办呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

515

2023.07.19

mysql创建数据库
mysql创建数据库

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql怎么创建数据库呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

256

2023.07.25

mysql默认事务隔离级别
mysql默认事务隔离级别

MySQL是一种广泛使用的关系型数据库管理系统,它支持事务处理。事务是一组数据库操作,它们作为一个逻辑单元被一起执行。为了保证事务的一致性和隔离性,MySQL提供了不同的事务隔离级别。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

386

2023.08.08

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

533

2023.08.11

mysql忘记密码
mysql忘记密码

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。那么忘记mysql密码我们该怎么解决呢?php中文网给大家带来了相关的教程以及其他关于mysql的文章,欢迎大家前来学习阅读。

602

2023.08.14

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

158

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.3万人学习

Node.js 教程
Node.js 教程

共57课时 | 9.6万人学习

CSS3 教程
CSS3 教程

共18课时 | 5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号