雪花算法简介

article/2025/9/19 21:18:03

文章目录

  • 1、简介
  • 2、雪花算法
  • 3、算法实现
  • 4、算法优缺点
  • 5、补充

1、简介

在生成随机主键的时候,我第一个想到的就是UUID,但是UUID在MySQL中作为主键生成时,就会出现一个问题,UUID生成的是乱序的。这时候,学习MP的过程中,发现MP在插入主键时,使用的算法是雪花算法

雪花算法是Twitter公司发明的一种算法,主要目的是解决在分布式环境下,ID怎样生成的问题

2、雪花算法

在这里插入图片描述

雪花算法的原理就是生成一个的 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。

雪花算法可以作为一个单独服务来进行,只需要指定10为的机器码即可。

3、算法实现

package com.shang.reggie.common;import java.util.Date;/*** @Author :漠殇* @Data :Create in 17:14 2022/6/22*/
public class SnowFlakeUtil {private static SnowFlakeUtil snowFlakeUtil;static {snowFlakeUtil = new SnowFlakeUtil();}// 当前的时间戳 2022-06-22 17:27:00  = 》 1655890020000private static final long INIT_EPOCH = 1655890020000L;// 时间位取&private static final long TIME_BIT = 0b1111111111111111111111111111111111111111110000000000000000000000L;// 记录最后使用的毫秒时间戳,主要用于判断是否同一毫秒,以及用于服务器时钟回拨判断private static long lastTimeMillis = -1L;// dataCenterId占用的位数private static final long DATA_CENTER_ID_BITS = 5L;// dataCenterId占用5个比特位,最大值31// 0000000000000000000000000000000000000000000000000000000000011111private static final long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_ID_BITS);// dataCenterIdprivate long dataCenterId;// workId占用的位数private static final long WORKER_ID_BITS = 5L;// workId占用5个比特位,最大值31// 0000000000000000000000000000000000000000000000000000000000011111private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);// workIdprivate long workerId;// 最后12位,代表每毫秒内可产生最大序列号,即 2^12 - 1 = 4095private static final long SEQUENCE_BITS = 12L;// 掩码(最低12位为1,高位都为0),主要用于与自增后的序列号进行位与,如果值为0,则代表自增后的序列号超过了4095// 0000000000000000000000000000000000000000000000000000111111111111private static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);// 同一毫秒内的最新序号,最大值可为 2^12 - 1 = 4095private long sequence;// workId位需要左移的位数 12private static final long WORK_ID_SHIFT = SEQUENCE_BITS;// dataCenterId位需要左移的位数 12+5private static final long DATA_CENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;// 时间戳需要左移的位数 12+5+5private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATA_CENTER_ID_BITS;/*** 无参构造*/public SnowFlakeUtil() {this(1, 1);}/*** 有参构造* @param dataCenterId* @param workerId*/public SnowFlakeUtil(long dataCenterId, long workerId) {// 检查dataCenterId的合法值if (dataCenterId < 0 || dataCenterId > MAX_DATA_CENTER_ID) {throw new IllegalArgumentException(String.format("dataCenterId 值必须大于 0 并且小于 %d", MAX_DATA_CENTER_ID));}// 检查workId的合法值if (workerId < 0 || workerId > MAX_WORKER_ID) {throw new IllegalArgumentException(String.format("workId 值必须大于 0 并且小于 %d", MAX_WORKER_ID));}this.workerId = workerId;this.dataCenterId = dataCenterId;}/*** 获取唯一ID* @return*/public static Long getSnowFlakeId() {return snowFlakeUtil.nextId();}/*** 通过雪花算法生成下一个id,注意这里使用synchronized同步* @return 唯一id*/public synchronized long nextId() {long currentTimeMillis = System.currentTimeMillis();System.out.println(currentTimeMillis);// 当前时间小于上一次生成id使用的时间,可能出现服务器时钟回拨问题if (currentTimeMillis < lastTimeMillis) {throw new RuntimeException(String.format("可能出现服务器时钟回拨问题,请检查服务器时间。当前服务器时间戳:%d,上一次使用时间戳:%d", currentTimeMillis,lastTimeMillis));}if (currentTimeMillis == lastTimeMillis) {// 还是在同一毫秒内,则将序列号递增1,序列号最大值为4095// 序列号的最大值是4095,使用掩码(最低12位为1,高位都为0)进行位与运行后如果值为0,则自增后的序列号超过了4095// 那么就使用新的时间戳sequence = (sequence + 1) & SEQUENCE_MASK;if (sequence == 0) {currentTimeMillis = getNextMillis(lastTimeMillis);}} else { // 不在同一毫秒内,则序列号重新从0开始,序列号最大值为4095sequence = 0;}// 记录最后一次使用的毫秒时间戳lastTimeMillis = currentTimeMillis;// 核心算法,将不同部分的数值移动到指定的位置,然后进行或运行// <<:左移运算符, 1 << 2 即将二进制的 1 扩大 2^2 倍// |:位或运算符, 是把某两个数中, 只要其中一个的某一位为1, 则结果的该位就为1// 优先级:<< > |return// 时间戳部分((currentTimeMillis - INIT_EPOCH) << TIMESTAMP_SHIFT)// 数据中心部分| (dataCenterId << DATA_CENTER_ID_SHIFT)// 机器表示部分| (workerId << WORK_ID_SHIFT)// 序列号部分| sequence;}/*** 获取指定时间戳的接下来的时间戳,也可以说是下一毫秒* @param lastTimeMillis 指定毫秒时间戳* @return 时间戳*/private long getNextMillis(long lastTimeMillis) {long currentTimeMillis = System.currentTimeMillis();while (currentTimeMillis <= lastTimeMillis) {currentTimeMillis = System.currentTimeMillis();}return currentTimeMillis;}/*** 获取随机字符串,length=13* @return*/public static String getRandomStr() {return Long.toString(getSnowFlakeId(), Character.MAX_RADIX);}/*** 从ID中获取时间* @param id 由此类生成的ID* @return*/public static Date getTimeBySnowFlakeId(long id) {return new Date(((TIME_BIT & id) >> 22) + INIT_EPOCH);}}

测试:

public static void main(String[] args) {SnowFlakeUtil snowFlakeUtil = new SnowFlakeUtil();long id = snowFlakeUtil.nextId();System.out.println(id);Date date = SnowFlakeUtil.getTimeBySnowFlakeId(id);System.out.println(date + "date");long time = date.getTime();System.out.println(time);System.out.println(getRandomStr());
}

4、算法优缺点

优点:

  • 高并发分布式环境下生成不重复 id,每秒可生成百万个不重复 id。
  • 基于时间戳,以及同一时间戳下序列号自增,基本保证 id 有序递增。
  • 不依赖第三方库或者中间件。
  • 算法简单,在内存中进行,效率高。

缺点:

  • 依赖服务器时间,服务器时钟回拨时可能会生成重复 id。算法中可通过记录最后一个生成 id 时的时间戳来解决,每次生成 id 之前比较当前服务器时钟是否被回拨,避免生成重复 id。

5、补充

其实雪花算法每一部分占用的比特位数量并不是固定死的。例如你的业务可能达不到69年之久,那么可用减少时间戳占用的位数,雪花算法服务需要部署的节点超过1024台,那么可将减少的位数补充给机器码用。

注意,雪花算法中41位比特位不是直接用来存储当前服务器毫秒时间戳的,而是需要当前服务器时间戳减去某一个初始时间戳值,一般可以使用服务上线时间作为初始时间戳值。

对于机器码,可根据自身情况做调整,例如机房号,服务器号,业务号,机器 IP 等都是可使用的。对于部署的不同雪花算法服务中,最后计算出来的机器码能区分开来即可。

本文参考自:SnowFlake 雪花算法详解与实现


http://chatgpt.dhexx.cn/article/uV9SvDlb.shtml

相关文章

雪花算法

文章目录 1、雪花算法的起源2、雪花算法原理3、雪花算法java实现4、一些细节讨论4.1调整比特位分布4.2workerid一般如何生成 1、雪花算法的起源 snowflake中文的意思是 雪花&#xff0c;雪片&#xff0c;所以翻译成雪花算法。它最早是twitter内部使用的分布式环境下的唯一ID生…

SnowFlake 雪花算法详解与实现

我是陈皮&#xff0c;一个在互联网 Coding 的 ITer&#xff0c;个人微信公众号「陈皮的JavaLib」关注第一时间阅读最新文章。 文章目录 背景SnowFlake 雪花算法算法实现算法验证算法优缺点注意事项 背景 现在的服务基本是分布式&#xff0c;微服务形式的&#xff0c;而且大数据…

雪花算法(SnowFlake)

简介 现在的服务基本是分布式、微服务形式的&#xff0c;而且大数据量也导致分库分表的产生&#xff0c;对于水平分表就需要保证表中 id 的全局唯一性。 对于 MySQL 而言&#xff0c;一个表中的主键 id 一般使用自增的方式&#xff0c;但是如果进行水平分表之后&#xff0c;多…

二维反卷积 matlab,二维反卷积的实现(实际意义不明确)

前言 一维反卷积(deconv),可以很好的实现一维卷积的反过程!但是二维反卷积就很难恢复了!为什么呢?因为我们知道二维卷积计算的过程就是:卷积核不断滑动,卷积核不断与原始数据中的小矩阵做"点乘并求和";现假设卷积核为3x3,那么每一个和它点乘的小矩阵对应尺寸…

python 反卷积(DeConv) tensorflow反卷积(DeConv)(实现原理+手写)

Tensorflow反卷积&#xff08;DeConv&#xff09;实现原理手写python代码实现反卷积&#xff08;DeConv&#xff09; 理解&#xff1a; https://www.zhihu.com/question/43609045/answer/130868981 上一篇文章已经介绍过卷积的实现&#xff0c;这篇文章我们学习反卷积原理&am…

地震信号系列完结篇-反卷积方法

前言 本篇将详细地讲解地震信号中用到的反卷积方法。反卷积方法的作用在文章 地震信号的一些基本概念 中已经阐述过&#xff0c;简单的说就是&#xff1a;在压缩原信号的同时&#xff0c;对频谱进行补偿&#xff08;反卷积的输出信号&#xff09;。而在地震信号处理中&#xf…

反卷积的棋盘格效应

本文译自来自谷歌大脑的AUGUSTUS ODENA等人的文章: Deconvolution and Checkerboard Artifacts[1], 虽然是16年的博客了, 但是其对解释反卷积的棋盘效应已经如何规避都给出了非常好和到位的意见. 下面让我们开始~ 前言 当我们分析由神经网络生成的图片的时候, 常常会发觉有一种…

反卷积神经网络介绍

反卷积是指&#xff1a;通过测量输出和已经输入重构未知输入的过程。在神经网络中&#xff0c;反卷积过程并不具备学习的能力&#xff0c;仅仅是用于可视化一个已经训练好的卷积网络模型&#xff0c;没有学习训练的过程。 下图所示为VGG 16反卷积神经网络的结构&#xff0c;展示…

一文读懂什么是反卷积

反卷积&#xff08;Deconvolution&#xff09;的概念第一次出现是Zeiler在2010年发表的论文Deconvolutional networks中&#xff0c;但是并没有指定反卷积这个名字&#xff0c;反卷积这个术语正式的使用是在其之后的工作中(Adaptive deconvolutional networks for mid and high…

反卷积相关论文理解

关于反卷积原理&#xff0c;小编就不再赘述&#xff0c;在知乎中有详细的解释&#xff0c;很清晰&#xff0c;都是大佬。 链接如下&#xff1a;https://www.zhihu.com/question/43609045/answer/120266511 反卷积相对于卷积在神经网络结构的正向和反向传播中做相反的运算&…

反卷积理解和推导

参考 怎样通俗易懂地解释反卷积&#xff1f; - 知乎&#xff0c;【基础知识学习】卷积与反卷积学习笔记 - 知乎 1.概念 反卷积是一种特殊的正向卷积&#xff0c;先按照一定的比例通过补 0 来扩大输入图像的尺寸&#xff0c;接着旋转卷积核&#xff0c;再进行正向卷积。 图1 反…

生物信息学反卷积论文阅读

文章目录 反卷积的概念反卷积的具体方式反卷积预测RNA序列知识背景公式推导 亚硫酸氢盐测序知识背景公式推导 R包的使用RNA测序数据分析使用亚硫酸氢盐数据进行测序 反卷积的概念 由于许多组织样本不适合分解成单个细胞&#xff0c;因此不能利用单细胞RNA测序技术对它们的单个…

理解反卷积

先看看卷积&#xff0c;数字只是说明位置方便&#xff0c;不是具体数值&#xff0c;这里是valid卷积 &#xff0c;stride1 由CNN基础我们知道 17 这个点是由前面1 2 5 6 和卷积核运算得到的&#xff0c;那么反卷积就是要从17 反推1,2,5,6 &#xff0c;这是一个无穷解问题&#…

反卷积常用方法

反卷积 一个用于分类任务的深度神经网络通过卷积来不断抽象学习&#xff0c;实现分辨率的降低&#xff0c;最后得到一个较小的FeatureMap&#xff0c;即特征图&#xff0c;通常大小为 5 5 5\times5 55或者 7 7 7\times7 77。而图像分割任务需要恢复与原尺寸大小一样的图片&am…

声音反卷积matlab,用MATLAB做反卷积

关键词&#xff1a;反卷积 MATLAB fft 频移 分母中频谱零点 卷积核 % 代码如下&#xff1a; clear all;clc; h [1 1 1 1] % 要求 f [1 -2 3 -2] % 已知 g conv(h,f) % 已知 g h*f 这里卷积结果g知道&#xff0c;f知道&#xff0c;f视作卷积核&#xff0c;反卷积求h …

彻底搞懂CNN中的卷积和反卷积

前言 卷积和反卷积在CNN中经常被用到&#xff0c;想要彻底搞懂并不是那么容易。本文主要分三个部分来讲解卷积和反卷积&#xff0c;分别包括概念、工作过程、代码示例&#xff0c;其中代码实践部分主结合TensorFlow框架来进行实践。给大家介绍一个卷积过程的可视化工具&#x…

卷积与反卷积

1、卷积 上图展示了一个卷积的过程&#xff0c;其中蓝色的图片(4*4)表示的是进行卷积的图片&#xff0c;阴影的图片(3*3)表示的是卷积核&#xff0c;绿色的图片(2*2)表示是进行卷积计算之后的图片。在卷积操作中有几个比较重要的参数&#xff0c;输入图片的尺寸、步长、卷积核的…

反卷积原理

一 介绍 反卷积&#xff0c;可以理解为卷积操作的逆运算。这里千万不要当成反卷积操作可以复原卷积操作的输入值&#xff0c;反卷积并没有那个功能&#xff0c;它仅仅是将卷积变换过程中的步骤反向变换一次而已&#xff0c;通过将卷积核转置&#xff0c;与卷积后的结果再做一遍…

Tensorflow——反卷积

目标——主要用来进行上采样&#xff0c;使图像形状变大 函数&#xff1a;conv2d_transpose(value, filter, output_shape, strides, padding"SAME", data_format"NHWC", nameNone) Arg&#xff1a; value&#xff1a;指需要做反卷积的输入图像&#xff…

机器学习19:反卷积算法

机器学习19:反卷积算法&#xff08;转载和整理&#xff09; 在整理全卷积网络的过程中&#xff0c;被反卷积的概念困扰很久&#xff0c;于是将反卷积算法单独整理为一篇博客&#xff0c;本文主要转载和整理自知乎问题如何通俗易懂地解释反卷积&#xff1f;中的高票答案。 1.反…