基于时钟序列解决时钟回拨

news2025/2/6 23:50:47

一、背景

分布式 ID 生成算法用于在分布式系统中生成全局唯一的 ID 标识,而 twitter 提出的雪花算法便是其中一种知名的算法,其每次会生成一个 64 位的全局唯一整数,算法的基本思想非常巧妙:

二进制64位长整型数字:1bit保留 + 41bit时间戳 + 10bit机器(或5位数据中心ID+5位机器ID) + 12bit序列号

二、问题

由于雪花算法重度依赖机器的当前时间,所以一旦发生时间回拨,将有可能导致生成的 ID 可能与此前已经生成的某个 ID 重复。针对这种问题,目前算法本身只是抛出异常。

if (timestamp < lastTimestamp) {
    throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
或者如果偏差比较小,则延迟等待,如美团的leaf
if (timestamp < lastTimestamp) {
    long offset = lastTimestamp - timestamp;
    if (offset <= 5) {
        try {
            wait(offset << 1);
            timestamp = timeGen();
            if (timestamp < lastTimestamp) {
                return new Result(-1, Status.EXCEPTION);
            }
        } catch (InterruptedException e) {
            LOGGER.error("wait interrupted");
            return new Result(-2, Status.EXCEPTION);
        }
    } else {
        return new Result(-3, Status.EXCEPTION);
    }
}

如果是在一个并发不高或者请求量不大的业务系统中,抛出异常或延迟等待或者重试的策略问题不大,但是如果是在一个高并发的系统中,这种策略显得过于粗暴。

三、基于多时钟序列

既然我已经发现了时间回拨,那我就认为原先的“时钟”已经不可用,使用一个新的“时钟”即可,并将新的当前时间认为是新时钟的时间。基于时钟序列的雪花算法:
二进制64位长整型数字:1bit保留 + 41bit时间戳 + 5位时钟序列 + 5bit机器 + 12bit序列号

分布式实例规模缩小到32, 单实例支持最多 32次回拨同一时间范围(如果时间回拨发生在互不交叠的时间段,则理论上可以完美解决时间回拨问题)。

public synchronized long nextId() {
    long timestamp = timeGen();
    if (timestamp < lastTimestamp) {
        clockSequence = (clockSequence +1) & maxclockSequence;
        //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)
            | (clockSequence << clockSequenceShift)
            | (workerId << workerIdShift) | sequence;

    return nextId;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1336575.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PostgreSQL 可观测性最佳实践

简介 软件简述 PostgreSQL 是一种开源的关系型数据库管理系统 (RDBMS)&#xff0c;它提供了许多可观测性选项&#xff0c;以确保数据库的稳定性和可靠性。 可观测性 可观测性&#xff08;Observability&#xff09;是指对数据库状态和操作进行监控和记录&#xff0c;以便在…

哪些超声波清洗机的清洁力比较好?清洁力好的超声波清洗机推荐

超声波清洗机在我们日常生活中是越来越常见&#xff0c;它以强大的清洁力获得大众的青睐&#xff01;毕竟家里购入一款超声波清洗机还是一件非常方便的事情&#xff0c;免去了跑去眼镜店洗眼镜麻烦&#xff0c;免去了清洗一些耳钉、化妆刷这些小物件难清洁烦恼&#xff01;现在…

如何进行快照管理

目录 快照管理 手动创建快照 自动创建快照 快照管理 快照管理 传统的物理服务器&#xff0c;为了确保服务器中数据的安全&#xff0c;需要你自行定制备份策略&#xff0c;如果备份到服务器本地&#xff0c;如果存储损坏&#xff0c;备份会同正常数据一起丢失。也就是说需要…

C++力扣题目232--用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 实现 MyQueue 类&#xff1a; void push(int x) 将元素 x 推到队列的末尾int pop() 从队列的开头移除并返回元素int peek() 返回队列开头…

Java经典框架之Spring MVC

Spring MVC Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机&#xff0c;Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. Spring MVC 入门案例 2. 基…

云计算1.0、云原生2.0、AI云计算3.0,是解除IT互联网人才35岁的危机之道?

互联网员工的“35岁”危机&#xff0c;算不上一个新鲜的话题。年轻人不断涌入大厂的同时&#xff0c;老员工的受挫与焦虑也在同步发生。 “员工35岁被裁”“高龄员工劝退”&#xff0c;论坛、新闻里一些案例&#xff0c;更是放大了互联网人的35岁危机感。处在上有老、下有小的…

SpringBoot整合JWT+Spring Security+Redis实现登录拦截(二)权限认证

上篇博文中我们已经实现了登录拦截&#xff0c;接下来我们继续补充代码&#xff0c;实现权限的认证 一、RBAC权限模型 什么事RBAC权限模型&#xff1f; RBAC权限模型&#xff08;Role-Based Access Control&#xff09;即&#xff1a;基于角色的权限访问控制。在RBAC中&#x…

黑豹程序员-平方根倒数速算法

程序员约翰卡马克&#xff08;John Carmack&#xff09;在《雷神之锤 III 竞技场》源代码中的平方根倒数速算法&#xff08;Fast Inverse Square Root&#xff0c;Fast InvSqrt()&#xff09;&#xff0c;看过之后大为惊奇。 该算法的意义在于减少了求平方根倒数时浮点运算操作…

第一个程序:HelloWorld——IDEA 使用

IDEA创建是&#xff1a;项目(projefct)、模块(module)、包(package)、类(class) 1.双击打开IDEA&#xff0c;勾选Do not import settings点击OK。 2.选择New Project这里选择创建一个空的项目名为helloworld2023&#xff0c;选择项目创建路径&#xff0c;最后点击创建即可。 3.…

OPNET Modeler帮助文档的打开方式

前面有篇文章修改OPNET帮助文档的默认打开浏览器 & 给Edge浏览器配置IE Tab插件已经提到了打开OPNET Modeler打开帮助文档的方法&#xff0c;有时候打开时会显示如下。 界面中没有什么内容加载出来&#xff01;我是在Google浏览器中打开的&#xff0c;其他的浏览器也是一样…

关于个人Git学习记录及相关

前言 可以看一下猴子都能懂的git入门&#xff0c;图文并茂不枯燥 猴子都能懂的git入门 学习东西还是建议尽可能的去看官方文档 权威且详细 官方文档 强烈建议看一下GitHub漫游指南及开源指北&#xff0c;可以对开源深入了解一下&#xff0c;打开新世界的大门&#xff01; …

使用YT Config Tools工具导出引脚配置清单至Excel文件

使用YT Config Tool工具导出引脚配置清单至Excel文件 文章目录 使用YT Config Tool工具导出引脚配置清单至Excel文件IntroductionOperations在YTC中导入hello_world样例工程在Pinout Configuration标签页中配置引脚保存源码工程导出Excel文件 Conclusion Introduction YT Conf…

如何进行实例管理

目录 修改实例规格 修改网络带宽 网站的访问量每天都比较高&#xff0c;网站明显变慢了&#xff0c;这是怎么回事&#xff1f; 这说明你的网站的并发访问能力已经不足了&#xff0c;并发访问是指同一时间&#xff0c;多个用户请求访问同一个域名下的资源或服务&#xff0c;请…

postgresql|数据库|LVM快照热备冷恢复数据库的思考

一&#xff0c; LVM快照备份的意义 数据库备份一直是数据库运维工作中的重点&#xff0c;一个完备的备份不仅仅是仅有后悔药的功能&#xff0c;还可能有迁移数据库的作用。 那么&#xff0c;数据库备份系统我们需要的&#xff0c;也就是看重的是四个点&#xff0c;甚至更多的…

c语言:计算阶乘的和|练习题

一、题目 输入一个数n&#xff0c;计算1&#xff01;2&#xff01;……n&#xff01;的和 如图&#xff1a; 二、思路分析 设置两个函数 1、一个函数求阶乘 2、一个函数求多个数相加的总和 3、把求阶乘的函数&#xff0c;嵌套在求相加总和的函数里面 三、代码截图【带注释】 四…

关于OpenCV中 CV_Assert() 的使用引起程序中止/崩溃问题

CV_Assert() 的作用是&#xff1a;若括号中的表达式值为 false &#xff0c;则返回一个错误信息&#xff0c;并终止程序执行。 但是 CV_Assert() 与 assert 不同&#xff0c;CV_Assert() 会通过异常抛出&#xff0c;所以如果使用 CV_Assert()&#xff0c;可以通过捕获异常而不是…

【微服务面试题(三十三道)】

文章目录 微服务面试题&#xff08;三十三道&#xff09;概述1.什么是微服务&#xff1f;2.微服务带来了哪些挑战&#xff1f;3.现在有哪些流行的微服务解决方案&#xff1f;这三种方案有什么区别吗&#xff1f; 4.说下微服务有哪些组件&#xff1f; 注册中心5.注册中心是用来干…

odoo17核心概念view5——ir_ui_view.py

这是view系列的第5篇文章&#xff0c;介绍一下view对应的后端文件ir_ui_view.py&#xff0c;它是base模块下的一个文件 位置&#xff1a;odoo\addons\base\models\ir_ui_view.py 该文件一共定义了三个模型 1.1 ir.ui.view.custom 查询数据库这个表是空的&#xff0c;从名字看…

基于ssm学生考勤管理系统的设计与实现论文

目 录 目 录 I 摘 要 III ABSTRACT IV 1 绪论 1 1.1 课题背景 1 1.2 研究现状 1 1.3 研究内容 2 2 系统开发环境 3 2.1 vue技术 3 2.2 JAVA技术 3 2.3 MYSQL数据库 3 2.4 B/S结构 4 2.5 SSM框架技术 4 3 系统分析 5 3.1 可行性分析 5 3.1.1 技术可行性 5 3.1.2 操作可行性 5 3…