雪花算法生成分布式ID的时间回拨问题处理
一般方法
1.直接抛异常
2.延迟等待到最新时间(需要回拨时间比较短)
3.采用历史最大时间
package com.zjq.javabasic.algorithm;/*** @description: 雪花算法-时间回拨问题* @create: 2022-01-20 16:55**/
public class SnowflakeTest {/*** 最大容忍时间, 单位毫秒, 即如果时钟只是回拨了该变量指定的时间, 那么等待相应的时间即可;* 考虑到sequence服务的高性能, 这个值不易过大*/private static final long MAX_BACKWARD_MS = 5;/*** 开始时间戳,单位毫秒;这里是2021-06-01*/private static final long TW_EPOCH = 1622476800000L;/*** 机器 ID 所占的位数*/private static final long WORKER_ID_BITS = 5L;/*** 数据标识 ID 所占的位数*/private static final long DATA_CENTER_ID_BITS = 5L;/*** 支持的最大机器ID,最大为31* <p>* PS. Twitter的源码是 -1L ^ (-1L << workerIdBits);这里最后和-1进行异或运算,由于-1的二进制补码的特殊性,就相当于进行取反。*/private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);/*** 支持的最大机房ID,最大为31*/private static final long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_ID_BITS);/*** 序列在 ID 中占的位数*/private static final long SEQUENCE_BITS = 12L;/*** 机器 ID 向左移12位*/private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;/*** 机房 ID 向左移17位*/private static final long DATA_CENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;/*** 时间截向左移22位*/private static final long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATA_CENTER_ID_BITS;/*** 生成序列的掩码最大值,最大为4095*/private static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);/*** 工作机器 ID(0~31)*/private final long workerId;/*** 机房 ID(0~31)*/private final long dataCenterId;/*** 毫秒内序列(0~4095)*/private long sequence = 0L;/*** 上次生成 ID 的时间戳*/private long lastTimestamp = -1L;/*** 创建 ID 生成器的方式一: 使用工作机器的序号(也就是将机房的去掉给机器ID使用),范围是 [0, 1023],优点是方便给机器编号** @param workerId 工作机器 ID*/public SnowflakeTest(long workerId) {// 计算最大值long maxMachineId = (MAX_DATA_CENTER_ID + 1) * (MAX_WORKER_ID + 1) - 1;if (workerId < 0 || workerId > maxMachineId) {throw new IllegalArgumentException(String.format("Worker ID can't be greater than %d or less than 0", maxMachineId));}// 取高位部分作为机房ID部分this.dataCenterId = (workerId >> WORKER_ID_BITS) & MAX_DATA_CENTER_ID;// 取低位部分作为机器ID部分this.workerId = workerId & MAX_WORKER_ID;}/*** 创建 ID 生成器的方式二: 使用工作机器 ID 和机房 ID,优点是方便分机房管理** @param dataCenterId 机房 ID (0~31)* @param workerId 工作机器 ID (0~31)*/public SnowflakeTest(long dataCenterId, long workerId) {if (workerId > MAX_WORKER_ID || workerId < 0) {throw new IllegalArgumentException(String.format("Worker ID can't be greater than %d or less than 0", MAX_WORKER_ID));}if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) {throw new IllegalArgumentException(String.format("DataCenter ID can't be greater than %d or less than 0", MAX_DATA_CENTER_ID));}this.workerId = workerId;this.dataCenterId = dataCenterId;}/*** 获得下一个 ID(该方法是线程安全的)** @return 返回一个长度位15的 long类型的数字*/public synchronized long nextId() {long timestamp = timeGen();// 如果当前时间小于上一次 ID 生成的时间戳,说明发生时钟回拨,为保证ID不重复抛出异常。if (timestamp < lastTimestamp) {//如果小于容忍时间,直接设置历史最大时间long backTime = lastTimestamp - timestamp;if (backTime < MAX_BACKWARD_MS) {timestamp = lastTimestamp;} else {//抛异常throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));}}if (lastTimestamp == timestamp) {// 同一时间生成的,则序号+1sequence = (sequence + 1) & SEQUENCE_MASK;// 毫秒内序列溢出:超过最大值if (sequence == 0) {// 阻塞到下一个毫秒,获得新的时间戳timestamp = tilNextMillis(lastTimestamp);}} else {// 时间戳改变,毫秒内序列重置sequence = 0L;}// 上次生成 ID 的时间戳lastTimestamp = timestamp;// 移位并通过或运算拼到一起return ((timestamp - TW_EPOCH) << TIMESTAMP_LEFT_SHIFT)| (dataCenterId << DATA_CENTER_ID_SHIFT)| (workerId << WORKER_ID_SHIFT)| sequence;}private long tilNextMillis(long lastTimestamp) {long timestamp = timeGen();while (timestamp <= lastTimestamp) {timestamp = timeGen();}return timestamp;}private long timeGen() {return System.currentTimeMillis();}public static void main(String[] args) {SnowflakeTest snowflakeTest = new SnowflakeTest(0, 0);System.out.println(snowflakeTest.nextId());}
}
雪花算法生成分布式ID的时间回拨问题处理相关推荐
- 基于雪花算法生成用户id
8.1 为啥这样做 1.全局唯一性,不会出现重复的id.如果通过id自增来保证id不重复,则该表 无法分表操作例如 服务器A的数据库的user表 数据如下1 小明 男2 小红 女2 张三 男此时 进行 ...
- DefaultIdentifierGenerator 雪花算法 生成 重复 id 解决办法
DefaultIdentifierGenerator 雪花算法 生成 重复 id 前言 问题发生 排查原因 问题解决 前言 利用 mybatisplus 的 DefaultIdentifierGene ...
- 雪花算法snowflake分布式id生成原理详解,以及对解决时钟回拨问题几种方案讨论
文章目录 一.前言 二.雪花算法snowflake 1.基本定义 2.snowflake的优缺点 三.Java代码实现snowflake 1.组装生成id 2.计算最大值的几种方式 3.反解析ID 4 ...
- 分布式下使用雪花算法生成全局ID及解决时钟回拨问题
简介 雪花算法是 64 位 的二进制,一共包含了四部分: 1位是符号位,也就是最高位,始终是0,没有任何意义,因为要是唯一计算机二进制补码中就是负数,0才是正数 41位是时间戳,具体到毫秒,41位的二 ...
- 雪花算法【分布式ID问题】【刘新宇】
分布式ID 1 方案选择 UUID UUID是通用唯一识别码(Universally Unique Identifier)的缩写,开放软件基金会(OSF)规范定义了包括网卡MAC地址.时间戳.名字空间 ...
- 推特雪花算法,分布式id生成器
推特雪花算法 分布式id生成器 package util;import java.lang.management.ManagementFactory; import java.net.InetAddr ...
- python版雪花算法生成唯一ID
一.雪花算法图解 理论一大堆,总结如下图: 下方为源码,返回的结果为19位,为10进制表示,使用二进制表示就是64位,所以不必有所疑惑. 二.源码 1.异常捕获块 文件名:exceptions.py ...
- 雪花算法:分布式唯一 ID 生成利器
无论是在分布式系统中的 ID 生成,还是在业务系统中请求流水号这一类唯一编号的生成,都是软件开发人员经常会面临的一场景.而雪花算法便是这些场景的一个解决方案. 以分布式 ID 为例,它的生成往往会在唯 ...
- 雪花算法:分布式唯一ID生成利器
前言 无论是在分布式系统中的ID生成,还是在业务系统中请求流水号这一类唯一编号的生成,都是软件开发人员经常会面临的一场景.而雪花算法便是这些场景的一个解决方案. 以分布式ID为例,它的生成往往会在唯一 ...
最新文章
- 2020 北京智源大会“云上”开幕, 中外顶尖学者畅想AI的下一个十年
- python导入csv文件-Python读写文件(csv、txt、excel)
- Java工具类--雪花算法生成全局唯一ID
- “约见”面试官系列之常见面试题第七篇说说Vue的生命周期(建议收藏)
- netpref 使用_使用PerfView监测.NET程序性能(转发)
- idea没有代码自动提示功能和包自动引入不了问题
- 12.2 新特性:锁信息获取之在线删除索引
- 双显卡只用独显好吗_双动力洗衣机好吗
- android读写相册权限,androidQ 关于存储权限相册图片
- 计算机应用基础任务化教程试题及答案,计算机应用基础任务化教程windows7office2010试卷(带操作题)及答案.doc...
- 网页输入数据到mysql_为什么用PHP编写的网页中,输入的数据不能插入到Mysql数据库中?...
- 【Java】Java_03第一个Java程序
- Numpy的各种下标操作
- STM8入门以及程序编译、烧录、IAR使用方法(扫盲篇)
- 【ubuntu查看显卡、配置显卡、cuda、cudnn】
- 艺赛旗(RPA)相对路径、绝对路径、执行空间、代码空间,傻傻分不清?
- 怎么样才能学好java_论新手该如何学习java?
- 不到七千入手的高性能笔记本,游匣G15实测
- A/B compartment:染色质区室简介
- 给自己定个小目标:每天写点东西
热门文章
- 运用免费OA让你有意想不到的效果
- CSDN高校巡讲石大站—青岛易软天创CEO王春生与我们分享“学习 工作 创业”
- java根据模板生成pdf文件并导出(iText)
- 单元测试 php,PHP单元测试PHPUnit简单用法示例
- 基于Java毕业设计在线药物配送系统源码+系统+mysql+lw文档+部署软件
- 小扰动线性化思想在机器学习中的跨界应用
- 《C++入门经典(第5版•修订版)》——2.7 作业
- Request URI does not contain a valid hostname: service-eureka-order/order/1 解决方法
- 最恐怖的 Cosplay。
- 融城杯 | 神州信息:金融科技助力乡村振兴