『SnowFlake』雪花算法的详解及时间回拨解决方案

news2025/1/10 12:03:28


📣读完这篇文章里你能收获到

  • 图文形式为你讲解原生雪花算法的特征及原理
  • 了解时间回拨的概念以及可能引起发此现象的操作
  • 掌握时间回拨的解决方案—基于时钟序列的雪花算法
  • 关于雪花算法的常见问题解答

请添加图片描述

文章目录

  • 一、原生的雪花算法
    • 1. 简介
    • 2. 特征
    • 3. 原理
      • 3.1 格式(64bit)
      • 3.2 字节分配
  • 二、雪花算法的时间回拨问题
    • 1. 问题描述
    • 2. 现象引发
    • 3. 常见的处理方式
      • 3.1 直接抛出异常
      • 3.2 延迟等待
  • 三、基于时钟序列解决时间回拨的方案
    • 1. 简介
    • 2. 设计思路
    • 3. 算法支持
    • 4. 关键实现代码
  • 四、关于雪花算法的常见问题解答
    • 1. 雪花算法支持的并发数最大多少?
    • 2. 雪花算法支持最多支持系统运行多少年?
    • 3. 用了雪花Id,出现负闰秒为什么会导致系统大量抛异常?

一、原生的雪花算法

1. 简介

  • 分布式 ID 生成算法用于在分布式系统中生成全局唯一的 ID 标识
  • Twitter 提出的雪花算法便是其中一种知名的算法,也是一种发号器方案
  • 百度(uid-generator)、美团(Leaf)及滴滴(Tinyid)等开源分布式ID都是基于雪花算法实现的,如果有人问你有关唯一 ID 生成的问题,你应该立即想到雪花!
  • 雪花是二进制的 64位(只有 63 位用于填充有符号整数),最终数字一般以十进制序列化

2. 特征

  • 全局唯一性:雪花算法可以保证集群系统的ID全局唯一
  • 趋势递增:由于强依赖时间戳,所以整体趋势会随着时间递增
  • 单调递增(×):不满足单调递增,在不考虑时间回拨的情况下,虽然在单机中可以保持单调递增,但在分布式集群中无法做到单调递增,只能保证总体趋势递增
  • 信息安全指的是ID生成不规则,无法猜测下一个

雪花算法特征.png

3. 原理

3.1 格式(64bit)

二进制64位长整型数字:1bit保留 + 41bit时间戳 + 10bit机器 + 12bit序列号

在这里插入图片描述

3.2 字节分配

  • 1bit不用:因为二进制中最高位是符号位,1表示负数,0表示正数,生成的id一般都是用整数,所以最高位固定为0
  • 41bit时间戳:这里采用的就是当前系统的具体时间,单位为毫秒
  • 10bit工作机器ID(workerId):每台机器分配一个id,这样可以标示不同的机器,但是上限为1024,标示一个集群某个业务最多部署的机器个数上限
  • 12bit序列号(自增域):表示在某一毫秒下,这个自增域最大可以分配的bit个数,在当前这种配置下,每一毫秒可以分配2^12 = 4096个数据

二、雪花算法的时间回拨问题

1. 问题描述

简单说就是时间被调整回到了之前的时间,由于雪花算法重度依赖机器的当前时间,所以一旦发生时间回拨,将有可能导致生成的 ID 可能与此前已经生成的某个 ID 重复(前提是刚好在同一毫秒生成 ID 时序列号也刚好一致),这就是雪花算法最经常讨论的问题——时间回拨

2. 现象引发

  • 网络时间校准
  • 人工设置
  • 出现负闰秒(关于闰秒的介绍会在后面讲到)

3. 常见的处理方式

3.1 直接抛出异常

在雪花算法原本的实现中,针对这种问题,算法本身只是返回错误,由应用另行决定处理逻辑,如果是在一个并发不高或者请求量不大的业务系统中,错误等待或者重试的策略问题不大,但是如果是在一个高并发的系统中,这种策略显得过于粗暴

3.2 延迟等待

将当前线程阻塞3ms,之后再获取时间,看时间是否比上一次请求的时间大,如果大了,说明恢复正常了,则不用管如果还小,说明真出问题了,则抛出异常,缺点仍然如3.1所描述

当使用雪花算法出现时间回拨时,不想抛异常,又希望能继续保持全局唯一性、趋势递增、信息安全,可以了解第四点,基于时间序列的方案

三、基于时钟序列解决时间回拨的方案

1. 简介

我这里介绍的是一种基于修改扩展位的思路,基于时钟序列的雪花算法
二进制64位长整型数字:1bit保留 + 41bit时间戳 + 3位时钟序列 + 7bit机器 + 12bit序列号

在这里插入图片描述

2. 设计思路

  • 如上图,将原本10位的机器码拆分成3位时钟序列及7位机器码
  • 发生时间回拨的时候,时间已经发生了变化,那么这时将时钟序列新增1位,重新定义整个雪花Id
  • 为了避免实例重启引起时间序列丢失,因此时钟序列最好通过DB/缓存等方式存储起来

3. 算法支持

  • 还是支持最长 69 年多的运行时间
  • 分布式实例规模由210(1024)降至27(128)
  • 单实例每毫秒仍然支持 4096次请求
  • 每个分布式实例支持最多 2^3(8) 次时间回拨

4. 关键实现代码

.Net Demo 其他语言参考流程自行改造

/// <summary>
/// 获取下一个ID
/// </summary>
/// <returns></returns>
public long NextId()
{
    lock (_lock)
    {
        //当前系统时间戳
        var currentTimestamp = TimeGen();
        //出现时间回拨 当前系统时间小于最后更新时间
        if (currentTimestamp < _lastTimestamp)
        {
            // _clockSequence自增,和CLOCK_SEQUENCE_MASK相与一下,去掉高位
            _clockSequence = (_clockSequence + 1) & CLOCK_SEQUENCE_MASK;
        }

        // 如果上次生成时间和当前时间相同,在同一毫秒内
        if (_lastTimestamp == currentTimestamp)
        {
            // sequence自增,和SEQUENCE_MASK相与一下,去掉高位
            _sequence = (_sequence + 1) & SEQUENCE_MASK;
            //判断是否溢出,也就是每毫秒内超过1024,当为1024时,与sequenceMask相与,sequence就等于0
            if (_sequence == 0)
            {
                //等待到下一毫秒
                currentTimestamp = TilNextMillis(_lastTimestamp);
            }
        }
        else
        {
            //如果和上次生成时间不同,重置sequence,就是下一毫秒开始,sequence计数重新从0开始累加,
            _sequence = 0;
        }

        _lastTimestamp = currentTimestamp;
        return ((currentTimestamp - TWEPOCH) << TIMESTAMP_LEFT_SHIFT) | _clockSequence << CLOCK_SEQUENCE_SHIFT | (WorkerId << WORKER_ID_SHIFT) | _sequence;
    }
}

四、关于雪花算法的常见问题解答

1. 雪花算法支持的并发数最大多少?

  • 这个是由序列号的位数决定的,原生雪花算法序列号12位,也就是1毫秒最大可生成2^12(4096),相当于1秒可生成 4096 * 1000 个ID,也就是QPS可以到 409.6 w/s

2. 雪花算法支持最多支持系统运行多少年?

  • 这个是由时间戳位数决定的,原生雪花算法时间戳占41位,也就是支持最大的时间戳为2^41(2199023255552),而1年的总毫秒数为3600 * 1000 * 24 * 365 = 31,536,000,000,因此2^41 / 1年的总毫秒数≈69.7年

    image.png

  • 其实衍生出另一个问题,41位能表示的最大的时间戳为2^41(2199023255552)对应的时间应该是2039-09-07 23:47:35,距离现在只有不到20年的时间,为什么算出来的是69年呢?

  • 其实时间戳的算法是1970年1月1日到指点时间所经过的毫秒或秒数,那咱们把开始时间从2021年开始,就可以延长41位时间戳能表达的最大时间,所以这里实际指的是相对自定义开始时间的时间戳

3. 用了雪花Id,出现负闰秒为什么会导致系统大量抛异常?

  • 闰秒是偶尔运用于协调世界时(UTC)的调整,经由增加或减少一秒,以消弥精确的时间(使用原子钟测量)和不精确的观测太阳时(称为UT1),之间的差异
  • 这种做法已被证明具有破坏性,特别是在二十一世纪,尤其是在依赖精确时间戳或时间关键程序控制的服务中
  • 而雪花算法严重依赖时间戳,当出现负闰秒也就是时间减少一秒时(时间往前回拨1秒),雪花Id就可能出现重复,而原生的雪花算法出现时间回拨的处理方式是直接抛异常
  • 2022年11月,在第27届国际计量大会上,科学家和政府代表投票决定到2035年取消闰秒

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

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

相关文章

什么软件可以去除照片水印?这3种方法可以帮你轻松搞定

大家有过这样的烦恼吗&#xff1f;在网上看到一张喜欢的图片&#xff0c;想要将它保存下来做壁纸&#xff0c;但是却发现图片里面有个大大的水印&#xff0c;十分影响效果。或者是在网上看到一张喜欢的头像&#xff0c;里面也有着一个大大的水印&#xff0c;我们该放弃这张图片…

【能源物联网】物联网体系结构与建筑能源管理系统的相关性分析

摘要&#xff1a; 在能源形势紧张的大趋势下&#xff0c;高能耗的大型公共建筑能源管理系统的建设逐渐受到重视&#xff0c;以物联网技术及基础的建筑能源管理平台可以提供即时、准确、高效的能源管理策略。系统阐述了结合物联网技术的建筑能源管理构建方法&#xff0c;对物联…

低代码助力制造型企业——工时管理系统

生产管理是制造企业的核心职能之一,工时管理是生产管理的重要方法和手段&#xff0c;可以帮助更好的掌控交货期&#xff0c;控制成本&#xff0c;更准确的安排生产计划。在当前激烈竞争的市场环境下&#xff0c;企业必须以现代化的理念结合不断改进的管理方法才能及时抓住发展机…

Aspose.GIS 22.10.0 for .NET Crack

概述 获取最完整和最强大的 API&#xff0c;以创建受其启发并基于它们的新项目&#xff0c;而不是通过为您编写此处已有的内容来浪费资源和精力。适用于 .NET 的 GIS API 是一种使用 GIS 数据的简单方法完全托管的代码&#xff0c;具有简单的界面、部署和数据安全性。 我们的 .…

Python FastAPI 多参数传递

Python FastAPI请求参数传递 FastAPI多参数传递类型 FastAPI通过模板来匹配URL中的参数列表&#xff0c;大致有如下三类方式传递参数&#xff1a; 路径参数传递&#xff1a;获取自定义的构造URL中的参数GET参数传递&#xff1a;获取一个URL后面带的?param11&param22这种…

ubuntu20.04+anaconda+yolov5训练kitti数据集

yolov5安装流程 一、Anaconda安装 1.Anaconda官网:https://www.anaconda.com/products/distribution 2.点击Download&#xff0c;下载For Linux版本 3.到下载的文件夹&#xff0c;输入&#xff1a; bash ~/Downloads/Anaconda3-xxxxxxxxx.sh # 根据下载的文件不同&#xff…

火爆全网的ChatGPT机器人,你玩了吗?

最近几天&#xff0c;由OpenAI公司发布的ChatGPT聊天机器人火了&#xff0c;小杨也怀着对新鲜事物的好奇&#xff0c;亲自体验了一下这个火爆全网&#xff0c;让人沉迷其中无法自拔的ChatGPT聊天机器人&#xff0c;经过体验&#xff0c;我只想用一个字来表达我的感受&#xff0…

⚡通信管理模块⚡

目录 &#x1f333;.通信管理模块的介绍 &#x1f333;.通信模块的设计 &#x1f333;.ListShow函数 &#x1f333;.UpLoad函数 &#x1f333;.DownLoad函数 下载的断点续传 &#x1f333;.通信管理模块的介绍 通信管理模块管理着服务器与浏览器之间的通信: 当服务器收…

猿如意工具-【SwitchHosts】详情介绍

一、什么是猿如意&#xff1f; 在发表文章的契机下&#xff0c;看到了【猿如意】这个名词。处于好奇&#xff0c;点击进行了解。 发现是我们熟悉的CSDN提供的一个面向开发者的辅助开发工具箱&#xff0c;猿如意的意思是-程序猿&#xff08;员&#xff09;的如意兵器。 它提供…

Elasticsearch与spring data整合api变化

记录 spring-data-elasticsearch 版本api变化 https://blog.csdn.net/zlpzlpzyd/article/details/128255792 spring boot 2.7.x 对应 spring-data-elasticsearch 4.4.x 排查问题之前先看一下上述链接中版本的对应关系 org.springframework.data.elasticsearch.core.Elastics…

如何搭建真实的性能测试环境?

在编写脚本的同时&#xff0c;执行场景之前需要完成测试环境的搭建工作&#xff0c;这里包括硬件和软件环境的搭建。根据性能测试计划中的测试环境规划&#xff0c;完成对整个测试环境的搭建。由于性能测试的特殊性&#xff0c;整个测试环境需要在严格的独立监控下管理&#xf…

微信建群怎么建?2个方法,快速学会!

​如果你想建立一个微信群来提高工作效率&#xff0c;你该怎么办&#xff1f;微信建群怎么建&#xff0c;找了很长一段时间不到。下面小编分享2个微信建群的方法&#xff0c;可以让您快速学习如何建立微信群&#xff01;感兴趣的小伙伴可以来看看哦&#xff01; 微信建群方法一…

JDBC第一章节(从概念到操作)

一、数据持久化存储回顾 1、持久化概述 2. JAVA中的数据存储 二、JDBC概述 1.概述 1.1 概述&#xff1a; 1.2 没有jdbc之前存在一些问题 1.3 有jdbc 之后 1.4 JDBC本质 1.5 优点 三、JDBC API 四、初始JDBC 操作数据库 1、操作步骤概述 2、实操步骤 2.1 导入MySQ…

Vue 实现拖拽模块(三)自定义拖拽组件的样式

上文介绍了 自定义拖拽组件位置 的简单实现&#xff0c;本文将继续给大家分享如何自定义拖拽组件位置的简单实现&#xff0c;文中通过示例代码介绍&#xff0c;感兴趣的小伙伴们可以了解一下 本文主要介绍了 Vue 自定义拖拽组件的样式&#xff0c;具体如下&#xff1a; 支持通过…

番外-LogParser(IIS日志分析)

编写原因&#xff1a;在线的那个信息管理系统&#xff0c;总有人添加空白数据&#xff0c;一加就是很多条&#xff0c;用这个分析一下&#xff0c;再发现之后将其IP拉入黑名单 1&#xff0c;下载安装 网盘下载链接 提取码&#xff1a;229e 文件下载后解压&#xff0c;解压后为…

Lecture5:卷积层、池化层、全连接层

目录 1.卷积层、池化层、全连接层 1.1 全连接层 1.2 卷积层 1.3 池化层 1.卷积层、池化层、全连接层 1.1 全连接层 对全连接层而言&#xff0c;我们要做的就是在这些向量上进行操作&#xff0c;比如我们有一张RGB-D图片&#xff0c;它的大小为32*32*3&#xff0c;我们将所…

vue3 几款值得推荐的UI组件库

推荐几个比较流行的VUE3 UI框架&#xff0c;同时提供出色的开发人员体验&#xff0c;合理利用&#xff0c;又或者学习借鉴都是不错的选择&#xff0c;排名不分先后。 Ant Design Vue 官方网站&#xff1a;https://2x.antdv.com/components/overview/ Ant Design Vue 是一个非…

PingCAP 成为中国唯一入选 Forrester Wave 数据库厂商,被评为卓越表现者

2022 年 12 月 6 日&#xff0c;国际权威研究机构 Forrester 发布了「Forrester Wave™: Translytical Data Platforms, Q4 2022 」报告&#xff0c;企业级开源分布式数据库厂商 PingCAP 作为中国唯一入围的数据库厂商&#xff0c;首次参评该报告即获评“卓越表现者&#xff08…

微服务框架 SpringCloud微服务架构 29 ES 集群 29.3 集群职责及脑裂

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构29 ES 集群29.3 集群职责及脑裂29.3.1 ES 集群的节点角色29.3.2 ES集群的分…

RAID图解

RAID图解什么是RAID各种 RAID 详解RAID 0RAID 1RAID 2&#xff08;已淘汰&#xff09;RAID 3RAID 4RAID 5RAID 6RAID 7RAID 01RAID 10RAID 10和RAID 01有何区别&#xff1f;实操教程其他问题最近在涉及到服务器安装系统这块才了解到RAID这个知识点&#xff0c;上网了解该知识&a…