标签:根据 lse term 比较 rem 最新 ring cloc 维护
每一次HTTP请求,数据库的事务的执行,我们追踪代码执行的过程中,需要一个唯一值和这些业务操作相关联,对于单机的系统,可以用数据库的自增ID或者时间戳加一个在本机递增值,即可实现唯一值。但在分布式,又该如何实现唯一性的ID
CREATE TABLE FLIGHT_ORDER (
id int(11) unsigned NOT NULL auto_increment, #自增ID
PRIMARY KEY (id),
) ENGINE=innodb;
@Autowired
private StringRedisTemplate stringRedisTemplate;
private static final String ID_KEY = "id_good_order";
public Long incrementId() {
return stringRedisTemplate.opsForValue().increment(ID_KEY);
}
//KEY_NAME 是 hash结构对应的Key,FIELD_NAME 是hash结构的字段,INCR_BY_NUMBER是增量值
redis 127.0.0.1:6379> HINCRBY KEY_NAME FIELD_NAME INCR_BY_NUMBER
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.2.0</version>
</dependency>
RetryPolicy retryPolicy = new ExponentialBackoffRetry(500, 3);
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("localhost:2181")
.connectionTimeoutMs(5000)
.sessionTimeoutMs(5000)
.retryPolicy(retryPolicy)
.build();
client.start();
String sequenceName = "root/sequence/distributedId";
DistributedAtomicLong distAtomicLong = new DistributedAtomicLong(client, sequenceName, retryPolicy);
//使用DistributedAtomicLong生成自增序列
public Long sequence() throws Exception {
AtomicValue<Long> sequence = this.distAtomicLong.increment();
if (sequence.succeeded()) {
return sequence.postValue();
} else {
return null;
}
}
String uuid = UUID.randomUUID().toString().replaceAll("-","");
1:第一个bit位(1bit):Java中long的最高位是符号位代表正负,正数是0,负数是1,一般生成ID都为正数,所以默认为0。
2:时间戳部分(41bit):毫秒级的时间,不建议存当前时间戳,而是用(当前时间戳 - 固定开始时间戳)的差值,可以使产生的ID从更小的值开始
3:工作机器id(10bit):也被叫做workId,这个可以灵活配置,机房或者机器号组合都可以。
4:序列号部分(12bit),自增值支持同一毫秒内同一个节点可以生成4096个ID
//Twitter的SnowFlake算法,使用SnowFlake算法生成一个整数
public class SnowFlakeShortUrl {
//起始的时间戳
static long START_TIMESTAMP = 1624698370256L;
//每一部分占用的位数
static long SEQUENCE_BIT = 12; //序列号占用的位数
static long MACHINE_BIT = 5; //机器标识占用的位数
static long DATA_CENTER_BIT = 5; //数据中心占用的位数
//每一部分的最大值
static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
static long MAX_DATA_CENTER_NUM = -1L ^ (-1L << DATA_CENTER_BIT);
//每一部分向左的位移
static long MACHINE_LEFT = SEQUENCE_BIT;
static long DATA_CENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
static long TIMESTAMP_LEFT = DATA_CENTER_LEFT + DATA_CENTER_BIT;
//dataCenterId + machineId 等于10bit工作机器ID
private long dataCenterId; //数据中心
private long machineId; //机器标识
private volatile long sequence = 0L; //序列号
private volatile long lastTimeStamp = -1L; //上一次时间戳
private volatile long l currTimeStamp = -1L; //当前时间戳
private long getNextMill() {
long mill = System.currentTimeMillis();
while (mill <= lastTimeStamp) mill = System.currentTimeMillis();
return mill;
}
//根据指定的数据中心ID和机器标志ID生成指定的序列号
public SnowFlakeShortUrl(long dataCenterId, long machineId) {
Assert.isTrue(dataCenterId >=0 && dataCenterId <= MAX_DATA_CENTER_NUM,"dataCenterId is illegal!");
Assert.isTrue(machineId >= 0 || machineId <= MAX_MACHINE_NUM,"machineId is illegal!");
this.dataCenterId = dataCenterId;
this.machineId = machineId;
}
//生成下一个ID
public synchronized long nextId() {
currTimeStamp = System.currentTimeMillis();
Assert.isTrue(currTimeStamp >= lastTimeStamp,"Clock moved backwards");
if (currTimeStamp == lastTimeStamp) {
//相同毫秒内,序列号自增
sequence = (sequence + 1) & MAX_SEQUENCE;
if (sequence == 0L) { //同一毫秒的序列数已经达到最大,获取下一个毫秒
currTimeStamp = getNextMill();
}
} else {
sequence = 0L; //不同毫秒内,序列号置为0
}
lastTimeStamp = currTimeStamp;
return (currTimeStamp - START_TIMESTAMP) << TIMESTAMP_LEFT //时间戳部分
| dataCenterId << DATA_CENTER_LEFT //数据中心部分
| machineId << MACHINE_LEFT //机器标识部分
| sequence; //序列号部分
}
public static void main(String[] args) {
SnowFlakeShortUrl snowFlake = new SnowFlakeShortUrl(10, 4);
for (int i = 0; i < (1 << 12); i++) {
//10进制
System.out.println(snowFlake.nextId());
}
}
}
标签:根据 lse term 比较 rem 最新 ring cloc 维护
原文地址:https://www.cnblogs.com/cscw/p/14939999.html