【Redis进阶篇|第十四篇】redis构建全局唯一ID

1. 什么是全局唯一ID

全局唯一ID(Globally Unique Identifier)是指在分布式系统、多服务、多数据库等跨节点环境中,能够保证全局范围内不重复的标识符。它通常用于主键、订单号、消息ID、用户ID等场景,是分布式架构中数据一致性、链路追踪和业务去重的基础。

一个合格的全局唯一ID通常需要满足以下几个特性:

  • 全局唯一性:在任何节点、任何时间生成的ID都不会重复。都需要保证唯一性。
  • 趋势递增:在多数业务场景下,ID最好随时间递增,便于数据库索引和排序。
  • 高可用:ID生成服务不能成为系统瓶颈,需要支持高并发。
  • 安全性:ID不应泄露业务规模或可被轻易猜测,避免被恶意遍历。

2. 为什么需要全局唯一ID

在单体应用中,数据库自增主键即可满足唯一性需求。但在分布式系统中,数据分散在多个数据库、多个服务实例中,如果每个节点都使用本地自增ID,就会出现重复。因此需要一套跨节点的ID生成方案,保证全局唯一。

典型场景包括:

  • 订单系统:多个订单服务实例同时生成订单号,不能重复。
  • 消息队列:每条消息需要唯一ID用于去重和追踪。
  • 分库分表:数据拆分到多张表后,主键不能依赖单库自增。
  • 日志链路:分布式调用链需要全局唯一的TraceID串联日志。

3. 常见的全局唯一ID构建方案

业界常用的全局唯一ID方案主要有以下几种,各有优缺点,需要根据业务场景选择。

3.1 UUID

UUID(Universally Unique Identifier)是最简单直接的方案,由128位二进制组成,通常表示为32位十六进制字符串。Java中可通过 UUID.randomUUID() 生成。

java 复制代码
import java.util.UUID;

public class UuidDemo {
    public static void main(String[] args) {
        String id = UUID.randomUUID().toString().replace("-", "");
        System.out.println(id);
    }
}

优点:生成简单、无需网络交互、本地即可保证唯一。缺点:无序、长度较长(36位含连字符),作为数据库主键时会导致索引碎片,查询性能下降。因此在实际的业务中很少被用到,只有在那些极少数的情况下(对数据的顺序结构没有要求的时候)会用到。

3.2 数据库自增ID

利用数据库的自增主键生成ID,在单库场景下简单可靠。但在分布式场景下,可以通过设置不同的起始值和步长来避免冲突。这个方案同样的也很少用到,我们的项目的数据库大多都是集群的形式出现,并不会出现一个单独的数据库,一个数据库如果出现了问题的话就会很麻烦,因此我们并不会只布置一台数据库。

sql 复制代码
-- 节点1
CREATE TABLE t_id (
    id BIGINT NOT NULL AUTO_INCREMENT,
    PRIMARY KEY (id)
) AUTO_INCREMENT = 1;

-- 节点2
CREATE TABLE t_id (
    id BIGINT NOT NULL AUTO_INCREMENT,
    PRIMARY KEY (id)
) AUTO_INCREMENT = 2;

优点:实现简单、趋势递增。缺点:依赖数据库,高并发下数据库成为瓶颈;多节点配置复杂,扩展性差。

3.3 Redis生成ID

利用Redis的原子自增命令 INCR 或 INCRBY 生成ID,可以结合日期前缀实现趋势递增。

java 复制代码
import redis.clients.jedis.Jedis;

public class RedisIdDemo {
    public static void main(String[] args) {
        try (Jedis jedis = new Jedis("localhost", 6379)) {
            long id = jedis.incr("order:id");
            System.out.println("生成的ID: " + id);
        }
    }
}

优点:性能高、实现简单、天然趋势递增。缺点:依赖Redis的可用性,如果Redis宕机可能影响ID生成;需要额外维护Redis集群。

3.4 雪花算法(Snowflake)

雪花算法是Twitter开源的一种分布式ID生成算法,由64位组成,结构如下:

text 复制代码
0 | 41位时间戳 | 10位机器ID | 12位序列号

其中第1位为符号位固定为0,41位时间戳可支持约69年,10位机器ID可部署1024个节点,12位序列号每毫秒可生成4096个ID。

java 复制代码
public class SnowflakeIdWorker {
    private final long twepoch = 1288834974657L;
    private final long workerIdBits = 10L;
    private final long sequenceBits = 12L;
    private final long workerIdShift = sequenceBits;
    private final long timestampLeftShift = sequenceBits + workerIdBits;
    private final long sequenceMask = -1L ^ (-1L << sequenceBits);

    private long workerId;
    private long sequence = 0L;
    private long lastTimestamp = -1L;

    public SnowflakeIdWorker(long workerId) {
        this.workerId = workerId;
    }

    public synchronized long nextId() {
        long timestamp = System.currentTimeMillis();
        if (timestamp < lastTimestamp) {
            throw new RuntimeException("时钟回拨");
        }
        if (timestamp == lastTimestamp) {
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }
        lastTimestamp = timestamp;
        return ((timestamp - twepoch) << timestampLeftShift)
                | (workerId << workerIdShift)
                | sequence;
    }

    private long tilNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }
}

优点:性能极高、趋势递增、不依赖外部组件。缺点:依赖机器时钟,时钟回拨会导致ID重复,需要做好时钟同步和回拨处理。

3.5 美团Leaf方案

美团开源的Leaf提供了两种模式:号段模式和雪花模式。号段模式通过批量获取数据库号段,减少数据库压力;雪花模式在雪花算法基础上解决了时钟回拨问题。

text 复制代码
号段模式:每次从数据库取一批ID(如1000个),缓存在本地内存中,用完再取下一批。

优点:兼顾性能和可用性,适合大规模分布式系统。缺点:实现复杂度较高,需要引入额外组件。

4. 方案对比与选型建议

方案 唯一性 趋势递增 性能 依赖 适用场景
UUID 高 否 高 无 非主键场景、离线生成
数据库自增 高 是 低 数据库 单库、低并发
Redis 高 是 中 Redis 中高并发、趋势递增
雪花算法 高 是 极高 无 高并发、分布式
美团Leaf 高 是 极高 数据库+ZK 大规模分布式系统

选型建议:中小型系统优先考虑雪花算法或Redis方案;对ID有序性要求高且并发量大的场景,推荐美团Leaf号段模式;如果只是临时生成唯一标识且不关心顺序,UUID即可满足。

5. 总结

全局唯一ID是分布式系统的基础设施之一,核心目标是保证跨节点唯一。不同方案在唯一性、递增性、性能和依赖上有明显差异,实际选型时应结合业务规模、并发量、可用性要求和运维成本综合权衡。雪花算法因其高性能和趋势递增特性,是目前最主流的方案;美团Leaf则在雪花基础上进一步解决了时钟回拨等工程问题,适合大规模生产环境。

相关推荐
小南家的青蛙1 小时前
华为云DCS全产品对比
redis·1024程序员节
java_nnnn3 小时前
Redis 核心特性与应用场景:从底层原理到分布式系统应用
数据库·redis·1024程序员节
余槐i3 小时前
开虚拟线程后接口反而更慢:JDK 21 synchronized 锁住载体线程的排查
java·spring boot·redis·mysql·性能优化
啊哈一半醒4 小时前
Redis 三大缓存问题:缓存穿透、缓存击穿、缓存雪崩
运维·redis·1024程序员节
前进的李工15 小时前
飞书企业知识库设计+后端高频八股
数据库·redis·后端·mysql·性能优化·飞书·rag
技术拾荒的人儿20 小时前
高并发投票系统:限流、幂等防刷与票数一致性的落地实践
redis·高并发·限流·系统设计·后端架构
bksczm21 小时前
Redis数据结构之string
java·redis·mybatis
码士集团小青1 天前
Redis 缓存击穿(失效)、缓存穿透、缓存雪崩怎么解决?
数据库·redis·缓存
码士集团小青1 天前
硬核 | Redis 布隆(Bloom Filter)过滤器原理与实战
数据库·redis·缓存