分布式雪花算法生成唯一ID
雪花算法组成
10bit工作进程位:用来记录工作机器的id,包括5位datacenterId和5位workerId;5位(bit)可以表示的最大正整数是31,即可以用0,1,2,3,…31这32个数字,来表示不同的datacenterId和workerId
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.16</version>
</dependency>
Snowflake需自行保证单例,否则多个对象生成ID会导致重复
代码
package com.lyods.base.utils;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.IdUtil;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @creator linhy
* @date 2021-11-16
* @descrption 获取雪花算法ID
*
*/
public class SnowFlakeUtil {
private final static Logger log = LoggerFactory.getLogger(SnowFlakeUtil.class);
private static long workerId = 0;
private volatile static Snowflake snowflake = null;
private volatile static SnowFlakeUtil sfu = null;
/**
* 单例
*/
private SnowFlakeUtil() {
}
public static SnowFlakeUtil getInstance() {
if (null == sfu) {
synchronized (SnowFlakeUtil.class) {
if (null == sfu) {
sfu = new SnowFlakeUtil();
}
}
}
return sfu;
}
/**
* 获取ID
* @return
*/
public long snowflakeId() {
if (null == snowflake) {
snowflake = getSnowflake();
}
return snowflake.nextId();
}
/**
* 获取ID(自定义工作机器ID)
* @param workerId 终端ID
* @param dataCenterId 数据中心ID
* @return
*/
public long snowflakeId(long workerId, long dataCenterId) {
if (null == snowflake) {
snowflake = getSnowflake(workerId, dataCenterId);
}
return snowflake.nextId();
}
/**
* Snowflake带参对象获取
* @return
*/
private synchronized Snowflake getSnowflake(long workerId, long dataCenterId) {
snowflake = IdUtil.getSnowflake(workerId, dataCenterId);
return snowflake;
}
/**
* Snowflake无参对象获取
* @return
*/
private synchronized Snowflake getSnowflake() {
snowflake = new Snowflake();
return snowflake;
}
@PostConstruct
public void init() {
try {
workerId = NetUtil.ipv4ToLong(NetUtil.getLocalhostStr());
log.info("当前机器的workId: {}", workerId);
} catch (Exception e) {
e.printStackTrace();
log.error("当前机器的workId获取失败", e);
workerId = NetUtil.getLocalhostStr().hashCode();
}
}
}
线程池30线程测试
ExecutorService executorService = Executors.newFixedThreadPool(5);
Stream.iterate(0, x -> x + 1).limit(30).forEach(x -> {
executorService.submit(() -> {
long id = SnowFlakeUtil.getInstance().snowflakeId();
System.out.println(id);
});
});
结果
- 优点
时间戳位在高位,ID趋势递增(几千页的分页下可以根据最后一条数据ID进行分页提高效率),生成ID性能高,不依赖第三方系统,分布式系统内不会产生ID碰撞(由datacenter和workerId作区分) - 缺点
回拨本机时间可能导致时间戳相同,ID重复,分布式下不同机器可能时间不完全同步
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
二维码