public class SnowflakeIdGenerator { private final long twepoch = 1609459200000L; // 2021-01-01 00:00:00 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 workerId; private long datacenterId; private long sequence = 0L; private long lastTimestamp = -1L; public SnowflakeIdGenerator(long workerId, long datacenterId) { if (workerId > maxWorkerId || workerId < 0) { throw new IllegalArgumentException("Worker ID out of range"); } if (datacenterId > maxDatacenterId || datacenterId < 0) { throw new IllegalArgumentException("Datacenter ID out of range"); } this.workerId = workerId; this.datacenterId = datacenterId; } public synchronized long nextId() { long timestamp = timeGen(); if (timestamp < lastTimestamp) { throw new RuntimeException("Clock moved backwards"); } if (timestamp == lastTimestamp) { sequence = (sequence + 1) & sequenceMask; if (sequence == 0) { timestamp = tilNextMillis(lastTimestamp); } } else { sequence = 0L; } lastTimestamp = timestamp; return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence; } private long timeGen() { return System.currentTimeMillis(); } private long tilNextMillis(long lastTimestamp) { long timestamp = timeGen(); while (timestamp <= lastTimestamp) { timestamp = timeGen(); } return timestamp; } }
2.3 时钟回拨处理
public synchronized long nextId() { long timestamp = timeGen(); if (timestamp < lastTimestamp) { long offset = lastTimestamp - timestamp; if (offset <= 5) { try { wait(offset << 1); timestamp = timeGen(); if (timestamp < lastTimestamp) { throw new RuntimeException("Clock moved backwards"); } } catch (InterruptedException e) { throw new RuntimeException(e); } } else { throw new RuntimeException("Clock moved backwards too much"); } } if (timestamp == lastTimestamp) { sequence = (sequence + 1) & sequenceMask; if (sequence == 0) { timestamp = tilNextMillis(lastTimestamp); } } else { sequence = 0L; } lastTimestamp = timestamp; return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence; }
public class RedisIdGenerator { private final StringRedisTemplate redisTemplate; private final String keyPrefix = "sequence:"; private final long step = 100; public long nextId(String bizType) { String key = keyPrefix + bizType; Long current = redisTemplate.opsForValue().increment(key); if (current <= step) { redisTemplate.opsForValue().set(key, String.valueOf(current + step * 10)); } return current; } }
4.2 Lua脚本保证原子性
local key = KEYS[1] local step = tonumber(ARGV[1]) local current = redis.call('INCR', key) if current <= step then redis.call('SET', key, current + step * 10) end return current