雪花算法

article/2025/9/19 21:19:08

文章目录

  • 1、雪花算法的起源
  • 2、雪花算法原理
  • 3、雪花算法java实现
  • 4、一些细节讨论
    • 4.1调整比特位分布
    • 4.2workerid一般如何生成

1、雪花算法的起源

snowflake中文的意思是 雪花,雪片,所以翻译成雪花算法。它最早是twitter内部使用的分布式环境下的唯一ID生成算法。在2014年开源。开源的版本由scala编写,大家可以再找个地址找到这版本。

https://github.com/twitter-archive/snowflake/tags

雪花算法产生的背景当然是twitter高并发环境下对唯一ID生成的需求,得益于twitter内部牛逼的技术,雪花算法流传至今并被广泛使用。它至少有如下几个特点:

  • 能满足高并发分布式系统环境下ID不重复
  • 基于时间戳,可以保证基本有序递增(有些业务场景对这个又要求)
  • 不依赖第三方的库或者中间件
  • 生成效率极高

2、雪花算法原理

雪花算法的原理其实非常简单,我觉得这也是该算法能广为流传的原因之一吧。

算法产生的是一个long型 64 比特位的值,第一位未使用。接下来是41位的毫秒单位的时间戳,我们可以计算下:

2^41/1000*60*60*24*365 = 69

也就是这个时间戳可以使用69年不重复,这个对于大部分系统够用了。

很多人这里会搞错概念,以为这个时间戳是相对于一个我们业务中指定的时间(一般是系统上线时间),而不是1970年。这里一定要注意。

10位的数据机器位,所以可以部署在1024个节点。

12位的序列,在毫秒的时间戳内计数。 支持每个节点每毫秒产生4096个ID序号,所以最大可以支持单节点差不多四百万的并发量,这个妥妥的够用了。

3、雪花算法java实现

雪花算法因为原理简单清晰,所以实现的话基本大同小异。下面这个版本跟网上的很多差别也不大。唯一就是我加了一些注释方便你理解。

public class SnowflakeIdWorker {/** 开始时间截 (这个用自己业务系统上线的时间) */private final long twepoch = 1575365018000L;/** 机器id所占的位数 */private final long workerIdBits = 10L;/** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */private final long maxWorkerId = -1L ^ (-1L << workerIdBits);/** 序列在id中占的位数 */private final long sequenceBits = 12L;/** 机器ID向左移12位 */private final long workerIdShift = sequenceBits;/** 时间截向左移22位(10+12) */private final long timestampLeftShift = sequenceBits + workerIdBits;/** 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */private final long sequenceMask = -1L ^ (-1L << sequenceBits);/** 工作机器ID(0~1024) */private long workerId;/** 毫秒内序列(0~4095) */private long sequence = 0L;/** 上次生成ID的时间截 */private long lastTimestamp = -1L;//==============================Constructors=====================================/*** 构造函数* @param workerId 工作ID (0~1024)*/public SnowflakeIdWorker(long workerId) {if (workerId > maxWorkerId || workerId < 0) {throw new IllegalArgumentException(String.format("workerId can't be greater than %d or less than 0", maxWorkerId));}this.workerId = workerId;}// ==============================Methods==========================================/*** 获得下一个ID (该方法是线程安全的)* @return SnowflakeId*/public synchronized long nextId() {long timestamp = timeGen();//如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常if (timestamp < lastTimestamp) {throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));}//如果是同一时间生成的,则进行毫秒内序列if (lastTimestamp == timestamp) {sequence = (sequence + 1) & sequenceMask;//毫秒内序列溢出if (sequence == 0) {//阻塞到下一个毫秒,获得新的时间戳timestamp = tilNextMillis(lastTimestamp);}}//时间戳改变,毫秒内序列重置else {sequence = 0L;}//上次生成ID的时间截lastTimestamp = timestamp;//移位并通过或运算拼到一起组成64位的IDreturn ((timestamp - twepoch) << timestampLeftShift) //| (workerId << workerIdShift) //| sequence;}/*** 阻塞到下一个毫秒,直到获得新的时间戳* @param lastTimestamp 上次生成ID的时间截* @return 当前时间戳*/protected long tilNextMillis(long lastTimestamp) {long timestamp = timeGen();while (timestamp <= lastTimestamp) {timestamp = timeGen();}return timestamp;}/*** 返回以毫秒为单位的当前时间* @return 当前时间(毫秒)*/protected long timeGen() {return System.currentTimeMillis();}
}

可能有些人对于下面这个生成最大值得方法不太理解,我这里解释下,

private final long sequenceMask = -1L ^ (-1L << sequenceBits);

首先我们要知道负数在计算机里是以补码的形式表达的,而补码是负数的绝对值的原码,再取得反码,然后再加1得到。

好像有点乱是吧,举个例子吧。

-1取绝对值是1,1的二进制表示,也就是原码是:

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001

然后取反操作,也就是1变0; 0变1,得到:

11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111110

然后加1,得到:

11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111

OK,这就是-1在计算机中的表示了,然后我们来看看(-1L « sequenceBits),这个很简单,直接左移12个比特位即可,得到:

11111111 11111111 11111111 11111111 11111111 11111111 11110000 00000000

上面两个异或,得到:

00000000 00000000 00000000 00000000 00000000 00000000 00001111 11111111

也就是4095。

上面第一部分说到雪花算法的性能比较高,接下来我们测试下性能:

public static void main(String[] args) {SnowflakeIdWorker idWorker = new SnowflakeIdWorker(1);long start = System.currentTimeMillis();int count = 0;for (int i = 0; System.currentTimeMillis()-start<1000; i++,count=i) {idWorker.nextId();}long end = System.currentTimeMillis()-start;System.out.println(end);System.out.println(count);}

用上面这段代码,在我自己的评估笔记本上,每秒可以产生400w+的id。效率还是相当高的。

4、一些细节讨论

4.1调整比特位分布

很多公司会根据 snowflake 算法,根据自己的业务做二次改造。举个例子。你们公司的业务评估不需要运行69年,可能10年就够了。但是集群的节点可能会超过1024个,这种情况下,你就可以把时间戳调整成39bit,然后workerid调整为12比特。同时,workerid也可以拆分下,比如根据业务拆分或者根据机房拆分等。类似如下:

4.2workerid一般如何生成

方案有很多。比如我们公司以前用过通过jvm启动参数的方式传过来,应用启动的时候获取一个启动参数,保证每个节点启动的时候传入不同的启动参数即可。启动参数一般是通过-D选项传入,示例:

-Dname=value

然后我们在代码中可以通过

System.getProperty("name");

获取,或者通过 @value注解也能拿到。

还有问题,现在很多部署都是基于k8s的容器化部署,这种方案往往是基于同一个yaml文件一键部署多个容器。所以没法通过上面的方法每个节点传入不同的启动参数。

这个问题可以通过在代码中根据一些规则计算workerid,比如根据节点的IP地址等。下面给出一个方案:

private static long makeWorkerId() {try {String hostAddress = Inet4Address.getLocalHost().getHostAddress();int[] ips = StringUtils.toCodePoints(hostAddress);int sums = 0;for (int ip: ips) {sums += ip;}return (sums % 1024);} catch (UnknownHostException e) {return RandomUtils.nextLong(0, 1024);}}

这里其实是获取了节点的IP地址,然后把ip地址中的每个字节的ascii码值相加然后对最大值取模。当然这种方法是有可能产生重复的id的。

网上还有一些其它方案,比如取IP的后面10个比特位等。

总之不管用什么方案,都要尽量保证workerid不重复,否则即便是在并发量不高的情况下,也很容易出现id重复的情况。


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

相关文章

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.反…

卷积和反卷积详解

反卷积&#xff08;deconvolution&#xff09;&#xff0c;也叫转置卷积&#xff0c;分部卷积&#xff08;fractionally-strided convolution&#xff09;&#xff0c;在论文中也叫upconv。 1. Pytorch中2D卷积和反卷积的函数 class torch.nn.Conv2d(in_channels, out_channe…