分布式id解决方法--雪花算法
uuid,jdk自带,但是数据库性能差,32位呀。
mysql数据库主键越短越好,B+tree产生节点分裂,大大降低数据库性能,所以uuid不建议。
redis的自增,但是要配置维护redis集群,就为了一个id,还要引入一套redis。费事,成本高。
如果有序自增别人就知道你的业务量多少了。
雪花算法
分布式自增id算法snowflake,京东还有好多大厂使用这个。
经测试每秒能产生26w个自增可以排序的id
1.生成id能按照时间有序生成
2.生成id结果是一个64bit大小的整数,为一个Long型(转换成字符串长度最多19)
3.分布式系统内不会产生id碰撞(由datacenter和worderId作区分)并且效率高。
雪花算法几个核心组成部分


1bit,符号位,不用,因为二进制中最高位是符号位,1表示负,0表示正。生成的id是正数,所以是0.
5位机房id,5位机器id

一毫秒内只能生成4095,如果超过只能到下一秒了,需要获取下一个时间戳
雪花算法的原理就是生成一个的 64 位比特位的 long 类型的唯一 id。
最高 1 位固定值 0,因为生成的 id 是正整数,如果是 1 就是负数了。
接下来 41 位存储毫秒级时间戳,2^41/(1000606024365)=69,大概可以使用 69 年。
再接下 10 位存储机器码,包括 5 位 datacenterId 和 5 位 workerId。最多可以部署 2^10=1024 台机器。
最后 12 位存储序列号。同一毫秒时间戳时,通过这个递增的序列号来区分。即对于同一台机器而言,同一毫秒时间戳下,可以生成 2^12=4096 个不重复 id。
如何使用,整合springboot即可
hutool工具包
雪花算法源码
判断是否时钟回拨,回拨抛异常不做处理


如果是这个时间第一次,sequence=0,如果同一个时间有其他进入,则(sequence+1)& sequenceMask计算,这个计算就是和12个1做与运算,当你小于4095时后,还是你自己,当大于的时候,比方是4096,计算后就是0,如果并发特别高,1毫秒产生的大于4096,阻塞到下一毫秒。通过while循环等一下,等到下一毫秒,然后变成下一个时间段了。
真正自己代码会减掉一个自己的系统初始时间,可以让我们时间更长

通过zookeeper生成机器id

雪花服务注册到nacos注册中心
时钟回拨问题
雪花算法源码里面通过判断时间大小来判断是否发生时间回拨,如果发生,抛异常,拒绝生成。这里没有做任何时钟回拨处理,所以线上机器不要动。
如何处理时钟回拨问题呢?
雪花算法源码没有解决,真的线上不能使用,需要修改。才能达到高并发,高可用,高可扩展。
第一种解决方法,我们可以加个容忍时间,设置3ms,如果发生时钟回拨,我们用LockSupport锁来睡一下,睡上最大容忍时间3ms,然后再去看一下有没有时钟回拨问题。如果还是有问题呢?我们要通过人为干预解决了
第二种解决方法,雪花算法10位机器是可以控制的,我们用备用机解决,
回拨时间长短,如果短,等待一会儿。
如果时间适中,可以将最近的数据时间段,每一毫秒的maxId数据保存起来,在他最后面开始++。
如果时间再长,雪花算法10位机器是可以控制的,我们用备用机解决,重试其他机器,换一台机器。下次再走到,已经过了时间,没有回拨问题了。
如果时间更长,机器下线,不能用了,人为解决吧。调用nacos服务下限api,将这台机器直接下线。同步发送短信告知运维。
百度开源的 UidGenerator 是基于Java语言实现的唯一ID生成器,是在雪花算法 snowflake 的基础上做了一些改进(解决了时钟回拨问题)。
美团,Leaf
基于雪花算法进行修改封装。
工作进程怎么办,1024台怎么维护
分布式主键中间件获取id,由他区分工作进程,用美团的Leaf服务,Leaf也是高可用,负载均衡
保证leaf也是不同id,0-1023,zookeeper有序节点,启动leaf,一直能扩展到1023.
Leaf需要依赖zookeeper顺序节点,通过RPC去Leaf中获取id
还有就是解决时钟回拨问题
Leaf-snowflake 方案
Leaf-segment 方案可以生成趋势递增的 ID,同时 ID 号是可计算的,不适用于订单 ID 生成场景,比如竞对在两天中午 12 点分别下单,通过订单 id 号相减就能大致计算出公司一天的订单量,这个是不能忍受的。面对这一问题,我们提供了 Leaf-snowflake 方案。
Leaf-snowflake不同于原始snowflake算法地方,主要是在workId的生成上,Leaf-snowflake依靠Zookeeper生成workId,也就是上边的机器ID(占5比特)+ 机房ID(占5比特)。Leaf中workId是基于ZooKeeper的顺序Id来生成的,每个应用在使用Leaf-snowflake时,启动时都会都在Zookeeper中生成一个顺序Id,相当于一台机器对应一个顺序节点,也就是一个workId。
Leaf-snowflake 方案完全沿用 snowflake 方案的 bit 位设计,即是 “1+41+10+12” 的方式组装 ID 号。对于 workerID 的分配,当服务集群数量较小的情况下,完全可以手动配置。Leaf 服务规模较大,动手配置成本太高。所以使用 Zookeeper 持久顺序节点的特性自动对 snowflake 节点配置 wokerID。Leaf-snowflake 是按照下面几个步骤启动的:
启动 Leaf-snowflake 服务,连接 Zookeeper,在 leaf_forever 父节点下检查自己是否已经注册过(是否有该顺序子节点)。
如果有注册过直接取回自己的 workerID(zk 顺序节点生成的 int 类型 ID 号),启动服务。
如果没有注册过,就在该父节点下面创建一个持久顺序节点,创建成功后取回顺序号当做自己的 workerID 号,启动服务。

弱依赖 ZooKeeper
除了每次会去 ZK 拿数据以外,也会在本机文件系统上缓存一个 workerID 文件。当 ZooKeeper 出现问题,恰好机器出现问题需要重启时,能保证服务能够正常启动。这样做到了对三方组件的弱依赖。一定程度上提高了 SLA
启动Leaf-snowflake模式也比较简单,启动本地ZooKeeper,修改一下项目中的leaf.properties文件,关闭leaf.segment模式,启用leaf.snowflake模式即可。
leaf.name=com.sankuai.leaf.opensource.test
leaf.segment.enable=false
leaf.snowflake.enable=true
leaf.snowflake.zk.address=127.0.0.1
leaf.snowflake.port=2181
注意:在启动项目之前,请保证已经正常启动zookeeper
解决时钟问题
因为这种方案依赖时间,如果机器的时钟发生了回拨,那么就会有可能生成重复的 ID 号,需要解决时钟回退的问题。

参见上图整个启动流程图,服务启动时首先检查自己是否写过 ZooKeeper leaf_forever 节点:
若写过,则用自身系统时间与 leaf_forever/ s e l f 节点记录时间做比较,若小于 l e a f f o r e v e r / {self} 节点记录时间做比较,若小于 leaf_forever/ self节点记录时间做比较,若小于leafforever/{self} 时间则认为机器时间发生了大步长回拨,服务启动失败并报警。
若未写过,证明是新服务节点,直接创建持久节点 leaf_forever/${self} 并写入自身系统时间,接下来综合对比其余 Leaf 节点的系统时间来判断自身系统时间是否准确,具体做法是取 leaf_temporary 下的所有临时节点 (所有运行中的 Leaf-snowflake 节点) 的服务 IP:Port,然后通过 RPC 请求得到所有节点的系统时间,计算 sum (time)/nodeSize。
若 abs (系统时间 - sum (time)/nodeSize ) < 阈值,认为当前系统时间准确,正常启动服务,同时写临时节点 leaf_temporary/${self} 维持租约。
否则认为本机系统时间发生大步长偏移,启动失败并报警。
每隔一段时间 (3s) 上报自身系统时间写入 leaf_forever/${self}。
由于强依赖时钟,对时间的要求比较敏感,在机器工作时 NTP 同步也会造成秒级别的回退,建议可以直接关闭 NTP 同步。要么在时钟回拨的时候直接不提供服务直接返回 ERROR_CODE,等时钟追上即可。或者做一层重试,然后上报报警系统,更或者是发现有时钟回拨之后自动摘除本身节点并报警,如下:
//发生了回拨,此刻时间小于上次发号时间
if (timestamp < lastTimestamp) { long offset = lastTimestamp - timestamp; if (offset <= 5) { try { //时间偏差大小小于5ms,则等待两倍时间wait(offset << 1);//waittimestamp = timeGen(); if (timestamp < lastTimestamp) { //还是小于,抛异常并上报throwClockBackwardsEx(timestamp);} } catch (InterruptedException e) { throw e;}} else { //throwthrowClockBackwardsEx(timestamp);}} //分配ID
从上线情况来看,在 2017 年闰秒出现那一次出现过部分机器回拨,由于 Leaf-snowflake 的策略保证,成功避免了对业务造成的影响。
相关文章:
分布式id解决方法--雪花算法
uuid,jdk自带,但是数据库性能差,32位呀。 mysql数据库主键越短越好,Btree产生节点分裂,大大降低数据库性能,所以uuid不建议。 redis的自增,但是要配置维护redis集群,就为了一个id&a…...
5年经验之谈:月薪3000到30000,测试工程师的变“行”记
自我介绍下,我是一名转IT测试人,我的专业是化学,去化工厂实习才发现这专业的坑人之处,化学试剂害人不浅,有毒,易燃易爆,实验室经常用丙酮,甲醇,四氯化碳,接触…...
PMP考试都是什么题?
PMP新版大纲加入了ACP敏捷管理的内容,说是敏捷混合题型占到了 50%,但是这次318的考试,敏捷题占了大半,都说敏捷和情景快要占到80%-90%。 所以有友友说开了四个小时盲盒,题目读不懂,或者觉得4个选项都不对或…...
macbook2023系统清理软件cleanmymac中文版
cleanmymac x 中文版基本都是大家首选Mac清理软件了。它集各种功能于一身,几乎满足用户所有的清理需求。它可以清理,优化,保养和监测您的电脑,确保您的Mac运行畅通无阻!支持一键快速清理Mac,快速检查并安全…...
基于Python+AIML+Tornado的智能聊天机器人(NLP+深度学习)含全部工程源码+语料库 适合个人二次开发
目录 前言总体设计系统整体结构图系统流程图 运行环境Python 环境Tornado 环境 模块实现1. 前端2. 后端3. 语料库4. 系统测试 其它资料下载 前言 本项目旨在利用AIML技术构建一个聊天机器人,实现用户通过聊天界面与机器人交互的功能。通过提供的工程源代码…...
算法Day15 | 层序遍历,102,107,199,637,429,515,116,117,104,111,226,101
Day15 层序遍历102.二叉树的层序遍历107.二叉树的层次遍历 II199.二叉树的右视图637.二叉树的层平均值429.N叉树的层序遍历515.在每个树行中找最大值116.填充每个节点的下一个右侧节点指针117.填充每个节点的下一个右侧节点指针II104.二叉树的最大深度111.二叉树的最小深度 226…...
Prometheus+Grafana学习(十一)安装使用pushgateway
Pushgateway允许短暂和批量作业将其指标暴露给 Prometheus。由于这些工作的生命周期可能不足够长,不能够存在足够的时间以让 Prometheus 抓取它们的指标。Pushgateway 允许它们可以将其指标推送到 Pushgateway,然后 Pushgateway 再将这些指标暴露给 Prom…...
深入理解C/C++预处理器指令#pragma once以及与ifndef的比较
#pragma once用法总结 为了防止重复引用造成二义性 在C/C中,在使用预编译指令#include的时候,为了防止重复引用造成二义性,通常有两种方式 第一种是#ifndef指令防止代码块重复引用,比如说 #ifndef _CODE_BLOCK #define _CODE_BLO…...
git 环境配置 + gitee拉取代码
好嘛 配环境的时候 老是忘记这个命令行 干脆自己写一个记录一下 也不用搜了 1.先从git官网下载git 安装 2.然后从gitee拉取代码的时候提示 这是因为换了新电脑没有加入新的公钥啦 哎 所以老是记不住命令行 first : git config --global user.name “Your Name” …...
港联证券|港股拥抱特专科技企业 内资券商“修炼内功”蓄势而为
港股市场新一轮改革举措渐次落地。特别是港交所推出特专科技公司上市机制,吸引符合资格的科技企业申请赴港上市,成为这一轮港股市场改革的“重头戏”。 作为香港资本市场的重要参与者,内资券商立足香港、背靠内地、辐射全球,走出一…...
多项创新技术加持,实现零COGS的Microsoft Editor语法检查器
编者按:Microsoft Editor 是一款人工智能写作辅助工具,其中的语法检查器(grammar checker)功能不仅可以帮助不同水平、领域的用户在写作过程中检查语法错误,还可以对错误进行解释并给出正确的修改建议。神经语法检查器…...
Python编程环境搭建:Windows中如何安装Python
在 Windows 上安装 Python 和安装普通软件一样简单,下载安装包以后猛击“下一步”即可。 Python 安装包下载地址:https://www.python.org/downloads/ 打开该链接,可以看到有两个版本的 Python,分别是 Python 3.x 和 Python 2.x&…...
Sui Builder House首尔站倒计时!
Sui主网上线后的第一场Builder House活动即将在韩国首尔举行,同期将举办首场线下面对面的黑客松。活动历时两天,将为与会者提供独特的学习、交流和娱乐的机会。活动详情请查看:Sui Builder House首尔站|主网上线后首次亮相。 Sui…...
Java设计模式-状态模式
简介 在软件开发领域,设计模式是一组经过验证的、被广泛接受的解决问题的方案。其中之一是状态模式,它提供了一种优雅的方式来管理对象的不同状态。 状态模式是一种行为型设计模式,它允许对象在内部状态发生改变时改变其行为。状态模式将对…...
智慧社区用什么技术开发
智慧社区是指利用信息技术和先进的管理理念,将社区内的各种公共服务进行整合和优化,提高社区居民的生活品质和社区管理的效率。为了实现智慧社区的建设,需要采用多种技术,包括但不限于以下几种: 1.物联网技术…...
多线程 线程池饱和策略
RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。 这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。 在JDK 1…...
进程间通信之信号
进程间通信之信号 1. 信号2. 信号由谁产生?3. 有哪些信号4. 信号的安装5. 信号的发送1) 使用kill函数2)使用alarm函数3) 使用raise6.发送多个信号7. 信号集1. 信号 什么是信号? 信号是给程序提供一种可以处理异步事件的方法,它利用软件中断来实现。不能自定义信号,所有信号…...
二分查找三道题
二分查找 两种写法:左闭右闭[left,right]、左闭右开[left,right) 主要有几点不同:1. right是从num.length开始还是从num.length-1开始。2.left<还是<right。3.rightmid还是mid1 左闭右闭写法: public int search(int[] nums, int targ…...
MyBatis 框架
MyBatis 框架 MyBatis 简介搭建 MyBatis 开发环境核心配置文件详解mapper 映射文件(实现增删改查)MyBatis获取参数值的两种方式MyBatis的各种查询功能特殊SQL的执行自定义映射resultMapresultMap 字段和属性的映射多对一映射处理一对多映射处理 动态SQLM…...
【C++】虚表和虚基表到底有哪些区别?
虚表和虚基表 虚表虚基表虚拟继承和虚函数都存在时的对象模型 虚表 我们知道,如果类中声明了的方法是用virtual进行修饰的,则说明当前这个方法要作为虚函数,而虚函数的存储和普通函数的存储是有区别的 当有虚函数声明时,编译器会…...
全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...
