Java分布式全局唯一Id:id生成要求、为什么不用UUID、生成分布式雪花Id
在分布式系统中生成全局唯一ID(Global Unique Identifier,GUID)是一个常见的需求。以下是几种可能的方法:
- 使用数据库的自增主键:适用于单点数据库,不适合分布式场景。
- 使用Redis的INCR命令:可以生成唯一的递增ID,但不保证全局唯一。
- 使用UUID:虽然可以生成全局唯一ID,但不适合作为数据库索引。
- 使用雪花算法(Snowflake):结合时间戳、机器ID和序列号生成唯一ID,适合分布式系统。
为什么不用UUID:
- UUID生成的ID过长,不适合作为数据库索引。
- UUID的随机性不够,不适合安全敏感的应用场景。
生成分布式雪花Id的Java代码示例:
public class SnowflakeIdGenerator {
private final long twepoch = 1288834974657L; // 起始时间戳
private final long workerIdBits = 5L; // 机器ID所占的位数
private final long datacenterIdBits = 5L; // 数据中心ID所占的位数
private final long maxWorkerId = -1L ^ (-1L << workerIdBits); // 机器ID的最大值
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); // 数据中心ID的最大值
private final long sequenceBits = 12L; // 序列号所占的位数
private final long workerIdShift = sequenceBits; // 机器ID向左移多少位
private final long datacenterIdShift = sequenceBits + workerIdBits; // 数据中心ID向左移多少位
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; // 时间戳向左移多少位
private final long sequenceMask = -1L ^ (-1L << sequenceBits); // 序列号的掩码
private long workerId; // 机器ID
private long datacenterId; // 数据中心ID
private long sequence = 0L; // 序列号
private long lastTimestamp = -1L; // 上一次时间戳
public SnowflakeIdGenerator(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException("worker Id can't be greater than %d or less than 0");
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException("datacenter Id can't be greater than %d or less than 0");
}
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);
}
评论已关闭