一、简介
1、雪花算法的组成:
由64个Bit(比特)位组成的long类型的数字
0 | 0000000000 0000000000 0000000000 000000000 | 00000 | 00000 | 000000000000
1个bit:符号位,始终为0。
41个bit:时间戳,精确到毫秒级别,可以使用69年。
10个bit:工作机器ID,可以部署在1024个节点上。
12个bit:序列号,每个节点每毫秒内最多可以生成4096个ID。
2、雪花算法的优缺点
优点:
全局唯一:雪花算法生成的ID是全局唯一的,可以用于分布式系统中的数据分片和数据合并。
时间有序:雪花算法生成的ID中包含了时间戳信息,可以根据ID的大小推算出生成的时间。
高性能:雪花算法生成ID的速度很快,可以满足高并发的场景需求。
可扩展性:雪花算法的数据结构相对简单,易于扩展和修改。
缺点:
依赖于系统时钟:雪花算法生成ID的过程中依赖于系统时钟,如果系统时钟发生回拨,可能会导致生成的ID出现重复。
长度固定:雪花算法生成的ID长度固定为64位,可能会导致存储和传输成本较高。
不支持分布式计算:雪花算法生成ID的过程是单线程的,不能支持分布式计算。
二、项目中使用
1、引入依赖
XML
<dependency>
<groupId>com.github.beyondfengyu</groupId>
<artifactId>snowflake-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
2、配置参数
cs
snowflake:
data-center-id: 1 # 数据中心ID,可以使用机器IP地址最后一段数字,范围为0-31
machine-id: 1 # 机器ID,可以使用服务器编号,范围为0-31
3、使用
java
@Service
public class OrderSevice {
@Autowired
private SnowflakeIdWorker snowflakeIdWorker;
public Long creatOrderId() {
return snowflakeIdWorker.nextId();
}
}
三、手写雪花算法生成ID
java
/**
* 功能描述:雪花算法生成订单号
*/
public class SnowFlakeTemplate {
//起始的时间戳
private final static long START_STAMP = 1480166465631L;
//每一部分占用的位数
private final static long SEQUENCE_BIT = 12; //序列号占用的位数
private final static long MACHINE_BIT = 5; //机器标识占用的位数
private final static long DATA_CENTER_BIT = 5;//数据中心占用的位数
//每一部分的最大值
private final static long MAX_DATA_CENTER_NUM = -1L ^ (-1L << DATA_CENTER_BIT);
private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
//每一部分向左的位移
private final static long MACHINE_LEFT = SEQUENCE_BIT;
private final static long DATA_CENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
private final static long TIMESTAMP_LEFT = DATA_CENTER_LEFT + DATA_CENTER_BIT;
private long dataCenterId; //数据中心
private long machineId; //机器标识
private long sequence = 0L; //序列号
private long lastStamp = -1L;//上一次时间戳
public SnowFlakeTemplate(long dataCenterId, long machineId) {
if (dataCenterId > MAX_DATA_CENTER_NUM || dataCenterId < 0) {
throw new IllegalArgumentException("dataCenterId can't be greaterthan MAX_DATA_CENTER_NUM or less than 0");
}
if (machineId > MAX_MACHINE_NUM || machineId < 0) {
throw new IllegalArgumentException("machineId can't be greater thanMAX_MACHINE_NUM or less than 0");
}
this.dataCenterId = dataCenterId;
this.machineId = machineId;
}
private String Prefix() {
String randomPrefix = "";
for (int i = 0; i < 2; i++) {
char c = (char) (Math.random() * 26 + 'A');
randomPrefix += c;
}
return randomPrefix;
}
//产生下一个ID
public synchronized String nextId() {
long currStamp = getNewStamp();
if (currStamp < lastStamp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id");
}
if (currStamp == lastStamp) {
//相同毫秒内,序列号自增
sequence = (sequence + 1) & MAX_SEQUENCE;
//同一毫秒的序列数已经达到最大
if (sequence == 0L) {
currStamp = getNextMill();
}
} else {
//不同毫秒内,序列号置为0
sequence = 0L;
}
lastStamp = currStamp;
return Prefix() + ((currStamp - START_STAMP) << TIMESTAMP_LEFT //时间戳部分
| dataCenterId << DATA_CENTER_LEFT //数据中心部分
| machineId << MACHINE_LEFT //机器标识部分
| sequence); //序列号部分
}
private long getNextMill() {
long mill = getNewStamp();
while (mill <= lastStamp) {
mill = getNewStamp();
}
return mill;
}
private long getNewStamp() {
return System.currentTimeMillis();
}
public static void main(String[] args) {
System.out.println(new SnowFlakeTemplate(2, 3).nextId() );
}
}