雪花算法以及具体实现

article/2025/9/19 20:45:08

一、为何要用雪花算法

    1、问题产生的背景

        现如今越来越多的公司都在用分布式、微服务,那么对应的就会针对不同的服务进行数据库拆分,然后当数据量上来的时候也会进行分表,那么随之而来的就是分表以后id的问题。

        例如之前单体项目中一个表中的数据主键id都是自增的,mysql是利用autoincrement来实现自增,而oracle是利用序列来实现的,但是当单表数据量上来以后就要进行水平分表,阿里java开发建议是单表大于500w的时候就要分表,但是具体还是得看业务,如果索引用的号的话,单表千万的数据也是可以的。水平分表就是将一张表的数据分成多张表,那么问题就来了如果还是按照以前的自增来做主键id,那么就会出现id重复,这个时候就得考虑用什么方案来解决分布式id的问题了。

    2、解决方案

        2.1、数据库表

        可以在某个库中专门维护一张表,然后每次无论哪个表需要自增id的时候都去查这个表的记录,然后用for update锁表,然后取到的值加一,然后返回以后把再把值记录到表中,但是这个方法适合并发量比较小的项目,因此每次都得锁表。

        2.2、redis

        因为redis是单线程的,可以在redis中维护一个键值对,然后哪个表需要直接去redis中取值然后加一,但是这个跟上面一样由于单线程都是对高并发的支持不高,只适合并发量小的项目。

        2.3、uuid

        可以使用uuid作为不重复主键id,但是uuid有个问题就是其是无序的字符串,如果使用uuid当做主键,那么主键索引就会失效。

        2.4、雪花算法

        雪花算法是解决分布式id的一个高效的方案,大部分互联网公司都在使用雪花算法,当然还有公司自己实现其他的方案。

二、雪花算法

1、原理

       

        雪花算法就是使用64位long类型的数据存储id,最高位一位存储0或者1,0代表整数,1代表负数,一般都是0,所以最高位不变,41位存储毫秒级时间戳,10位存储机器码(包括5位datacenterId和5位workerId),12存储序列号。这样最大2的10次方的机器,也就是1024台机器,最多每毫秒每台机器产生2的12次方也就是4096个id。(下面有代码实现)

         但是一般我们没有那么多台机器,所以我们也可以使用53位来存储id。为什么要用53位?
         因为我们几乎都是跟web页面打交道,就需要跟js打交道,js支持最大的整型范围为53位,超过这个范围就会丢失精度,53之内可以直接由js读取,超过53位就需要转换成字符串才能保证js处理正确。53存储的话,32位存储秒级时间戳,5位存储机器码,16位存储序列化,这样每台机器每秒可以生产65536个不重复的id。

2、缺点

       由于雪花算法严重依赖时间,所以当发生服务器时钟回拨的问题是会导致可能产生重复的id。当然几乎没有公司会修改服务器时间,修改以后会导致各种问题,公司宁愿新加一台服务器也不愿意修改服务器时间,但是不排除特殊情况。

如何解决时钟回拨的问题?可以对序列化的初始值设置步长,每次触发时钟回拨事件,则其初始步长就加1w,可以在下面代码的第85行来实现,将sequence的初始值设置为10000。

三、代码实现

64位的代码实现:

package com.yl.common;
/*** Twitter_Snowflake<br>* SnowFlake的结构如下(每部分用-分开):<br>* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 <br>* 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0<br>* 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截)* 得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69<br>* 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId<br>* 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号<br>* 加起来刚好64位,为一个Long型。<br>* SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右。*/
public class SnowflakeIdWorker {// ==============================Fields===========================================/** 开始时间截 (2020-01-01) */private final long twepoch = 1577808000000L;/** 机器id所占的位数 */private final long workerIdBits = 5L;/** 数据标识id所占的位数 */private final long datacenterIdBits = 5L;/** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */private final long maxWorkerId = -1L ^ (-1L << workerIdBits);/** 支持的最大数据标识id,结果是31 */private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);/** 序列在id中占的位数 */private final long sequenceBits = 12L;/** 机器ID向左移12位 */private final long workerIdShift = sequenceBits;/** 数据标识id向左移17位(12+5) */private final long datacenterIdShift = sequenceBits + workerIdBits;/** 时间截向左移22位(5+5+12) */private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;/** 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */private final long sequenceMask = -1L ^ (-1L << sequenceBits);/** 工作机器ID(0~31) */private long workerId;/** 数据中心ID(0~31) */private long datacenterId;/** 毫秒内序列(0~4095) */private long sequence = 0L;/** 上次生成ID的时间截 */private long lastTimestamp = -1L;//==============================Constructors=====================================/*** 构造函数* @param workerId 工作ID (0~31)* @param datacenterId 数据中心ID (0~31)*/public  SnowflakeIdWorker(long workerId, long datacenterId) {if (workerId > maxWorkerId || workerId < 0) {throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));}if (datacenterId > maxDatacenterId || datacenterId < 0) {throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));}this.workerId = workerId;this.datacenterId = datacenterId;}// ==============================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) //| (datacenterId << datacenterIdShift) //| (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();}//==============================Test=============================================/** 测试 */public static void main(String[] args) {SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0, 0);for (int i = 0; i < 100; i++) {long id = idWorker.nextId();System.out.println(id);}}
}

 


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

相关文章

什么是雪花算法,详解雪花算法原理

雪花算法(SnowFlake) 雪花算法是Twitter开源的分布式ID生成算法. 主要是由64bit的long型生成的全局ID,引入了时间戳和ID保持自增的属性. 64bit分为四个部分: 第一个部分是1bit, 这不 使用,没有意义; 第二个部分是41bit, 组成时间戳; 第三个部分是10bit, 工作机器ID,里面分为…

雪花算法原理及实现

背景 分布式高并发的环境下&#xff0c;最常见的就是每年双十一的十二点&#xff0c;大量用户同时抢购同一商品&#xff0c;毫秒级的时间下可能生成数万个订单&#xff0c;此时确保生成订单ID的唯一性变得至关重要。此外&#xff0c;在秒杀环境下&#xff0c;不仅要保障ID唯一…

雪花算法的原理和实现Java

SnowFlake 算法&#xff0c;是 Twitter 开源的分布式 id 生成算法。其核心思想就是&#xff1a;使用一个 64 bit 的 long 型的数字作为全局唯一 id。在分布式系统中的应用十分广泛&#xff0c;且ID 引入了时间戳&#xff0c;基本上保持自增的&#xff0c;后面的代码中有详细的注…

雪花算法简介

文章目录 1、简介2、雪花算法3、算法实现4、算法优缺点5、补充 1、简介 在生成随机主键的时候&#xff0c;我第一个想到的就是UUID&#xff0c;但是UUID在MySQL中作为主键生成时&#xff0c;就会出现一个问题&#xff0c;UUID生成的是乱序的。这时候&#xff0c;学习MP的过程中…

雪花算法

文章目录 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…