全新分布式ID组件TSID支持N种数据类型

TSID:时间排序唯一标识符的完整指南

1. 简介

标准的128位随机UUID虽然流行,但在数据库主键应用中存在显著缺陷:

UUID作为主键的问题:

  • 存储空间大:每条记录需要16字节,影响外键列存储
  • 索引效率低 :B+树索引随机值导致:
    • 填充因子低:8kB页只存储少量元素,浪费磁盘和内存
    • 频繁页分裂:随机插入导致索引频繁重新平衡
    • 缓存效率差:随机访问模式降低缓冲池效果

2. TSID核心概念

2.1 什么是TSID?

TSID(Time-Sorted Unique Identifier)融合了Twitter Snowflake和ULID思想:

  • ✅ 时间排序:按生成时间自然排序
  • ✅ 紧凑存储:64位整数或13字符字符串
  • ✅ Base32编码:采用Crockford编码,URL安全、无大小写敏感
  • ✅ 更短长度:比UUID、ULID、KSUID更短

2.2 TSID结构

复制代码
42位时间戳 + 22位随机部分
  • 时间部分(42位):自2020-01-01 00:00:00 UTC以来的毫秒数
  • 随机部分 (22位):
    • 节点标识符:0-20位(默认10位)
    • 计数器:2-22位(取决于节点位)
配置示例(默认):
  • 节点位:10位 → 最大节点值:2¹⁰-1 = 1023
  • 计数位:12位 → 最大计数值:2¹²-1 = 4095
  • 每毫秒最大TSID数:4096

2.3 基本使用

java 复制代码
// 1. 创建TSID对象
TSID tsid = TSID.Factory.getTsid();

// 2. 生成Long类型ID
long id = TSID.Factory.getTsid().toLong();  // 输出:797263809025044592

// 3. 生成String类型ID
String strId = TSID.Factory.getTsid().toString();  // 输出:0P43KE5EXXM3Z

// 4. 批量生成
for (int i = 0; i < 20; i++) {
    long id = TSID.Factory.getTsid().toLong();
    System.out.println(id);
}

// 5. 快速生成(每毫秒最多4,194,304个)
TSID fastTsid = TSID.fast();

// 6. 从字符串恢复
TSID tsid = TSID.from("0123456789ABC");
System.out.println(tsid.toLong());  // 输出:38390726480144748

// 7. 获取创建时间戳
Instant instant = TSID.Factory.getTsid().getInstant();
System.out.println(instant);  // 输出:2026-01-01T01:03:34.735Z

// 8. Base-62编码
String base62 = TSID.Factory.getTsid().encode(62);
System.out.println(base62);  // 输出:0wtVRVNVMwu

// 9. 格式化输出
String formatted = tsid.format("pack%S");
System.out.println(formatted);  // 输出:pack0P43SMJ0FH80H

2.4 密钥生成器实现

java 复制代码
public class KeyGenerator {
    public static String next() {
        return TSID.Factory.getTsid().toString();
    }
}

// 使用
KeyGenerator.next();  // 0P43T4Z0VAC3S
KeyGenerator.next();  // 0P43T4Z0VAC3T
KeyGenerator.next();  // 0P43T4Z0VAC3V

2.5 模拟Twitter Snowflake

java 复制代码
// Twitter Snowflake配置
int datacenter = 1;  // 最大值:31 (2⁵-1)
int worker = 1;      // 最大值:31 (2⁵-1)
int node = (datacenter << 5 | worker);  // 最大值:1023 (2¹⁰-1)

Instant customEpoch = Instant.ofEpochMilli(1288834974657L);
IntFunction<byte[]> randomFunction = (x) -> new byte[x];

TSID.Factory factory = TSID.Factory.builder()
    .withRandomFunction(randomFunction)
    .withCustomEpoch(customEpoch)
    .withNode(node)
    .build();

TSID tsid = factory.generate();
for (int i = 0; i < 5; i++) {
    System.out.println(tsid.toLong());
}

3. JPA集成示例

3.1 TSID组件配置

java 复制代码
@Component
public class TsidComponent {
    public static final String TSID_NODE_COUNT_PROPERTY = "tsid.node.count";
    public static final String TSID_NODE_COUNT_ENV = "TSID_NODE_COUNT";
    public static TSID.Factory TSID_FACTORY;
    
    static {
        String nodeCountSetting = System.getProperty(TSID_NODE_COUNT_PROPERTY);
        if (nodeCountSetting == null) {
            nodeCountSetting = System.getenv(TSID_NODE_COUNT_ENV);
        }
        int nodeCount = nodeCountSetting != null ? 
            Integer.parseInt(nodeCountSetting) : 256;
        TSID_FACTORY = getTsidFactory(nodeCount);
    }
    
    public static TSID.Factory getTsidFactory(int nodeCount, int nodeId) {
        int nodeBits = ((int) (Math.log(nodeCount) / Math.log(2))) + 1;
        return TSID.Factory.builder()
            .withRandomFunction(TSID.Factory.THREAD_LOCAL_RANDOM_FUNCTION)
            .withNodeBits(nodeBits)
            .withNode(nodeId)
            .build();
    }
}

3.2 自定义ID生成器注解

java 复制代码
// ID生成器类型注解
@IdGeneratorType(PackIdGenerator.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.FIELD })
public @interface PackSequence {
}

// 实体类使用
@Entity
@Table(name = "o_student")
public class Student {
    @Id
    @PackSequence
    private Long id;
    
    private String name;
    private String sno;
    
    // getters and setters
}

3.3 测试示例

java 复制代码
@Resource
private StudentService studentService;

@Test
public void testSave() {
    for (int i = 0; i < 10; i++) {
        Student student = new Student();
        student.setName("pack_xg_%s".formatted(i));
        student.setSno("X00002-%s".formatted(i));
        this.studentService.save(student);
    }
}

4. TSID优势总结

特性 UUID 自增ID TSID
排序性 随机无序 单库有序 时间有序
分布式 支持 不支持 完美支持
存储空间 16字节 通常8字节 8字节
索引性能 差(随机插入) 好(顺序插入) 优秀
可读性 差(长字符串) 好(数字) 好
冲突概率 极低 无(单库) 极低

5. 适用场景

  1. 微服务架构:分布式系统需要全局唯一ID
  2. 数据库分片:跨多个数据库实例保持ID唯一性
  3. 时间序列数据:日志、事件流等按时间排序的数据
  4. 高并发系统:需要高性能ID生成的场景
  5. 替代UUID:需要保持唯一性但提升数据库性能的场景

6. 注意事项

  1. 时间回拨:系统时间回拨可能导致ID冲突,TSID内置了时间保护机制
  2. 节点配置:在生产环境中合理配置节点ID,避免冲突
  3. 安全性 :对于安全敏感场景,使用Factory.getTsid()而非fast()
  4. 迁移成本:从现有ID方案迁移需要考虑数据迁移和兼容性

TSID为现代分布式系统提供了一个高性能、可扩展且数据库友好的ID生成解决方案。

相关推荐
此时不提桶,更待何时8 小时前
06-12-A-Kafka存储深水区与源码解析详解
分布式·kafka·linq
此时不提桶,更待何时12 小时前
06-15-A-Kafka生态集成与流处理详解
分布式·kafka
此时不提桶,更待何时16 小时前
06-13-A-Kafka客户端与协议深入详解
分布式·kafka
程序猿乐锅1 天前
从0-1一文详解RabbitMQ
java·分布式·后端·中间件·rabbitmq·ruby
老陈说编程2 天前
1. 鸿蒙 (HarmonyOS) 2012 至 2026 年的发展历程
分布式·华为·个人开发·harmonyos·鸿蒙·鸿蒙系统·程序员创富
ly76894 天前
Redis 分布式锁的边界条件:Redlock 争议、锁续期与客户端崩溃后的互斥失效
数据库·redis·分布式·分布式锁·watchdog·redlock
灯澜忆梦4 天前
【minio】#5 | MinIO 分布式部署 + HTTPS 部署
分布式·网络协议·https·对象存储·minio
谢亮_vipxieliang4 天前
Spring Cloud 服务治理入门:注册发现、配置中心、网关限流、熔断降级与分布式一致性方案
分布式·spring·spring cloud
樱花落木兰4 天前
分布式登录实战:Session 会话共享改造,Redis 存储用户登录状态
java·javascript·数据库·redis·分布式·缓存