Sharding-JDBC 实战 - 分布式唯一主键

在分布式系统中,生成唯一主键是一个常见的需求。在使用 Sharding-JDBC 进行分库分表时,生成唯一主键需要考虑到分布式环境下的唯一性和性能。以下是一种实战方案:

实现分布式唯一主键的方案

1. 使用数据库自增主键

对于单库单表的场景,可以使用数据库自增主键来生成唯一主键。但是在分库分表的情况下,由于每个库表都有独立的自增序列,无法保证全局唯一性。

2. 使用 UUID

可以使用 UUID 来生成唯一主键,UUID 保证了全局唯一性,但会导致主键过长,不利于索引和存储空间的利用。

3. 使用 Snowflake 算法

Snowflake 是一种分布式唯一 ID 生成算法,可以生成全局唯一且有序的 ID。它的特点是:

  • 时间有序性:生成的 ID 是递增的,保证了索引的顺序性和性能。
  • 唯一性:在同一时空中不会生成重复的 ID。
  • 高性能:生成 ID 的性能非常高。

Snowflake 算法使用一个 64 位的 long 型数字作为全局唯一 ID,结构如下:

 0 | timestamp(ms) | data center id | machine id | sequence

其中,timestamp(ms) 表示当前时间戳,data center id 和 machine id 可以根据实际情况分配,sequence 表示同一时间戳下的序列号,保证了同一毫秒内生成的 ID 的唯一性。

实现步骤

  1. 引入 Snowflake 算法的实现库,如 Twitter 的 Snowflake 或者自己实现一个 Snowflake 算法。
  2. 在应用启动时初始化 Snowflake 算法的实例。
  3. 每次生成唯一主键时调用 Snowflake 算法实例的 nextId() 方法获取唯一 ID。

示例代码

public class SnowflakeIdGenerator {
    private final long workerId;
    private final long datacenterId;
    private long sequence = 0L;
    private final long twepoch = 1288834974657L;
    private final long workerIdBits = 5L;
    private final long datacenterIdBits = 5L;
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
    private final long sequenceBits = 12L;
    private final long workerIdShift = sequenceBits;
    private final long datacenterIdShift = sequenceBits + workerIdBits;
    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
    private final long sequenceMask = -1L ^ (-1L << sequenceBits);
    private long lastTimestamp = -1L;

    public SnowflakeIdGenerator(long workerId, long datacenterId) {
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }

    public synchronized long nextId() {
        long timestamp = timeGen();
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }
        lastTimestamp = timestamp;
        return ((timestamp - twepoch) << timestampLeftShift) |
                (datacenterId << datacenterIdShift) |
                (workerId << workerIdShift) |
                sequence;
    }

    protected long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    protected long timeGen() {
        return System.currentTimeMillis();
    }
}
注意事项
  • 在分布式环境中,确保每个节点的 workerId 和 datacenterId 不重复。
  • Snowflake 算法要求时钟不可回退,确保服务器的时钟同步性。

以上是使用 Snowflake 算法实现分布式唯一主键的方案。根据具体业务需求和分布式环境的特点,选择合适的方案来生成唯一主键。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值