CosId 分布式 ID 生成器完全教程:从架构原理到生产落地

文章目录

    • [1. 项目概述](#1. 项目概述)
      • [1.1 什么是 CosId?](#1.1 什么是 CosId?)
      • [1.2 核心特性一览](#1.2 核心特性一览)
      • [1.3 四大 ID 生成算法对比](#1.3 四大 ID 生成算法对比)
    • [2. 为什么需要分布式 ID](#2. 为什么需要分布式 ID)
      • [2.1 背景:从单体到分布式的挑战](#2.1 背景:从单体到分布式的挑战)
      • [2.2 分布式 ID 的六大核心指标](#2.2 分布式 ID 的六大核心指标)
      • [2.3 主流方案对比](#2.3 主流方案对比)
    • [3. 核心架构与设计理念](#3. 核心架构与设计理念)
      • [3.1 整体架构图](#3.1 整体架构图)
      • [3.2 设计哲学](#3.2 设计哲学)
      • [3.3 模块结构](#3.3 模块结构)
    • [4. 环境准备与安装](#4. 环境准备与安装)
      • [4.1 版本兼容性](#4.1 版本兼容性)
      • [4.2 Gradle 构建(Kotlin DSL)](#4.2 Gradle 构建(Kotlin DSL))
      • [4.3 Maven 构建](#4.3 Maven 构建)
      • [4.4 基础设施依赖](#4.4 基础设施依赖)
    • [5. 快速开始(5 分钟上手)](#5. 快速开始(5 分钟上手))
      • [5.1 最简配置示例(Redis 分发器)](#5.1 最简配置示例(Redis 分发器))
      • [5.2 在代码中使用](#5.2 在代码中使用)
      • [5.3 运行验证](#5.3 运行验证)
      • [5.4 ⚠️ 重要注意事项](#5.4 ⚠️ 重要注意事项)
    • [6. CosIdGenerator 详解](#6. CosIdGenerator 详解)
      • [6.1 什么是 CosIdGenerator?](#6.1 什么是 CosIdGenerator?)
      • [6.2 位分配结构](#6.2 位分配结构)
        • [Base36 格式(默认)](#Base36 格式(默认))
        • [Base62 格式](#Base62 格式)
      • [6.3 配置示例](#6.3 配置示例)
      • [6.4 适用场景](#6.4 适用场景)
    • [7. SnowflakeId 雪花算法详解](#7. SnowflakeId 雪花算法详解)
      • [7.1 算法原理](#7.1 算法原理)
      • [7.2 各字段含义与容量](#7.2 各字段含义与容量)
      • [7.3 设计优缺点分析](#7.3 设计优缺点分析)
        • [✅ 优点](#✅ 优点)
        • [❌ 缺点与挑战](#❌ 缺点与挑战)
      • [7.4 CosId 对 SnowflakeId 的增强](#7.4 CosId 对 SnowflakeId 的增强)
      • [7.5 两种时间精度实现](#7.5 两种时间精度实现)
      • [7.6 SnowflakeFriendlyId(友好型 ID)](#7.6 SnowflakeFriendlyId(友好型 ID))
      • [7.7 SafeJavaScriptSnowflakeId(JS 安全型)](#7.7 SafeJavaScriptSnowflakeId(JS 安全型))
      • [7.8 ClockSyncSnowflakeId(时钟同步包装器)](#7.8 ClockSyncSnowflakeId(时钟同步包装器))
      • [7.9 SnowflakeId 完整配置](#7.9 SnowflakeId 完整配置)
    • [8. SegmentId 号段模式详解](#8. SegmentId 号段模式详解)
      • [8.1 算法原理](#8.1 算法原理)
      • [8.2 有序性特征](#8.2 有序性特征)
      • [8.3 IdSegmentDistributor 接口](#8.3 IdSegmentDistributor 接口)
      • [8.4 四种号段分发器实现](#8.4 四种号段分发器实现)
      • [8.5 JDBC 分发器初始化](#8.5 JDBC 分发器初始化)
      • [8.6 GroupedIdSegmentDistributor(分组分发器)](#8.6 GroupedIdSegmentDistributor(分组分发器))
      • [8.7 SegmentId 配置示例](#8.7 SegmentId 配置示例)
      • [8.8 SegmentId 性能特征](#8.8 SegmentId 性能特征)
    • [9. SegmentChainId 号段链模式(推荐)⭐](#9. SegmentChainId 号段链模式(推荐)⭐)
      • [9.1 为什么推荐 SegmentChainId?](#9.1 为什么推荐 SegmentChainId?)
      • [9.2 核心设计:PrefetchWorker(预取工作线程)](#9.2 核心设计:PrefetchWorker(预取工作线程))
      • [9.3 自适应机制(Adaptability)](#9.3 自适应机制(Adaptability))
      • [9.4 性能极限公式](#9.4 性能极限公式)
      • [9.5 SegmentChainId 配置](#9.5 SegmentChainId 配置)
      • [9.6 代码中使用 SegmentChainId](#9.6 代码中使用 SegmentChainId)
    • [10. 机器号分配器 MachineIdDistributor](#10. 机器号分配器 MachineIdDistributor)
      • [10.1 概述](#10.1 概述)
      • [10.2 六种分配器实现](#10.2 六种分配器实现)
      • [10.3 各分配器详细配置](#10.3 各分配器详细配置)
        • [① ManualMachineIdDistributor(手动)](#① ManualMachineIdDistributor(手动))
        • [② StatefulSetMachineIdDistributor(K8s StatefulSet)](#② StatefulSetMachineIdDistributor(K8s StatefulSet))
        • [③ RedisMachineIdDistributor](#③ RedisMachineIdDistributor)
        • [④ JdbcMachineIdDistributor](#④ JdbcMachineIdDistributor)
        • [⑤ ZookeeperMachineIdDistributor](#⑤ ZookeeperMachineIdDistributor)
        • [⑥ MongoMachineIdDistributor](#⑥ MongoMachineIdDistributor)
      • [10.4 MachineState(机器状态)](#10.4 MachineState(机器状态))
      • [10.5 MachineStateStorage(机器状态存储)](#10.5 MachineStateStorage(机器状态存储))
      • [10.6 机器号守护(Machine Guarder)](#10.6 机器号守护(Machine Guarder))
    • [11. 时钟回拨问题解决方案](#11. 时钟回拨问题解决方案)
      • [11.1 问题背景](#11.1 问题背景)
      • [11.2 两种时钟回拨场景](#11.2 两种时钟回拨场景)
      • [11.3 ClockBackwardsSynchronizer(时钟回拨同步器)](#11.3 ClockBackwardsSynchronizer(时钟回拨同步器))
      • [11.4 ClockSyncSnowflakeId vs 默认 SnowflakeId](#11.4 ClockSyncSnowflakeId vs 默认 SnowflakeId)
    • [12. IdGeneratorProvider 多业务支持](#12. IdGeneratorProvider 多业务支持)
      • [12.1 为什么需要 Provider?](#12.1 为什么需要 Provider?)
      • [12.2 通过配置文件注册](#12.2 通过配置文件注册)
      • [12.3 在代码中使用](#12.3 在代码中使用)
      • [12.4 通过代码动态注册](#12.4 通过代码动态注册)
      • [12.5 Bean Name 规则](#12.5 Bean Name 规则)
    • [13. MyBatis 插件集成](#13. MyBatis 插件集成)
      • [13.1 概述](#13.1 概述)
      • [13.2 添加依赖](#13.2 添加依赖)
      • [13.3 @CosId 注解说明](#13.3 @CosId 注解说明)
      • [13.4 使用示例](#13.4 使用示例)
        • [场景一:Long 类型 ID](#场景一:Long 类型 ID)
        • [场景二:友好 ID(String 类型)](#场景二:友好 ID(String 类型))
        • [场景三:Mapper 接口](#场景三:Mapper 接口)
      • [13.5 使用效果](#13.5 使用效果)
    • [14. ShardingSphere 分片集成](#14. ShardingSphere 分片集成)
      • [14.1 概述](#14.1 概述)
      • [14.2 CosIdKeyGenerateAlgorithm(分布式主键)](#14.2 CosIdKeyGenerateAlgorithm(分布式主键))
      • [14.3 CosIdIntervalShardingAlgorithm(时间范围分片)](#14.3 CosIdIntervalShardingAlgorithm(时间范围分片))
      • [14.4 CosIdModShardingAlgorithm(取模分片)](#14.4 CosIdModShardingAlgorithm(取模分片))
    • [15. 完整配置参考手册](#15. 完整配置参考手册)
      • [15.1 完整 application.yml 模板](#15.1 完整 application.yml 模板)
      • [15.2 配置项速查表](#15.2 配置项速查表)
    • [16. 性能基准测试](#16. 性能基准测试)
      • [16.1 测试环境](#16.1 测试环境)
      • [16.2 SnowflakeId 性能](#16.2 SnowflakeId 性能)
      • [16.3 SegmentChainId 性能](#16.3 SegmentChainId 性能)
      • [16.4 各算法性能汇总](#16.4 各算法性能汇总)
      • [16.5 如何运行基准测试](#16.5 如何运行基准测试)
    • [17. 最佳实践与生产建议](#17. 最佳实践与生产建议)
      • [17.1 算法选择决策树](#17.1 算法选择决策树)
      • [17.2 生产环境 Checklist](#17.2 生产环境 Checklist)
        • [✅ 必做项](#✅ 必做项)
        • [⚠️ 注意事项](#⚠️ 注意事项)
        • [🔧 高级优化](#🔧 高级优化)
      • [17.3 分发器选择指南](#17.3 分发器选择指南)
      • [17.4 监控指标建议](#17.4 监控指标建议)
    • [18. 常见问题 FAQ](#18. 常见问题 FAQ)
      • [Q1: CosId 和美团 Leaf 有什么区别?](#Q1: CosId 和美团 Leaf 有什么区别?)
      • [Q2: 同时开启 SnowflakeId 和 SegmentId 会怎样?](#Q2: 同时开启 SnowflakeId 和 SegmentId 会怎样?)
      • [Q3: SegmentChainId 的安全距离应该设多大?](#Q3: SegmentChainId 的安全距离应该设多大?)
      • [Q4: 为什么不同分发器最终都能达到相同性能?](#Q4: 为什么不同分发器最终都能达到相同性能?)
      • [Q5: 如何处理 JavaScript 的 Long 溢出问题?](#Q5: 如何处理 JavaScript 的 Long 溢出问题?)
      • [Q6: 时钟回拨应该如何处理?](#Q6: 时钟回拨应该如何处理?)
      • [Q7: CosId 支持哪些数据库?](#Q7: CosId 支持哪些数据库?)
      • [Q8: 如何在现有项目中迁移到 CosId?](#Q8: 如何在现有项目中迁移到 CosId?)

1. 项目概述

1.1 什么是 CosId?

CosId (Cosmic ID)是一个通用、灵活、高性能的分布式 ID 生成器,由 Java 全栈开发者 Ahoo-Wang 开源。它旨在为微服务架构下的分布式系统提供全局唯一的、趋势递增的高性能 ID 生成能力。

1.2 核心特性一览

特性 说明
🌐 通用性 支持多种分布式 ID 算法:SnowflakeId、SegmentId、SegmentChainId、CosIdGenerator
高性能 SegmentChainId TPS 达到 127,439,148+ ops/s,接近 AtomicLong 性能上限
🔧 灵活性 位分配方案可配置、多种分发器可选、支持多业务隔离
🔌 易集成 Spring Boot 自动配置、MyBatis 插件、ShardingSphere 插件开箱即用
🛡️ 健壮性 时钟回拨保护、机器号自动分配、安全距离自适应伸缩

1.3 四大 ID 生成算法对比

算法 TPS 性能 (ops/s) 稳定性 P9999 有序性 自治性 适用场景
CosIdGenerator 15,570,085 --- 全局趋势递增 完全自治 大规模集群、百万实例
SnowflakeId 4,096,000 0.244 us/op 本地单调递增 依赖时钟 中小规模集群、低延迟需求
SegmentId 29,506,073 46.624 us/op 本地单调递增 依赖第三方分发器 一般业务场景
SegmentChainId 127,439,148+ 0.208 us/op 本地单调递增 依赖第三方分发器 高吞吐生产环境(推荐)

2. 为什么需要分布式 ID

2.1 背景:从单体到分布式的挑战

在软件系统演进过程中,随着业务规模的增长(TPS/存储容量),我们需要通过集群化部署来分摊计算和存储压力。

复制代码
┌─────────────────────────────────────────────────────┐
│                   单体应用时代                        │
│  ┌──────────┐                                       │
│  │ 应用服务   │ ──→ ┌──────────┐                    │
│  │ (单实例)   │     │ 数据库    │ ← 自增主键即可      │
│  └──────────┘     └──────────┘                      │
└─────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────┐
│                 分布式/微服务时代                     │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐               │
│  │ 实例 1   │ │ 实例 2   │ │ 实例 N   │              │
│  └────┬────┘ └────┬────┘ └────┬────┘               │
│       └──────────┼──────────┘                       │
│                  ▼                                  │
│          ┌──────────────┐                           │
│          │  分库分表数据库  │ ← 需要!分布式 ID        │
│          └──────────────┘                           │
└─────────────────────────────────────────────────────┘

2.2 分布式 ID 的六大核心指标

指标 说明 为什么重要
全局唯一性 相同业务不同副本生成的 ID 不冲突 主键约束的基本要求
有序性 单调递增或趋势递增 B+树索引效率、追加写性能
吞吐量 单位时间生成 ID 数量 系统整体性能上限
稳定性 百分位延迟(如 P9999) 尾部延迟影响用户体验
自治性 对外部中间件的依赖程度 影响可用性和运维复杂度
适应性 流量突发时的动态伸缩能力 应对秒杀、大促等场景

2.3 主流方案对比

方案 唯一性 有序性 吞吐量 存储空间 缺陷
UUID/GUID ❌ 完全无序 307万/s 128-bit 索引性能差
数据库自增 ✅ 单调递增 64-bit 扩展困难
SnowflakeId ✅ 趋势递增 409万/s 64-bit 时钟依赖
CosId SegmentChainId ✅ 趋势递增 1.27亿+/s 64-bit 依赖第三方分发器

3. 核心架构与设计理念

3.1 整体架构图

复制代码
┌──────────────────────────────────────────────────────────────────┐
│                         CosId 架构                               │
├──────────────────────────────────────────────────────────────────┤
│  ┌─────────────────────────────────────────────────────────────┐│
│  │                    应用层 (Application Layer)                ││
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐  ││
│  │  │ MyBatis 插件 │  │ ShardingSphere│  │ 业务代码直接调用     │  ││
│  │  │ @CosId 注解  │  │ 分片算法集成  │  │ IdGenerator.generate│  ││
│  │  └─────────────┘  └─────────────┘  └─────────────────────┘  ││
│  └─────────────────────────────────────────────────────────────┘│
│                              ▼                                  │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │                   ID 生成引擎层 (Engine Layer)               ││
│  │  ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌──────────┐ ││
│  │  │CosIdGenerat│ │SnowflakeId │ │ SegmentId  │ │Segment   │ ││
│  │  │   or       │ │            │ │            │ │ChainId   │ ││
│  │  └────────────┘ └─────┬──────┘ └─────┬──────┘ └────┬─────┘ ││
│  └────────────────────────────┼────────────┼────────────┼──────┘│
│  ┌────────────────────────────▼────────────▼────────────▼──────┐│
│  │                  分发层 (Distributor Layer)                  ││
│  │  ┌──────────────────────────────────────────────────────┐  ││
│  │  │           MachineIdDistributor (机器号分配)             │  ││
│  │  │  Manual │ StatefulSet │ Redis │ JDBC │ Zookeeper │ Mongo│  ││
│  │  └──────────────────────────────────────────────────────┘  ││
│  │  ┌──────────────────────────────────────────────────────┐  ││
│  │  │           IdSegmentDistributor (号段分发)              │  ││
│  │  │        Redis │ JDBC │ Zookeeper │ MongoDB             │  ││
│  │  └──────────────────────────────────────────────────────┘  ││
│  └─────────────────────────────────────────────────────────────┘│
│                              ▼                                  │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │                  存储层 (Storage Layer)                      ││
│  │         Redis │ MySQL/PostgreSQL │ ZooKeeper │ MongoDB      ││
│  └─────────────────────────────────────────────────────────────┘│
│  ┌─────────────────────────────────────────────────────────────┐│
│  │              Spring Boot 自动配置层                          ││
│  │  cosid-spring-boot-starter (自动装配、属性绑定)              ││
│  └─────────────────────────────────────────────────────────────┘│
└──────────────────────────────────────────────────────────────────┘

基于 cosid-core 源码结构S5官方文档架构说明S2 整理

3.2 设计哲学

  1. 分层解耦:引擎层与分发层分离,可独立替换
  2. 策略模式:通过接口抽象,支持多种实现策略
  3. 约定优于配置:Spring Boot 自动配置,最小化用户配置量
  4. 渐进式复杂度:从最简配置到高级特性,按需启用

3.3 模块结构

模块 说明
cosid-core 核心引擎:IdGenerator、SnowflakeId、SegmentId、SegmentChainId
cosid-spring-boot-starter Spring Boot 自动配置、属性绑定
cosid-jdbc JDBC 号段分发器和机器号分发器
cosid-spring-redis Redis 号段分发器和机器号分发器
cosid-zookeeper ZooKeeper 号段分发器和机器号分发器
cosid-mongo MongoDB 号段分发器
cosid-mybatis MyBatis 插件(@CosId 注解)
cosid-jackson Jackson 序列化支持
cosid-activiti Activiti 工作流集成
cosid-axon Axon Framework 集成
cosid-flowable Flowable 工作流集成
cosid-spring-data-jdbc Spring Data JDBC 集成
cosid-benchmark JMH 性能基准测试
proxy CosId Proxy 独立代理服务

4. 环境准备与安装

4.1 版本兼容性

CosId 版本 Spring Boot 版本 Java 版本 Git 分支
1.x 2.x Java 8 1.x branch
2.x 3.x Java 17 2.x branch
3.x(当前最新) 4.x Java 17+ main branch

⚠️ 重要提示 :本教程基于 CosId v3.2.0 + Spring Boot 4.x + Java 17

4.2 Gradle 构建(Kotlin DSL)

kotlin 复制代码
// build.gradle.kts
val cosidVersion = "3.2.0"

dependencies {
    // 核心启动器(必选)
    implementation("me.ahoo.cosid:cosid-spring-boot-starter:${cosidVersion}")

    // 分发器按需选择(至少选一个)
    implementation("me.ahoo.cosid:cosid-spring-redis:${cosidVersion}")      // Redis
    implementation("me.ahoo.cosid:cosid-jdbc:${cosidVersion}")              // JDBC
    implementation("me.ahoo.cosid:cosid-zookeeper:${cosidVersion}")        // ZooKeeper
    implementation("me.ahoo.cosid:cosid-mongo:${cosidVersion}")            // MongoDB

    // 可选集成
    implementation("me.ahoo.cosid:cosid-mybatis:${cosidVersion}")          // MyBatis 插件
}

4.3 Maven 构建

xml 复制代码
<properties>
    <cosid.version>3.2.0</cosid.version>
</properties>

<dependencies>
    <!-- 核心启动器 -->
    <dependency>
        <groupId>me.ahoo.cosid</groupId>
        <artifactId>cosid-spring-boot-starter</artifactId>
        <version>${cosid.version}</version>
    </dependency>

    <!-- Redis 分发器 -->
    <dependency>
        <groupId>me.ahoo.cosid</groupId>
        <artifactId>cosid-spring-redis</artifactId>
        <version>${cosid.version}</version>
    </dependency>
</dependencies>

4.4 基础设施依赖

根据选择的分发器类型,需要准备对应的基础设施:

分发器类型 所需基础设施 额外依赖
Redis Redis Server 3.2+ spring-boot-starter-data-redis
JDBC MySQL / PostgreSQL / Oracle 对应数据库驱动
ZooKeeper ZooKeeper 3.5+ spring-cloud-starter-zookeeper 或客户端
MongoDB MongoDB 3.6+ spring-boot-starter-data-mongodb

5. 快速开始(5 分钟上手)

5.1 最简配置示例(Redis 分发器)

yaml 复制代码
# application.yml
spring:
  data:
    redis:
      host: localhost
      port: 6379
      # Redis 分发器直接依赖 spring-data-redis,无需额外配置

cosid:
  namespace: ${spring.application.name}  # 命名空间,用于隔离不同应用

  machine:
    enabled: true                        # 启用机器号分配(雪花算法需要)
    distributor:
      type: redis                        # 使用 Redis 作为机器号分发器

  snowflake:
    enabled: true                        # 启用雪花算法 ID 生成器

  segment:
    enabled: true                        # 启用号段算法 ID 生成器
    mode: chain                          # 使用号段链模式(推荐)
    distributor:
      type: redis                        # 使用 Redis 作为号段分发器

5.2 在代码中使用

java 复制代码
@RestController
@RequestMapping("/api/demo")
public class DemoController {

    /**
     * 方式一:通过 @Autowired 注入共享的 IdGenerator
     * 默认名称规则:
     *   - __share__SegmentId (号段模式)
     *   - __share__SnowflakeId (雪花模式)
     */
    @Autowired
    @Qualifier("__share__SegmentId")
    private IdGenerator segmentIdGenerator;

    @Autowired
    @Qualifier("__share__SnowflakeId")
    private SnowflakeId snowflakeId;

    /**
     * 方式二:通过 DefaultIdGeneratorProvider 获取
     */
    @GetMapping("/id")
    public Long generateId() {
        // 获取共享的 ID 生成器并生成 ID
        return DefaultIdGeneratorProvider.INSTANCE.getShare().generate();
    }

    @GetMapping("/snowflake")
    public Long generateSnowflakeId() {
        return snowflakeId.generate();
    }

    @GetMapping("/segment")
    public Long generateSegmentId() {
        return segmentIdGenerator.generate();
    }
}

5.3 运行验证

启动应用后访问:

bash 复制代码
curl http://localhost:8080/api/demo/id
# 返回: 208796080181248 (示例值)

curl http://localhost:8080/api/demo/snowflake
# 返回: 6928793728688168960 (示例值)

5.4 ⚠️ 重要注意事项

  1. 共享 ID 生成器冲突 :当同时开启 snowflake.enabled: truesegment.enabled: true 时,只有一个共享的 (__share__) IdGenerator 会注入到 Spring 容器(Bean 名称冲突),另一个会被忽略。
  2. 解决方案 :通过 provider 配置注册多个命名 ID 生成器(见第 12 章)。

6. CosIdGenerator 详解

6.1 什么是 CosIdGenerator?

CosIdGenerator 是 CosId 提供的一种完全自治的分布式 ID 生成算法,不依赖任何第三方中间件。

核心特点

  • 单机 TPS 性能:15,570,085 ops/s (是 UUID.randomUUID() 的 3 倍
  • 基于时钟的全局趋势递增 ID
  • 可同时支持 100 万个实例
  • 使用 Base36 或 Base62 编码压缩存储空间

6.2 位分配结构

Base36 格式(默认)
复制代码
[timestamp(44-bit)]-[machineId(20-bit)]-[sequence(16-bit)] = 80 BITS = 17 CHARS
= [timestamp(8字符)]-[machineId(4字符)]-[sequence(3字符)]
Base62 格式
复制代码
[timestamp(44-bit)]-[machineId(20-bit)]-[sequence(16-bit)] = 80 BITS = 15 CHARS
= [timestamp(9字符)]-[machineId(4字符)]-[sequence(4字符)]

6.3 配置示例

yaml 复制代码
cosid:
  cosid-generator:
    # Base36 或 Base62
    radix: base36

    machine-bit: 20
    sequence-bit: 16
    timestamp-bit: 44

6.4 适用场景

适合使用 CosIdGenerator 的场景

  • 大规模集群部署(数千至数百万实例)
  • 无法依赖外部中间件的轻量级服务
  • 需要短 ID 字符串的场景(17 位 Base36 或 15 位 Base62)

不适合的场景

  • 需要严格单调递增的业务(订单号等)
  • 需要纯数字 Long 类型 ID 的场景

7. SnowflakeId 雪花算法详解

7.1 算法原理

SnowflakeId 是 Twitter 开发的分布式唯一 ID 生成算法,使用 Long(64-bit)位分区来生成 ID。

标准位分配方案

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                        64-bit SnowflakeId 结构                  │
├────────────┬────────────────┬──────────────┬────────────────────┤
│  1 bit 符号 │ timestamp      │ machineId    │ sequence           │
│  (保留不用) │ (41-bit)       │ (10-bit)     │ (12-bit)           │
├────────────┼────────────────┼──────────────┼────────────────────┤
│     0      │ 41位时间戳      │ 10位机器号    │ 12位序列号          │
└────────────┴────────────────┴──────────────┴────────────────────┘

总位数: 1 + 41 + 10 + 12 = 64 bits (实际使用 63 位)

7.2 各字段含义与容量

字段 位数 容量 说明
timestamp 41-bit 69 年 (1L<<41)/(1000*3600*24*365) ≈ 69年,从自定义 EPOCH 开始计算
machineId 10-bit 1024 个实例 相同业务可部署的副本数(Kubernetes Pod 数)
sequence 12-bit 4096/ms 单机每毫秒可生成的 ID 数量

理论最大 TPS4096000 * 1024 = 4,194,304,000 ≈ 41.9 亿/秒

7.3 设计优缺点分析

✅ 优点
  1. 本地单调递增:时间戳在高位,单实例保证时钟向前 → 本地单调递增
  2. 全局趋势递增:受全局时钟同步影响,整体呈趋势递增
  3. 无强依赖:不对任何第三方中间件有强依赖关系
  4. 高性能 :TPS 达到 4,096,000 ops/s(JMH 基准测试)
  5. 灵活配置:位分配方案可根据业务需要调整
❌ 缺点与挑战
  1. 时钟依赖:强依赖本地时钟,时钟回拨会导致 ID 重复
  2. 机器号维护:machineId 需要手动设置,大规模集群维护繁琐
  3. JavaScript 溢出:63-bit ID 超过 JS 的 Number.MAX_SAFE_INTEGER(53-bit)

7.4 CosId 对 SnowflakeId 的增强

复制代码
┌─────────────────────────────────────────────────────────────┐
│              SnowflakeId 三大问题 & CosId 解决方案            │
├──────────────────┬──────────────────────────────────────────┤
│ ① 机器号分配问题  │ → MachineIdDistributor(6种分配策略)      │
│ ② 时钟回拨问题    │ → ClockBackwardsSynchronizer(主动同步)   │
│③ JS数值溢出问题  │ → SafeJavaScriptSnowflakeId(53-bit适配)  │
└──────────────────┴──────────────────────────────────────────┘

7.5 两种时间精度实现

MillisecondSnowflakeId(默认)
java 复制代码
// 使用 System.currentTimeMillis() 作为时间戳
// 精确到毫秒级别
// 单机 TPS: 409.6 万/秒(每毫秒 4096 个 ID)
SnowflakeId snowflakeId = new MillisecondSnowflakeId(...);
SecondSnowflakeId
java 复制代码
// 使用 System.currentTimeMillis() / 1000 作为时间戳
// 精确到秒级别
// 单机 TPS: 409.6 万/秒(每秒 4096 个 ID),但序列号空间更大
SnowflakeId snowflakeId = new SecondSnowflakeId(...);

7.6 SnowflakeFriendlyId(友好型 ID)

将 SnowflakeId 解析为人类可读的格式:

java 复制代码
public class SnowflakeIdState {
    private final long id;              // 原始 ID
    private final int machineId;        // 机器号
    private final long sequence;        // 序列号
    private final LocalDateTime timestamp; // 生成时间
    /**
     * 友好格式: {timestamp}-{machineId}-{sequence}
     * 示例: 20210623131730192-1-0
     */
    private final String friendlyId;
}

// 使用方式
SnowflakeFriendlyId friendlyId = new DefaultSnowflakeFriendlyId(snowflakeId);
SnowflakeIdState state = friendlyId.friendlyId();
state.getFriendlyId();  // 输出: "20210623131730192-1-0"

7.7 SafeJavaScriptSnowflakeId(JS 安全型)

解决 JavaScript 的 Number.MAX_SAFE_INTEGER(53-bit)溢出问题:

java 复制代码
// 自定义位分配,使总位数 ≤ 53-bit
// 示例: machineId=3bit, sequence=9bit → 总共 53-bit
SnowflakeId safeJsSnowflakeId = SafeJavaScriptSnowflakeId.ofMillisecond(1);
long id = safeJsSnowflakeId.generate();
// 返回给前端 JavaScript 不会溢出

7.8 ClockSyncSnowflakeId(时钟同步包装器)

java 复制代码
// 当发生时钟回拨时,主动等待时钟同步后再生成 ID
// 而不是直接抛出异常
ClockSyncSnowflakeId clockSyncId = new ClockSyncSnowflakeId(
    snowflakeId,
    new DefaultClockBackwardsSynchronizer(spinThreshold, brokenThreshold)
);

配置开启

yaml 复制代码
cosid:
  snowflake:
    share:
      clock-sync: true  # 开启时钟同步模式

7.9 SnowflakeId 完整配置

yaml 复制代码
cosid:
  namespace: ${spring.application.name}

  machine:
    enabled: true
    distributor:
      type: redis  # 可选: manual | stateful_set | redis | jdbc | zookeeper | mongo
    guarder:
      enabled: true  # 开启机器号守护(定期续约)

  snowflake:
    enabled: true
    zone-id: Asia/Shanghai  # 时区
    epoch: 1577203200000    # 自定义纪元时间戳(毫秒)

    clock-backwards:
      spin-threshold: 10    # 自旋等待阈值(毫秒)
      broken-threshold: 2000 # 时钟回拨异常阈值(毫秒)

    share:
      clock-sync: true      # 开启始终钟同步
      friendly: true        # 开启友好 ID 解析

    provider:
      # 注册多个命名 ID 生成器
      order:
        sequence-bit: 12
      user:
        sequence-bit: 12
      safeJs:
        machine-bit: 3      # JS 安全模式:缩短位数
        sequence-bit: 9

8. SegmentId 号段模式详解

8.1 算法原理

**SegmentId(号段模式)**的核心思想:每次获取一段(Step)长度的可用 ID,减少网络 IO 请求频次,提升性能。

复制代码
┌─────────────────────────────────────────────────────────────┐
│                    SegmentId 工作流程                        │
│                                                             │
│  Instance 1 ──→ [请求号段] ──→ IdSegmentDistributor         │
│                    ↓                                        │
│            获得 ID 区间: [1 ~ 1000]                          │
│                    ↓                                        │
│  ┌─────────────────────────────────┐                        │
│  │  本地内存号段: 1,2,3,...,1000   │ ← 从内存取 ID,无网络IO │
│  └─────────────────────────────────┘                        │
│                    ↓                                        │
│         号段用完后再次请求                                   │
│                                                             │
│  Instance 2 ──→ [请求号段] ──→ IdSegmentDistributor         │
│                    ↓                                        │
│            获得 ID 区间: [1001 ~ 2000]                       │
└─────────────────────────────────────────────────────────────┘

8.2 有序性特征

特征 说明
单实例 本地单调递增(每次获取的号段一定比上一次大)
全局 趋势递增(受 Step 长度和集群规模影响)
乱序程度 Step 越小越有序;Step=1 时无限接近单调递增

8.3 IdSegmentDistributor 接口

java 复制代码
/**
 * 号段分发器核心接口
 * 职责:在分布式实例之间分配连续的 ID 块
 */
public interface IdSegmentDistributor {

    /**
     * 获取下一个号段
     * @param namespace 命名空间
     * @param name ID 名称
     * @return IdSegment 号段对象(包含当前最大 ID)
     */
    IdSegment distribute(String namespace, String name);

    /**
     * 获取分组号段(支持按分组键分区)
     */
    IdSegment distributeGrouped(String namespace, String name, String group);
}

8.4 四种号段分发器实现

分发器类型 类名 适用场景 特点
Redis RedisIdSegmentDistributor 已有 Redis 基础设施 高性能、低延迟
JDBC JdbcIdSegmentDistributor 关系型数据库为主 通用性强、事务安全
ZooKeeper ZookeeperIdSegmentDistributor 已有 ZK 集群 强一致性保证
MongoDB MongoIdSegmentDistributor MongoDB 生态 文档型存储

8.5 JDBC 分发器初始化

使用 JDBC 分发器前需要创建表:

sql 复制代码
CREATE TABLE IF NOT EXISTS cosid (
    name            VARCHAR(100)  NOT NULL COMMENT '{namespace}.{name}',
    last_max_id     BIGINT        NOT NULL DEFAULT 0,
    last_fetch_time BIGINT        NOT NULL,
    CONSTRAINT cosid_pk PRIMARY KEY (name)
) ENGINE = InnoDB;

自动初始化配置(推荐):

yaml 复制代码
cosid:
  segment:
    distributor:
      type: jdbc
      jdbc:
        enable-auto-init-cosid-table: false      # 是否自动建表
        enable-auto-init-id-segment: true         # 是否自动初始化号段记录

8.6 GroupedIdSegmentDistributor(分组分发器)

扩展了基础分发器,支持按分组键进行 ID 分区:

java 复制代码
// 场景:租户隔离的 ID 生成
String tenantId = "tenant_001";
IdSegment segment = groupedDistributor.distributeGrouped(
    "namespace",
    "order_id",
    tenantId
);

优势

  • 不同租户/分组的 ID 序列相互隔离
  • 支持 allowReset() 在分组变更时重置号段

8.7 SegmentId 配置示例

yaml 复制代码
cosid:
  segment:
    enabled: true
    mode: normal  # 普通 SegmentId 模式(非链式)

    distributor:
      type: redis  # redis | jdbc | zookeeper | mongo

    share:
      offset: 0        # 起始偏移量
      step: 100        # 每次获取的号段长度

    provider:
      order:
        offset: 10000  # 订单业务的起始偏移
        step: 100
      user:
        offset: 20000  # 用户业务的起始偏移
        step: 100

8.8 SegmentId 性能特征

指标 说明
TPS 29,506,073 ops/s 号段未耗尽时的高性能
P9999 延迟 46.624 us/op 号段耗尽时同步获取导致延迟尖峰
稳定性 中等 受网络 IO 影响

9. SegmentChainId 号段链模式(推荐)⭐

9.1 为什么推荐 SegmentChainId?

SegmentChainId 是 SegmentId 的增强版,解决了 SegmentId 的稳定性问题:

复制代码
┌─────────────────────────────────────────────────────────────┐
│              SegmentId vs SegmentChainId 对比                │
├─────────────────────┬───────────────────────────────────────┤
│      SegmentId      │          SegmentChainId ⭐             │
├─────────────────────┼───────────────────────────────────────┤
│ 号段用完时同步等待   │ PrefetchWorker 预取,保持安全距离       │
│ P9999=46.624 us/op │ P9999=0.208 us/op(提升 224 倍!)    │
│ TPS=2950万/s       │ TPS=1.27亿+/s(提升 4.3 倍!)        │
│ Step 固定不可变     │ 安全距离动态伸缩(饥饿膨胀/收缩)        │
│ 无自适应性          │ 根据流量自动调整吞吐量                  │
└─────────────────────┴───────────────────────────────────────┘

9.2 核心设计:PrefetchWorker(预取工作线程)

复制代码
┌─────────────────────────────────────────────────────────────┐
│                 SegmentChainId 架构设计                      │
│                                                             │
│  ┌──────────────────────────────────────────────────────┐   │
│  │                  号段链 (Segment Chain)               │   │
│  │                                                      │   │
│  │  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐ │   │
│  │  │ 当前号段  │→ │ 缓冲号段1 │→ │ 缓冲号段2 │→ │ ...     │ │   │
│  │  │(正在使用) │  │(预取备用) │  │(预取备用) │  │(预取中) │ │   │
│  │  └─────────┘  └─────────┘  └─────────┘  └─────────┘ │   │
│  │       ↑                                              │   │
│  │       │ ID 获取线程(几乎无阻塞)                      │   │
│  │                                                      │   │
│  │  ┌──────────────────────────────────────────────┐    │   │
│  │  │         PrefetchWorker (后台预取线程)          │    │   │
│  │  │  职责: 维护安全距离 (safeDistance)             │    │   │
│  │  │  策略: 饥饿检测 → 动态膨胀/收缩安全距离         │    │   │
│  │  └──────────────────────────────────────────────┘    │   │
│  │                      ↓                                │   │
│  │            向 IdSegmentDistributor 请求新号段          │   │
│  └──────────────────────────────────────────────────────┘   │
│                                                             │
│  安全距离 (safeDistance):                                    │
│  ├─ 充足时: 收缩,减少内存占用和 ID 乱序                     │
│  └─ 不足时 (饥饿): 膨胀,提高吞吐量                          │
└─────────────────────────────────────────────────────────────┘

9.3 自适应机制(Adaptability)

SegmentChainId 引入饥饿状态概念,PrefetchWorker 根据饥饿状态动态调整安全距离:

复制代码
流量突增场景:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━► 时间
     ↑流量                    ↑流量下降
     │                         │
     ▼                         ▼
┌─────────┐              ┌─────────┐
│ 饥饿状态 │ → 安全距离膨胀 │ 恢复正常 │ → 安全距离收缩
│ (step×2)│              │         │
└─────────┘              └─────────┘

膨胀系数 (Expansion): 默认为 2
公式: 新安全距离 = 当前安全距离 × Expansion

9.4 性能极限公式

复制代码
TPS(SegmentChainId)极限值 = min(
    TPS(AtomicLong),                    // 上限: AtomicLong 性能
    (Step × Expansion) × TPS(Distributor) × T / s
)

其中:
- Step: 号段步长
- Expansion: 饥饿膨胀系数(默认 2)
- TPS(Distributor): 分发器的 TPS 性能
- T: 基准测试运行时长
- s: 秒

关键结论

  • 只要给足够的时间膨胀,任何分发器都能达到接近 AtomicLong 的性能上限
  • Redis 分发器膨胀更快,达到上限所需时间更短
  • 这解释了为什么不同性能的分发器最终都能达到 TPS=1.27亿/s

9.5 SegmentChainId 配置

yaml 复制代码
cosid:
  segment:
    enabled: true
    mode: chain  # ⭐ 号段链模式(推荐)

    chain:
      safe-distance: 5              # 初始安全距离(预取号段数)
      prefetch-worker:
        core-pool-size: 2           # 预取线程池核心大小
        prefetch-period: 1s         # 预取周期

    distributor:
      type: redis  # redis | jdbc | zookeeper | mongo

    share:
      offset: 0
      step: 100                    # 推荐:较小 Step,让 PrefetchWorker 自动调节

    provider:
      order:
        offset: 10000
        step: 100
      payment:
        offset: 20000
        step: 50                   # 高频业务可以用较小 Step

9.6 代码中使用 SegmentChainId

java 复制代码
@Resource
private IdGeneratorProvider provider;

@Resource
private IdSegmentDistributorFactory idSegmentDistributorFactory;

/**
 * 通过代码动态注册 SegmentChainId
 */
public void registerIdGenerator(String idName) {
    IdSegmentDistributorDefinition definition =
        new IdSegmentDistributorDefinition("namespace", idName, 0, 100);

    IdSegmentDistributor distributor =
        idSegmentDistributorFactory.create(definition);

    SegmentChainId segmentChainId = new SegmentChainId(distributor);
    provider.set(idName, segmentChainId);
}

/**
 * 使用已注册的 ID 生成器
 */
public Long nextOrderId() {
    return provider.get("order").generate();
}

10. 机器号分配器 MachineIdDistributor

10.1 概述

MachineIdDistributor 负责 SnowflakeId 的机器号分配,同时存储 MachineId 的上一次时间戳,用于启动时时钟回拨检查。

10.2 六种分配器实现

# 分配器类型 类名 适用场景 配置值
1 手动分配 ManualMachineIdDistributor 极小规模集群(< 5节点)、测试环境 manual
2 K8s StatefulSet StatefulSetMachineIdDistributor Kubernetes StatefulSet 部署 stateful_set
3 Redis RedisMachineIdDistributor 已有 Redis 基础设施 redis
4 JDBC JdbcMachineIdDistributor 关系型数据库为主 jdbc
5 ZooKeeper ZookeeperMachineIdDistributor 已有 ZK 集群、强一致性要求 zookeeper
6 MongoDB MongoMachineIdDistributor MongoDB 生态 mongo

10.3 各分配器详细配置

① ManualMachineIdDistributor(手动)
yaml 复制代码
cosid:
  snowflake:
    machine:
      distributor:
        type: manual
        manual:
          machine-id: 0  # 手动指定机器号(0~1023)

适用场景 :开发环境、极小规模生产集群

缺点:需要人工管理,容易重复或遗漏

② StatefulSetMachineIdDistributor(K8s StatefulSet)
yaml 复制代码
cosid:
  snowflake:
    machine:
      distributor:
        type: stateful_set
        # 自动从 Kubernetes StatefulSet 的 HOSTNAME 解析机器号
        # 例如: order-service-0 → machineId=0
        #       order-service-1 → machineId=1

适用场景 :Kubernetes 生产环境、云原生部署

前提条件:Pod 必须以 StatefulSet 方式部署(而非 Deployment)

③ RedisMachineIdDistributor
yaml 复制代码
cosid:
  snowflake:
    machine:
      distributor:
        type: redis
        # 使用 Redis 存储机器号和最后时间戳
        # 自动分配,无需手动配置

优点

  • 自动分配,无需人工干预
  • 存储 MachineState(机器号 + 最后时间戳),支持启动时时钟回拨检查
  • 利用已有的 Redis 基础设施
④ JdbcMachineIdDistributor
yaml 复制代码
cosid:
  snowflake:
    machine:
      distributor:
        type: jdbc
        jdbc:
          enable-auto-init-cosid-machine-table: true  # 自动建表

需要的表结构

sql 复制代码
CREATE TABLE IF NOT EXISTS cosid_machine (
    namespace     VARCHAR(100)  NOT NULL,
    instance_id   VARCHAR(100)  NOT NULL,
    machine_id    INT           NOT NULL,
    last_timestamp BIGINT       NOT NULL,
    PRIMARY KEY (namespace, instance_id),
    INDEX idx_namespace (namespace),
    INDEX idx_instance_id (instance_id)
) ENGINE = InnoDB;
⑤ ZookeeperMachineIdDistributor
yaml 复制代码
cosid:
  snowflake:
    machine:
      distributor:
        type: zookeeper
        # 使用 ZooKeeper 的临时顺序节点自动分配机器号

优点:强一致性保证、天然支持故障检测

⑥ MongoMachineIdDistributor
yaml 复制代码
cosid:
  snowflake:
    machine:
      distributor:
        type: mongo
        # 使用 MongoDB 存储机器号信息

10.4 MachineState(机器状态)

java 复制代码
public class MachineState {
    public static final MachineState NOT_FOUND = of(-1, -1);

    private final int machineId;      // 机器号
    private final long lastTimeStamp; // 最后一次生成 ID 的时间戳

    // getters, factory method of(...)
}

用途

  • 运行时时钟回拨检测:比较当前时间与 lastTimeStamp
  • 启动时时钟回拨检测:从外部存储恢复 lastTimeStamp

10.5 MachineStateStorage(机器状态存储)

yaml 复制代码
# 本地文件存储(适用于稳定部署环境)
cosid:
  snowflake:
    machine:
      state-storage:
        local:
          state-location: ./cosid-machine-state/

LocalMachineStateStorage

  • 使用本地文件存储 MachineState
  • 仅适用于实例部署环境稳定的场景
  • 如果 Pod 可能漂移到不同节点,应使用 Redis/JDBC 等分布式存储

10.6 机器号守护(Machine Guarder)

yaml 复制代码
cosid:
  snowflake:
    machine:
      guarder:
        enabled: true  # 开启守护线程,定期续约机器号

作用:防止因网络抖动等原因导致机器号被回收


11. 时钟回拨问题解决方案

11.1 问题背景

时钟回拨的致命问题是会导致 ID 重复、冲突,这是绝对不能容忍的。

重要理解 :我们解决的时钟回拨问题是当前 MachineId 的时钟回拨,而不是所有集群节点的时钟回拨。

11.2 两种时钟回拨场景

复制代码
┌─────────────────────────────────────────────────────────────┐
│                   时钟回拨两种场景                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  场景1: 运行时时钟回拨                                       │
│  ─────────────────────                                      │
│  时间轴: ──────T1───────T2(T1+100ms)───T'(T1-50ms)───      │
│                        ↑            ↑                      │
│                    正常生成        时钟回拨!                  │
│                                                             │
│  解决: 存储 lastTimestamp,检测到回抛异常或等待同步            │
│                                                             │
│  场景2: 启动时时钟回拨                                        │
│  ─────────────────────                                      │
│  上次关闭: T_close = 2024-01-01 12:00:00                    │
│  本次启动: T_start  = 2024-01-01 11:59:58  (时钟回拨2秒)     │
│                                                             │
│  解决: 从外部存储恢复 MachineState,比较 lastTimestamp        │
└─────────────────────────────────────────────────────────────┘

11.3 ClockBackwardsSynchronizer(时钟回拨同步器)

java 复制代码
/**
 * 默认的时钟回拨同步器
 * 策略: 主动等待时钟同步
 */
public class DefaultClockBackwardsSynchronizer implements ClockBackwardsSynchronizer {

    private final long spinThreshold;   // 自旋阈值(默认 10ms)
    private final long brokenThreshold; // 异常阈值(默认 2000ms)

    /**
     * 同步策略:
     * 1. 回拨 < spinThreshold: 自旋等待(忙等待,CPU 密集)
     * 2. 回拨 >= spinThreshold: 线程睡眠等待
     * 3. 回拨 > brokenThreshold: 抛出 ClockTooManyBackwardsException
     */
    public void synchronize(long backwardsMillis) { ... }
}

配置参数

yaml 复制代码
cosid:
  snowflake:
    clock-backwards:
      spin-threshold: 10     # 自旋等待阈值(毫秒)
      broken-threshold: 2000 # 异常阈值(毫秒,超过此值直接抛异常)

11.4 ClockSyncSnowflakeId vs 默认 SnowflakeId

特性 默认 SnowflakeId ClockSyncSnowflakeId
时钟回拨处理 直接抛出 ClockBackwardsException 主动等待同步后重新生成
用户体验 差(下游无法处理) 好(透明处理)
推荐程度 不推荐 推荐生产使用

开启方式

yaml 复制代码
cosid:
  snowflake:
    share:
      clock-sync: true  # 开启时钟同步模式

12. IdGeneratorProvider 多业务支持

12.1 为什么需要 Provider?

在实际业务中,不同的业务通常使用不同的 ID 生成器

  • 订单服务:order-service → 订单 ID
  • 用户服务:user-service → 用户 ID
  • 支付服务:payment-service → 支付流水号

IdGeneratorProvider 就是 IdGenerator 的容器,通过业务名称获取对应的 IdGenerator。

12.2 通过配置文件注册

yaml 复制代码
cosid:
  segment:
    enabled: true
    mode: chain
    distributor:
      type: redis
    share:
      offset: 0
      step: 100
    provider:  # ⭐ 注册多个命名 ID 生成器
      order:           # 名称为 "order" 的 ID 生成器
        offset: 10000
        step: 100
      user:            # 名称为 "user" 的 ID 生成器
        offset: 20000
        step: 100
      payment:         # 名称为 "payment" 的 ID 生成器
        offset: 30000
        step: 50

12.3 在代码中使用

java 复制代码
@Service
public class OrderService {

    @Resource
    private IdGeneratorProvider provider;

    /**
     * 获取指定业务的 ID 生成器
     */
    public Long createOrder() {
        // 获取名为 "order" 的 ID 生成器
        IdGenerator orderGenerator = provider.get("order");
        Long orderId = orderGenerator.generate();

        // ... 创建订单逻辑
        return orderId;
    }

    public Long createUser() {
        IdGenerator userGenerator = provider.get("user");
        return userGenerator.generate();
    }
}

12.4 通过代码动态注册

java 复制代码
@Component
public class IdGeneratorInitializer implements CommandLineRunner {

    @Resource
    private IdGeneratorProvider provider;

    @Resource
    private IdSegmentDistributorFactory idSegmentDistributorFactory;

    @Override
    public void run(String... args) throws Exception {
        // 动态注册新的 ID 生成器
        registerIdGenerator("invoice");
        registerIdGenerator("refund");
    }

    private void registerIdGenerator(String idName) {
        IdSegmentDistributorDefinition definition =
            new IdSegmentDistributorDefinition("my_app", idName, 0, 100);

        IdSegmentDistributor distributor =
            idSegmentDistributorFactory.create(definition);

        SegmentChainId segmentChainId = new SegmentChainId(distributor);
        provider.set(idName, segmentChainId);
    }
}

12.5 Bean Name 规则

配置名称 Bean Name 类型
共享(默认) __share__SegmentId SegmentId
共享(默认) __share__SnowflakeId SnowflakeId
命名: order orderSegmentId SegmentId
命名: user userSnowflakeId SnowflakeId

注入方式

java 复制代码
@Autowired
@Qualifier("__share__SegmentId")
@Lazy
private SegmentId segmentId;

@Autowired
@Qualifier("orderSegmentId")
@Lazy
private SegmentId orderSegmentId;

13. MyBatis 插件集成

13.1 概述

CosId 提供 MyBatis 插件 (CosIdPlugin),通过 @CosId 注解实现实体类字段的自动 ID 生成。

13.2 添加依赖

kotlin 复制代码
// Gradle Kotlin DSL
implementation("me.ahoo.cosid:cosid-mybatis:${cosidVersion}")
xml 复制代码
<!-- Maven -->
<dependency>
    <groupId>me.ahoo.cosid</groupId>
    <artifactId>cosid-mybatis</artifactId>
    <version>${cosid.version}</version>
</dependency>

13.3 @CosId 注解说明

java 复制代码
@Target({ElementType.FIELD})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface CosId {
    /**
     * ID 生成器名称,默认使用共享生成器 (__share__)
     */
    String value() default IdGeneratorProvider.SHARE;

    /**
     * 是否使用友好 ID 格式(SnowflakeIdState.toString())
     * 如: 20210623131730192-1-0
     */
    boolean friendlyId() default false;
}

13.4 使用示例

场景一:Long 类型 ID
java 复制代码
public class OrderEntity {

    @CosId(value = "order")  // 使用名为 "order" 的 ID 生成器
    private Long id;

    private String orderNo;
    private BigDecimal amount;

    // getters and setters...
}
场景二:友好 ID(String 类型)
java 复制代码
public class FriendlyIdEntity {

    @CosId(friendlyId = true)  // 生成友好格式的字符串 ID
    private String id;
    // id 值示例: "20210623131730192-1-0"

    // getters and setters...
}
场景三:Mapper 接口
java 复制代码
@Mapper
public interface OrderRepository {

    @Insert("INSERT INTO t_order (id, order_no, amount) VALUES (#{id}, #{orderNo}, #{amount})")
    void insert(OrderEntity order);

    @Insert({
        "<script>",
        "INSERT INTO t_friendly_table (id)",
        "VALUES",
        "<foreach item='item' collection='list' open='' separator=',' close=''>",
        "(#{item.id})",
        "</foreach>",
        "</script>"
    })
    void insertList(List<FriendlyIdEntity> list);
}

13.5 使用效果

java 复制代码
@Service
public class OrderService {

    @Autowired
    private OrderRepository orderRepository;

    public OrderEntity createOrder() {
        OrderEntity order = new OrderEntity();
        order.setOrderNo("ORD-20240101-001");
        order.setAmount(new BigDecimal("99.99"));

        // 插入时,@CosId 注解的字段会自动填充 ID
        orderRepository.insert(order);

        // order.getId() 已经有值,例如: 208796080181248
        return order;
        /**
         * 返回结果:
         * {
         *   "id": 208796080181248,
         *   "orderNo": "ORD-20240101-001",
         *   "amount": 99.99
         * }
         */
    }
}

14. ShardingSphere 分片集成

14.1 概述

CosId 为 Apache ShardingSphere 提供了两个高性能插件:

  1. CosIdKeyGenerateAlgorithm - 分布式主键生成
  2. CosIdIntervalShardingAlgorithm - 基于间隔的时间范围分片
  3. CosIdModShardingAlgorithm - 高性能取模分片

14.2 CosIdKeyGenerateAlgorithm(分布式主键)

yaml 复制代码
spring:
  shardingsphere:
    rules:
      sharding:
        key-generators:
          cosid:
            type: COSID  # 使用 CosId 作为主键生成器
            props:
              id-name: __share__  # 指定使用的 ID 生成器名称

14.3 CosIdIntervalShardingAlgorithm(时间范围分片)

优势对比官方实现

特性 CosId 实现 官方 IntervalShardingAlgorithm
数据类型支持 Long/LocalDateTime/DATE/String/SnowflakeId 先转 String 再转 LocalDateTime
转换成功率 高(直接解析) 受时间格式化字符影响
性能 高出 1200~4000 倍 基准

配置示例

yaml 复制代码
spring:
  shardingsphere:
    rules:
      sharding:
        sharding-algorithms:
          order-date-interval:
            type: COSID_INTERVAL  # CosId 时间范围分片
            props:
              logic-name-prefix: t_order_      # 逻辑表名前缀
              id-name: cosid-name              # ID 生成器名称
              datetime-lower: 2021-12-08 22:00:00  # 时间下界
              datetime-upper: 2022-12-01 00:00:00  # 时间上界
              sharding-suffix-pattern: yyyyMM       # 分片后缀格式
              datetime-interval-unit: MONTHS         # 间隔单位
              datetime-interval-amount: 1            # 间隔数量

        tables:
          t_order_log:
            actual-data-nodes: ds0.t_order_log_{202112..202212}
            table-strategy:
              standard:
                sharding-column: create_time
                sharding-algorithm-name: order-date-interval

支持的类型变体

Type 说明
COSID_INTERVAL 通用时间范围分片
COSID_INTERVAL_SNOWFLAKE SnowflakeId 时间范围分片(直接从 ID 解析时间)

14.4 CosIdModShardingAlgorithm(取模分片)

性能优势 :比官方 ModShardingAlgorithm 高出 1200~4000 倍,且不会出现严重性能退化

yaml 复制代码
spring:
  shardingsphere:
    rules:
      sharding:
        sharding-algorithms:
          order-mod:
            type: COSID_MOD  # CosId 取模分片
            props:
              mod: 4                    # 取模数(分片数量)
              logic-name-prefix: t_order_  # 逻辑表名前缀

        tables:
          t_order:
            actual-data-nodes: ds0.t_order_{0..3}
            table-strategy:
              standard:
                sharding-column: id
                sharding-algorithm-name: order-mod

15. 完整配置参考手册

15.1 完整 application.yml 模板

yaml 复制代码
# ============================================================
# CosId 完整配置模板(生产环境参考)
# ============================================================

spring:
  data:
    redis:
      host: localhost
      port: 6379

  datasource:
    url: jdbc:mysql://localhost:3306/cosid_db?useUnicode=true&characterEncoding=utf-8
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

cosid:
  # ----------------------------------------------------------
  # 基础配置
  # ----------------------------------------------------------
  namespace: ${spring.application.name}  # 命名空间,用于隔离不同应用

  # ----------------------------------------------------------
  # 机器号分配(SnowflakeId 需要)
  # ----------------------------------------------------------
  machine:
    enabled: true
    #    stable: true
    #    machine-bit: 10
    #    instance-id: ${HOSTNAME}
    distributor:
      type: redis  # manual | stateful_set | redis | jdbc | zookeeper | mongo
    #        manual:
    #          machine-id: 0
    guarder:
      enabled: true  # 开启机器号守护
    state-storage:
      local:
        state-location: ./cosid-machine-state/

  # ----------------------------------------------------------
  # SnowflakeId 雪花算法配置
  # ----------------------------------------------------------
  snowflake:
    enabled: true
    #    epoch: 1577203200000  # 自定义纪元(毫秒时间戳)
    zone-id: Asia/Shanghai

    clock-backwards:
      spin-threshold: 10      # 自旋等待阈值(毫秒)
      broken-threshold: 2000  # 异常阈值(毫秒)

    share:
      clock-sync: true        # 开启时钟同步模式(推荐)
      friendly: true          # 开启友好 ID 解析

    provider:
      # 注册多个命名 SnowflakeId 生成器
      bizA:
        sequence-bit: 12
      bizB:
        sequence-bit: 12
      safeJs:
        machine-bit: 3        # JS 安全模式
        sequence-bit: 9

  # ----------------------------------------------------------
  # SegmentId / SegmentChainId 号段算法配置
  # ----------------------------------------------------------
  segment:
    enabled: true
    mode: chain               # normal | chain(推荐 chain)

    chain:
      safe-distance: 5        # 初始安全距离
      prefetch-worker:
        core-pool-size: 2     # 预取线程池大小
        prefetch-period: 1s   # 预取周期

    distributor:
      type: redis             # redis | jdbc | zookeeper | mongo
      jdbc:
        enable-auto-init-cosid-table: false
        enable-auto-init-id-segment: true

    share:
      offset: 0               # 全局起始偏移量
      step: 100               # 全局默认步长

    provider:
      # 注册多个命名 SegmentChainId 生成器
      order:
        offset: 10000
        step: 100
      user:
        offset: 20000
        step: 100
      payment:
        offset: 30000
        step: 50

  # ----------------------------------------------------------
  # CosIdGenerator 配置(可选)
  # ----------------------------------------------------------
  #  cosid-generator:
  #    radix: base36  # base36 | base62

15.2 配置项速查表

配置路径 类型 默认值 说明
cosid.namespace String ${spring.application.name} 命名空间
cosid.machine.enabled Boolean false 是否启用机器号分配
cosid.machine.distributor.type String - 机器号分发器类型
cosid.snowflake.enabled Boolean false 是否启用 SnowflakeId
cosid.snowflake.epoch Long - 自定义纪元时间戳
cosid.snowflake.clock-backwards.spin-threshold Integer 10 自旋阈值(ms)
cosid.snowflake.clock-backwards.broken-threshold Integer 2000 异常阈值(ms)
cosid.snowflake.share.clock-sync Boolean false 时钟同步模式
cosid.snowflake.share.friendly Boolean false 友好 ID 模式
cosid.segment.enabled Boolean false 是否启用号段模式
cosid.segment.mode String normal normal / chain
cosid.segment.chain.safe-distance Integer 5 安全距离
cosid.segment.distributor.type String - 号段分发器类型
cosid.segment.share.offset Long 0 起始偏移量
cosid.segment.share.step Integer 100 默认步长

16. 性能基准测试

16.1 测试环境

项目 规格
开发机 MacBook Pro (M1)
Java 版本 Java 17
Redis 本机部署
测试工具 JMH (Java Microbenchmark Harness)

16.2 SnowflakeId 性能

复制代码
Benchmark                                            Mode  Cnt        Score   Error  Units
SnowflakeIdBenchmark.millisecondSnowflakeId_friendlyId      thrpt    3  4020311.665          ops/s
SnowflakeIdBenchmark.millisecondSnowflakeId_generate        thrpt    3  4095403.859          ops/s
SnowflakeIdBenchmark.safeJsMillisecondSnowflakeId_generate  thrpt    3   511654.048          ops/s
SnowflakeIdBenchmark.safeJsSecondSnowflakeId_generate       thrpt    3   539818.563          ops/s
SnowflakeIdBenchmark.secondSnowflakeId_generate             thrpt    3  4206843.941          ops/s

解读

  • 标准 SnowflakeId: ~409 万 ops/s
  • SafeJavaScriptSnowflakeId: ~51 万 ops/s(因为位数少,序列号空间小)
  • FriendlyId(带解析): ~402 万 ops/s(略有开销)

16.3 SegmentChainId 性能

指标 说明
TPS 127,439,148+ ops/s 接近 AtomicLong 性能上限
P9999 延迟 0.208 us/op 极其稳定
对比 UUID 41x 更快 UUID: 307万 ops/s
对比 Leaf(segment) 5x 更快 美团 Leaf segment 模式

16.4 各算法性能汇总

复制代码
TPS 性能对比 (ops/s):

UUID/GUID:        ████ 3,078,638
SnowflakeId:      ████████████████████ 40,960,000
SegmentId:        ████████████████████████████████████████ 29,506,073
SegmentChainId:   █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ 127,439,148+
CosIdGenerator:   ██████████████████████████████████████████████████████████ 15,570,085

16.5 如何运行基准测试

bash 复制代码
# 方式一:Gradle 任务
gradle cosid-core:jmh

# 方式二:直接运行 JAR
java -jar cosid-core/build/libs/cosid-core-3.2.0-jmh.jar \
  -bm thrpt \
  -wi 1 \
  -rf json \
  -f 1

17. 最佳实践与生产建议

17.1 算法选择决策树

复制代码
你需要分布式 ID?
│
├─ 需要纯数字 Long 类型?
│  │
│  ├─ 高吞吐(> 1000万 TPS)?
│  │  └─ ★★★ 使用 SegmentChainId(推荐)
│  │
│  ├─ 中等吞吐(100万~1000万 TPS)?
│  │  ├─ 已有 Redis/MongoDB → SegmentChainId
│  │  └─ 无外部依赖 → SnowflakeId
│  │
│  └─ 低吞吐(< 100万 TPS)?
│     └─ SnowflakeId(简单可靠)
│
├─ 可以接受字符串 ID?
│  │
│  ├─ 需要短 ID(< 20字符)?
│  │  └─ CosIdGenerator(Base36/Base62)
│  │
│  └─ 需要可读 ID?
│     └─ SnowflakeFriendlyId(格式: 时间-机器-序列)
│
└─ 需要前端 JavaScript 兼容?
   └─ SafeJavaScriptSnowflakeId(≤ 53-bit)

17.2 生产环境 Checklist

✅ 必做项
  • 选择合适的分发器:优先使用已有基础设施(Redis/JDBC)
  • 开启时钟同步cosid.snowflake.share.clock-sync: true
  • 配置机器号守护cosid.machine.guarder.enabled: true
  • 设置合理的 epoch:自定义纪元为产品上线时间
  • 监控 ID 生成速率:避免接近理论上限
  • 备份 MachineState:确保重启后能恢复状态
⚠️ 注意事项
  • 不要同时启用共享的 SnowflakeId 和 SegmentId(会冲突)
  • Step 不要设置过大(建议 50~500,让 PrefetchWorker 自动调节)
  • safeDistance 不要设置过小(建议 ≥ 3)
  • JDBC 分发器注意连接池配置
🔧 高级优化
  • 按业务拆分 provider:不同业务使用不同命名空间
  • 监控 PrefetchWorker 状态:观察饥饿膨胀频率
  • 设置 brokenThreshold 合理值:建议 1000~3000ms
  • 考虑多机房容灾:分发器跨机房部署

17.3 分发器选择指南

场景 推荐分发器 理由
已有 Redis Redis 高性能、低延迟、已有连接
纯数据库架构 JDBC 无额外组件、事务一致
强一致性要求 ZooKeeper CP 模型、原生分布式锁
MongoDB 生态 MongoDB 文档模型自然适配
K8s 原生部署 StatefulSet 无需外部依赖
开发/测试 Manual 最简单、可控

17.4 监控指标建议

指标 说明 告警阈值
ID 生成 TPS 每秒生成 ID 数量 接近理论上限的 80%
号段获取耗时 从分发器获取号段的延迟 > 100ms
时钟回拨次数 发生时钟回拨的频率 > 10次/分钟
PrefetchWorker 饥饿次数 安全距离不足的频率 持续饥饿
机器号分配失败 无法获取机器号的次数 > 0

18. 常见问题 FAQ

Q1: CosId 和美团 Leaf 有什么区别?

维度 CosId (SegmentChainId) Leaf (segment)
性能 5 倍 faster 基准
架构 嵌入式 SDK 独立服务(Leaf-Server)
部署复杂度 低(SDK 模式) 高(需部署 Leaf-Server)
语言支持 Java (Spring Boot) Java (Spring Boot)
算法丰富度 4 种算法 2 种算法

Q2: 同时开启 SnowflakeId 和 SegmentId 会怎样?

只有其中一个共享的 (__share__) IdGenerator 会注入到 Spring 容器,另一个会被忽略(Bean 名称冲突)。

解决方案 :通过 provider 配置显式注册多个命名 ID 生成器。

Q3: SegmentChainId 的安全距离应该设多大?

  • 初始值 :推荐 5(即预取 5 个号段作为缓冲)
  • 运行时:PrefetchWorker 会根据饥饿状态自动调整
  • 原则:宁可稍大(浪费少量 ID),不要过小(影响性能)

Q4: 为什么不同分发器最终都能达到相同性能?

因为 SegmentChainId 的极限性能主要取决于 AtomicLong 的性能上限饥饿膨胀机制,而不是分发器本身的 TPS。只要给足够时间膨胀,任何分发器都能达到接近上限的性能。

区别在于:高性能分发器(如 Redis)达到上限所需时间更短

Q5: 如何处理 JavaScript 的 Long 溢出问题?

三种方案:

  1. 转 String:直接将 Long 转 JSON 字符串
  2. SafeJavaScriptSnowflakeId:使用 ≤ 53-bit 的位分配
  3. SnowflakeFriendlyId:返回友好的字符串格式

Q6: 时钟回拨应该如何处理?

  1. 首选 :开启 clock-sync: true,让框架自动处理
  2. 监控:设置告警,及时发现时钟问题
  3. 根因:检查 NTP 配置、虚拟机时钟同步

Q7: CosId 支持哪些数据库?

  • JDBC 分发器:支持所有 JDBC 兼容的关系型数据库(MySQL、PostgreSQL、Oracle、SQL Server 等)
  • MongoDB 分发器:MongoDB 3.6+

Q8: 如何在现有项目中迁移到 CosId?

步骤

  1. 添加 CosId 依赖
  2. 配置分发器(选择已有基础设施)
  3. 逐步替换现有 ID 生成逻辑
  4. 验证 ID 唯一性和有序性
  5. 监控性能指标

相关推荐
凤凰院凶涛QAQ1 小时前
《Java版数据结构 & 集合类剖析》栈与队列:“push/pop 是栈的灵魂,offer/poll 是队列的骨架——四组 API,两种人生”
java·开发语言·数据结构
掘金_答案2 小时前
上线那天,一个 ConcurrentHashMap 差点送走我的 AI 客服——3 天排查 JVM 血泪史
java·后端·架构
MindUp3 小时前
企业网盘权限模型解析:多层级访问控制与审计能力选型指南
java·linux·运维
NG4773 小时前
【软件设计与体系结构】-策略设计模式
java·设计模式·软件工程
程序员天天困3 小时前
优雅记录操作日志:从注解到 SpEL 的全链路实践与开源方案对比
java·后端
战血石LoveYY4 小时前
Integer类型超限,导致数据异常
java·算法
乐观的Terry5 小时前
1、为什么要自己造发布系统
java·spring boot·后端·spring cloud·架构
兰令水5 小时前
hot100【acm版】【2026.7.13打卡-java版本】
java·开发语言·数据结构·算法·leetcode·面试
嗝屁小孩纸6 小时前
Maven版本升级&Nexus推送极简执行步骤
java·elasticsearch·maven