分布式服务自增长唯一ID小结
2024-09-07 07:34:59
1、常用生成唯一ID的方式,例如UUID
2、生成唯一自自增长ID方式:
例如:
- Zookeeper的增加ID;
- redis的incr方法
- mongodb的objectId
3、采用雪花模型
如下代码:
/**
* 采用twitter的雪花算法,生成有一定顺序且不重复的id,结果类型为64位的long型
*/
public class SnowflakeIdUtils {
//集群id
private long datacenterId;
//机器id
private long workerId;
//序列号
private long sequenceId; //集群id的bit位数
private long datacenterIdBits = 5L;
//机器id的bit位数
private long workerIdBits = 5L;
//序列号的bit位数
private long sequenceIdBits = 12L; //集群id的最大编号
private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
//机器id的最大编号
private long maxWorkerId = -1L ^ (-1L << workerIdBits);
//序列号的掩码
private long sequenceIdMask = -1L ^ (-1L << sequenceIdBits); //生成最终结果时,集群id需移动的bit位数
private long timestampShiftBits = sequenceIdBits + workerIdBits + datacenterIdBits;
//生成最终结果时,集群id需移动的bit位数
private long datacenterIdShiftBits = sequenceIdBits + workerIdBits;
//生成最终结果时,机器id需移动的bit位数
private long workerIdShiftBits = sequenceIdBits; //去掉过去的时间,即从指定时间(本例以2017-10-12 00:00:00)开始算,
// 大约可用69.5年(41位的时间位,最大值换成毫秒,再换算成年,大约69.5年)
//1507737600000为从1970-01-01 00:00:00到2017-10-12 00:00:00经过的毫秒数
private long pastMills = 1507737600000L;
//上一次生成id使用的timestamp ,以毫秒为单位
private long lastTimestamp = 1L; /**
* 若没有指定集群id和机器id,则默认均为0
*/
public SnowflakeIdUtils() {
this(0, 0);
} /**
* 指定集群id和机器id
*
* @param datacenterId
* @param workerId
*/
public SnowflakeIdUtils(long datacenterId, long workerId) {
if (datacenterId < 0 || datacenterId > maxDatacenterId) {
throw new RuntimeException(String.format("datacenterId greater than %d or less than 0", maxDatacenterId));
}
if (workerId < 0 || workerId > maxWorkerId) {
throw new RuntimeException(String.format("workerId greater than %d or less than 0", maxWorkerId));
}
this.datacenterId = datacenterId;
this.workerId = workerId;
} /**
* 生成全局唯一的id
*
* @return
*/
public synchronized long nextId() {
long timestamp = System.currentTimeMillis();
if (timestamp < lastTimestamp) { //出现这种情况,通常是由于机器时间出问题了
throw new RuntimeException("machine time error");
} //同一时刻生成的id号
if (timestamp == lastTimestamp) {
sequenceId = (sequenceId + 1) & sequenceIdMask;
if (sequenceId == 0) { //说明当前毫秒的序列号用完了,需从下个毫秒数开始重新计数
timestamp = nextTimestamp(lastTimestamp);
}
} else {
//否则序列号从0开始
sequenceId = 0L;
} lastTimestamp = timestamp;
long id = ((timestamp - pastMills) << timestampShiftBits)
| (datacenterId << datacenterIdShiftBits)
| (workerId << workerIdShiftBits)
| sequenceId;
return id;
} /**
* 获取上次取数毫秒的下一时刻
*
* @param lastTimestamp
* @return
*/
long nextTimestamp(long lastTimestamp) {
long timestamp = System.currentTimeMillis();
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
return timestamp;
} public static void main(String[] args) throws Exception {
SnowflakeIdUtils snowflakeIdGen = new SnowflakeIdUtils();
//测试,生成10个唯一id
for (int i = 0; i < 10; i++) {
long id = snowflakeIdGen.nextId();
System.out.println(id);
}
}
}
这里采用的是默认构造生成 SnowflakeIdUtils,如果分布式服务同时调用的话,会出现重复ID,
所以需要加上 集群id(0~31),workerId(0~31)
了解更多雪花模型知识,后续补充。
最新文章
- Ubuntu学习总结-10 XManager
- 解决 odoo.py: error: option --addons-path: The addons-path &#39;local-addons/&#39; does not seem to a be a valid Addons Directory!
- 关于语句#ifdef OS_GLOBALS #define OS_EXT #else #define OS_EXT extern #endif 的说明
- ks全自动安装centos
- apache开源项目--Sirona
- SRBF Lighting
- Oracle成长点点滴滴(3)— 权限管理
- Unity开发之实现更换鼠标图片
- HTML5地理定位API在chrome中不能正常使用
- Java NIO5:通道和文件通道
- Java线程和线程池
- matlab 基于 libsvm工具箱的svm分类遇到的问题与解决
- INET_ADDRSTRLEN 和 INET6_ADDRSTRLEN 长度
- tomcat+ngnix单机搭建集群及端口占用问题
- 「6月雅礼集训 2017 Day11」delight
- C#中线程的委托
- (转载)--SG函数和SG定理【详解】
- Linux文件系统管理 fdisk分区命令
- XtraFinder
- DRF接入Oauth2.0认证[微博登录]报错21322重定向地址不匹配
热门文章
- [poj] 1204 Word Puzzles || AC自动机
- [bzoj] 1036 Count
- NOIP2017赛前模拟11月6日—7日总结
- Registering RHEL6 Clients into spacewalk
- linux缺页异常处理--内核空间【转】
- linux内核分析之进程地址空间【转】
- [Oracle] Transporting Tablespace
- python--asyncio模块
- Servlet 2.4 规范之第七篇:过滤器
- Selenium2+python自动化15-select下拉框【转载】