当前位置:网站首页>雪花id,分布式唯一id
雪花id,分布式唯一id
2022-06-29 19:44:00 【ywl470812087】
/**
* <p>名称:IdWorker.java</p>
* <p>描述:分布式自增长ID</p>
* <pre>
* Twitter的 Snowflake JAVA实现方案
* </pre>
* 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:
* 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
* 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,
* 然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),
* 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
* 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),
* 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
* <p>
* 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))
*
*/
package com.rabee.common.utils.uuid;
import org.springframework.stereotype.Component;
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
@Component
public class SnowflakeIdUtil {
/**
* 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
*/
private final static long twepoch = 1420041600000L;
/**
* 机器标识位数
*/
private final static long workerIdBits = 5L;
/**
* 数据中心标识位数
*/
private final static long datacenterIdBits = 5L;
/**
* 机器ID最大值
*/
private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
/**
* 数据中心ID最大值
*/
private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
/**
* 毫秒内自增位
*/
private final static long sequenceBits = 12L;
/**
* 机器ID偏左移12位
*/
private final static long workerIdShift = sequenceBits;
/**
* 数据中心ID左移17位
*/
private final static long datacenterIdShift = sequenceBits + workerIdBits;
/**
* 时间毫秒左移22位
*/
private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
/**
* 上次生产id时间戳
*/
private static long lastTimestamp = -1L;
/**
* 并发控制
*/
private long sequence = 0L;
private final long workerId;
/**
* 数据标识id部分
*/
private final long datacenterId;
public SnowflakeIdUtil(){
this.datacenterId = getDatacenterId(maxDatacenterId);
this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
}
/**
* @param workerId
* 工作机器ID
* @param datacenterId
* 序列号
*/
public SnowflakeIdUtil(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
/**
* 获取下一个ID
*
* @return
*/
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
if (lastTimestamp == timestamp) {
// 当前毫秒内,则+1
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
// 当前毫秒内计数满了,则等待下一秒
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
// ID偏移组合生成最终的ID,并返回ID
long nextId = ((timestamp - twepoch) << timestampLeftShift)
| (datacenterId << datacenterIdShift)
| (workerId << workerIdShift) | sequence;
return nextId;
}
private long tilNextMillis(final long lastTimestamp) {
long timestamp = this.timeGen();
while (timestamp <= lastTimestamp) {
timestamp = this.timeGen();
}
return timestamp;
}
private long timeGen() {
return System.currentTimeMillis();
}
/**
* <p>
* 获取 maxWorkerId
* </p>
*/
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
StringBuffer mpid = new StringBuffer();
mpid.append(datacenterId);
String name = ManagementFactory.getRuntimeMXBean().getName();
if (!name.isEmpty()) {
/*
* GET jvmPid
*/
mpid.append(name.split("@")[0]);
}
/*
* MAC + PID 的 hashcode 获取16个低位
*/
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
}
/**
* <p>
* 数据标识id部分
* </p>
*/
protected static long getDatacenterId(long maxDatacenterId) {
long id = 0L;
try {
InetAddress ip = InetAddress.getLocalHost();
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
if (network == null) {
id = 1L;
} else {
byte[] mac = network.getHardwareAddress();
id = ((0x000000FF & (long) mac[mac.length - 1])
| (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
id = id % (maxDatacenterId + 1);
}
} catch (Exception e) {
System.out.println(" getDatacenterId: " + e.getMessage());
}
return id;
}
public static void main(String[] args) {
SnowflakeIdUtil sf = new SnowflakeIdUtil();
String id =String.valueOf(sf.nextId());
System.out.println(""+id+":"+id.length());
}
}
边栏推荐
- 3 - 3 découverte de l'hôte - découverte à quatre niveaux
- Sword finger offer 59 - I. maximum value of sliding window
- DAO 中存在的不足和优化方案
- Zotero期刊自動匹配更新影響因子
- 7. cancellation and closing
- Shell bash script note: there must be no other irrelevant characters after the escape character \ at the end of a single line (multi line command)
- 【精品】pinia详解
- 电脑ssd硬盘怎么安装使用
- Inception 新结构 | 究竟卷积与Transformer如何结合才是最优的?
- [network orientation training] - Enterprise Park Network Design - [had done]
猜你喜欢

@Sneakythlows annotation

【软件测试】01 -- 软件生命周期、软件开发模型

4-1 port scanning technology

Understanding of software test logic coverage

The concept and properties of mba-day26 number

洞见科技作为「唯一」隐私计算数商,「首批」入驻长三角数据要素流通服务平台

QC protocol + Huawei fcp+ Samsung AFC fast charging 5v9v chip fs2601 application

JVM (4) bytecode technology + runtime optimization

npm ERR! fatal: early EOF npm ERR! fatal: index-pack failed

k线图经典图解(收藏版)
随机推荐
JVM (4) bytecode technology + runtime optimization
JVM(3) 类加载
What if the win11 policy service is disabled? Solution to disabling win11 policy service
JVM (2) garbage collection
JVM(4) 字節碼技術+運行期優化
Freeswitch dial extension
数据基础设施升级窗口下,AI 新引擎的技术方法论
shell bash脚本注意:单行末尾转义符 \ 后千万不能有其他无关字符(多行命令)
创作者基金会 6 月份亮点
3-3 host discovery - layer 4 discovery
1404万!四川省人社厅关系型数据库及中间件软件系统升级采购招标!
【精品】pinia详解
JVM (3) class loading
[observation] softcom power liutianwen: embrace change and "follow the trend" to become an "enabler" of China's digital economy
Sword finger offer 41 Median in data stream
Docker compose deploy the flask project and build the redis service
@SneakyThrows注解
jfinal中如何使用过滤器监控Druid监听SQL执行?
剑指 Offer 41. 数据流中的中位数
雲服務器的安全設置常識