顾名思义,结合了美团的LeafSegment和Mist薄雾算法,目的是弥补LeafSegment算法的ID连续性、可预测性,同时弥补Mist算法再分布式架构和机器重启时,ID有概率重复的缺点。
UniqueId
/**
* 全局id生成器
*/
public interface UniqueId {
/**
* 下个全局id
*
* @return
*/
long next();
/**
* id含义
*
* @param id
* @return
*/
String mean(long id);
}
LeafSegment
/**
* 美团Leaf
* 原方案每次获取ID都得读写一次数据库,造成数据库压力大。改为利用proxy server批量获取,每次获取一个segment(step决定大小)号段的值。用完之后再去数据库获取新的号段,可以大大的减轻数据库的压力。
*/
public class LeafSegment implements UniqueId {
/**
* 业务名(唯一)
*/
private String bizTag;
private Segment[] segments = new Segment[]{new Segment(), new Segment()};
private volatile int currentPos;
private volatile boolean nextReady;
private volatile boolean initOk;
private final AtomicBoolean threadRunning = new AtomicBoolean(false);
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private volatile int step;
public LeafSegment(String bizTag, int step) {
this.bizTag = bizTag;
this.step = step;
}
public class Segment {
private volatile AtomicLong value = new AtomicLong();
private long maxValue;
public long getIdle() {
return maxValue - value.get();
}
}
@Override
public long next() {
if (!initOk) {
synchronized (this) {
if (!initOk) {
update(segments[currentPos]);
initOk = true;
}
}
}
long value = current();
if (value < 0) {
switchSegment();
return next();
} else {
return value;
}
}
private long current() {
lock.readLock().lock();
try {
Segment segment = segments[currentPos];
if (!nextReady && segment.getIdle() < 0.9 * step && threadRunning.compareAndSet(false, true)) {
prepareNext();
}
long value = segment.value.getAndIncrement();
if (value < segment.maxValue) {
return value;
}
return -1;
} finally {
lock.readLock().unlock();
}
}
/**
* 准备下个区的数据
*/
private void prepareNext() {
Invokable runnable = () -> {
Segment next = segments[nextPos()];
if (update(next)) {
lock.writeLock().lock();
nextReady = true;
threadRunning.set(false);
lock.writeLock().unlock();
} else {
threadRunning.set(false);
}
};
RetryableRequest.notRetryableRequest("LeafSegment", runnable);
}
/**
* 切换区
*/
private void switchSegment() {
lock.writeLock().lock();
try {
if (nextReady) {
switchPos();
nextReady = false;
} else {
throw new RuntimeException("Both segments are not ready");
}
} finally {
lock.writeLock().unlock();
}
}
private int nextPos() {
return (currentPos + 1) % segments.length;
}
private void switchPos() {
currentPos = nextPos();
}
long nextMaxValue = 100000;
/**
* 需要引入redis或DB,根据步长获取最大值
*
* @return
*/
protected synchronized long nextMaxvalue() {
nextMaxValue = nextMaxValue + step;
return nextMaxValue;
}
/**
* 更新区数据
*
* @param segment
* @return
*/
protected boolean update(Segment segment) {
segment.maxValue = nextMaxvalue();
segment.value.set(segment.maxValue - step);
return true;
}
@Override
public String mean(long id) {
return String.format("segmentIncreaseId:", id);
}
Mist
/**
* 薄雾
* 薄雾算法不受时间戳影响,受到数值大小影响。薄雾算法高位数值上限计算方式为int64(1<<47 - 1),上限数值140737488355327 百万亿级,假设每天消耗 10 亿,薄雾算法能使用 385+ 年。
* <p>
* 1位 位始终为0, 不可用 java中为符号位
* 47位 自增数 自增数在高位能保证结果值呈递增态势,遂低位可以为所欲为;
* 8位 随机因子1 上限数值 255,使结果值不可预测;
* 8位 随机因子2 上限数值 255,使结果值不可预测;
*/
public class Mist implements UniqueId {
private final AtomicLong sequence = new AtomicLong();
private final long saltBit = 8L;
private final long saltShift = saltBit;
private final int saltMax = ~(-1 << saltBit);
private final long increaseShit = saltBit + saltShift;
@Override
public long next() {
return mist(sequence.getAndIncrement());
}
public long mist(long sequence) {
long salt1 = JediFuncs.random(0, saltMax);
long salt2 = JediFuncs.random(0, saltMax);
return (sequence << increaseShit) | (salt1 << saltShift) | salt2;
}
@Override
public String mean(long id) {
long salt2 = id & saltMax;
long salt1 = (id >> saltShift) & saltMax;
long sequence = (id >> increaseShit);
return String.format("sequence:%d salt1:%d salt1:%d", sequence, salt1, salt2);
}
}
LeafSegmentMist
/**
* 分段薄雾
* 结合LeafSegment分段递增算法和薄雾算法,使ID呈递增状态且不可预测
*/
public class LeafSegmentMist implements UniqueId {
private LeafSegment leafSegment;
private Mist mist;
/**
* 分段薄雾
*
* @param bizTag 业务ID
* @param step 步长
*/
public LeafSegmentMist(String bizTag, int step) {
leafSegment = new LeafSegment(bizTag, step);
mist = new Mist();
}
@Override
public long next() {
return mist.mist(leafSegment.next());
}
@Override
public String mean(long id) {
return mist.mean(id);
}
}
Test
@Test
public void leafSegmentMist() {
LeafSegmentMist mist = new LeafSegmentMist("test", 1000);
int times = 1;
while (times++ <= 10000) {
long v = mist.next();
JLogger.debug("LeafSegmentMist:"+v);
JLogger.debug(mist.mean(v));
}
}
2023-06-30 13:46:08,971 [main] DEBUG debugLogger - LeafSegmentMist:6797296358
2023-06-30 13:46:08,971 [main] DEBUG debugLogger - sequence:103718 salt1:130 salt1:230
2023-06-30 13:46:08,971 [main] DEBUG debugLogger - LeafSegmentMist:6797364332
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - sequence:103719 salt1:140 salt1:108
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - LeafSegmentMist:6797453582
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - sequence:103720 salt1:233 salt1:14
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - LeafSegmentMist:6797510576
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - sequence:103721 salt1:199 salt1:176
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - LeafSegmentMist:6797573170
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - sequence:103722 salt1:188 salt1:50
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - LeafSegmentMist:6797598314
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - sequence:103723 salt1:30 salt1:106
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - LeafSegmentMist:6797686431
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - sequence:103724 salt1:118 salt1:159
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - LeafSegmentMist:6797722486
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - sequence:103725 salt1:3 salt1:118
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - LeafSegmentMist:6797826327
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - sequence:103726 salt1:153 salt1:23
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - LeafSegmentMist:6797896782
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - sequence:103727 salt1:172 salt1:78
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - LeafSegmentMist:6797924957
2023-06-30 13:46:08,972 [main] DEBUG debugLogger - sequence:103728 salt1:26 salt1:93