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

相关推荐
ALex_zry21 小时前
Redis Cluster 分布式缓存架构设计与实践
redis·分布式·缓存
为什么不问问神奇的海螺呢丶1 天前
n9e categraf rabbitmq监控配置
分布式·rabbitmq·ruby
TTBIGDATA1 天前
【Atlas】Atlas Hook 消费 Kafka 报错:GroupAuthorizationException
hadoop·分布式·kafka·ambari·hdp·linq·ranger
m0_687399841 天前
telnet localhost 15672 RabbitMQ “Connection refused“ 错误表示目标主机拒绝了连接请求。
分布式·rabbitmq
陌上丨1 天前
生产环境分布式锁的常见问题和解决方案有哪些?
分布式
新新学长搞科研1 天前
【智慧城市专题IEEE会议】第六届物联网与智慧城市国际学术会议(IoTSC 2026)
人工智能·分布式·科技·物联网·云计算·智慧城市·学术会议
泡泡以安1 天前
Scrapy分布式爬虫调度器架构设计说明
分布式·爬虫·scrapy·调度器
没有bug.的程序员1 天前
RocketMQ 与 Kafka 深度对垒:分布式消息引擎内核、事务金融级实战与高可用演进指南
java·分布式·kafka·rocketmq·分布式消息·引擎内核·事务金融
上海锟联科技1 天前
250MSPS DAS 在地铁监测中够用吗?——来自上海锟联科技的工程实践
分布式·科技·分布式光纤传感·das解调卡·光频域反射·das
岁岁种桃花儿1 天前
深度解析DolphinScheduler核心架构:搭建高可用Zookeeper集群
linux·分布式·zookeeper