谈谈分布式ID生成器

在后端开发中,唯一 ID 是一个基础而关键的需求。无论是用户注册时生成的用户 ID、下单时的订单号,还是日志系统中的 TraceId,唯一 ID 都承担着 数据唯一标识 的核心作用。
在单体应用时代,很多系统直接依赖数据库的自增主键来生成 ID,这种方式简单易用,能够满足小规模系统的需求。但随着系统规模不断扩大,传统自增ID逐渐暴露出数据泄露风险、分库分表困难、性能瓶颈等严重问题,促使我们寻找更适合分布式环境的ID生成方案。

常见分布式唯一 ID 方案

一、自增ID

利用数据库的 AUTO_INCREMENT 实现,这是最直观的ID生成方式,也是初学者的首选方案。

CREATE TABLE user (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50) NOT NULL
);

优点 :实现简单,性能良好,ID具有递增特性,适合作为数据库主键。
缺点

  • 安全风险 :自增ID具有明显的规律性,容易被恶意用户通过枚举方式获取敏感数据,存在严重的数据泄露风险
  • 分库分表困难 :在分布式环境下,多个数据库实例的自增ID可能发生冲突,需要引入复杂的分配策略(如库号 + 表号拼接)
  • 扩展性限制 :单点依赖数据库,无法满足高并发场景下的ID生成需求

二、UUID

UUID(Universally Unique Identifier)是一种标准化的128位标识符,通过Java官方的 java.util.UUID.randomUUID() 方法可以轻松生成全局唯一的ID。

import java.util.UUID;

public class UUIDExample {
    public static void main(String[] args) {
        String id = UUID.randomUUID().toString();
        System.out.println(id); // 输出类似:550e8400-e29b-41d4-a716-446655440000
    }
}

优点

  • 全局唯一性 :基于时间戳、随机数和MAC地址生成,理论上保证全局唯一
  • 安全性 :无序特性使其难以被枚举攻击
  • 无中心化 :无需依赖外部服务,本地即可生成

缺点

  • 存储开销 :长度较长(36个字符),占用更多存储空间
  • 索引性能 :无序特性导致B+树索引频繁分裂,严重影响数据库写入和查询性能
  • 业务适用性 :不具备时间递增性,不适合需要按时间排序的业务场景

三、雪花ID(Snowflake)

主要组成:img

  • 固定值 :符号位
  • 时间戳 :调用时间戳(ms)减去程序设计时间戳的差值
  • 机器id 、服务id:区别不同的生成机器
  • 序号 :同一毫秒的自增位数

雪花Id基本能应付大多数业务开发场景,能够保证:
优点

  • 高性能 :本地生成,无网络开销,单机QPS可达百万级别
  • 趋势递增 :时间戳在前,保证ID整体递增,适合数据库主键
  • 分布式友好 :通过机器ID保证不同节点生成的ID唯一性
  • 存储高效 :64位长整型,存储空间占用小

缺点

  • 时钟依赖 :严重依赖系统时钟,时钟回拨可能导致ID重复
  • 机器ID管理 :需要为每台机器分配唯一的机器ID,增加运维复杂度

方案对比

方案 性能 唯一性 有序性 存储开销 适用场景
自增ID 单库唯一 严格递增 小规模单体应用
UUID 全局唯一 无序 对性能要求不高的场景
雪花ID 极高 分布式唯一 趋势递增 大规模分布式系统