全新分布式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生成解决方案。

相关推荐
渔民小镇6 小时前
一次编写到处对接 —— 为 Godot/Unity/React 生成统一交互接口
java·分布式·游戏·unity·godot
愈努力俞幸运6 小时前
docker入门,容器,镜像
java·分布式·docker
珠海西格电力6 小时前
红区光伏与零碳园区:管理系统如何破解分布式光伏并网困局
大数据·人工智能·分布式·物联网·能源
大大大大晴天️6 小时前
大数据分布式处理基石:分布式理论深度解析
大数据·分布式
枫叶林FYL8 小时前
【自然语言处理 NLP】8.2 Ring Attention 与分布式长上下文训练
人工智能·分布式·自然语言处理
薛定猫AI8 小时前
【深度解析】Meta Muse Spark:原生多模态推理模型与多智能体编排的工程化实践
大数据·分布式·spark
小白学大数据21 小时前
Scrapy 分布式爬虫:大规模采集汽车之家电车评论
开发语言·分布式·爬虫·scrapy
仗剑_走天涯1 天前
hadoop reduce阶段 对象重用问题
大数据·hadoop·分布式
电磁脑机1 天前
无总线场同步:意识本质、AGI困境与脑机革命的核心理论重构
分布式·神经网络·架构·信号处理·agi
半桶水专家1 天前
kafka数据删除策略详解
分布式·kafka