组成结构


  雪花算法生成的ID是纯数字且具有时间顺序的。其原始版本是scala版,后面出现了许多其他语言的版本如Java、C++等。

  1. 1bit位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0。

  2. 41bit-时间戳,用来记录时间戳,毫秒级。

  • 41位可以表示个数字,
  • 如果只用来表示正整数(计算机中正数包含0),可以表示的数值范围是:0 至 ,减1是因为可表示的数值范围是从0开始算的,而不是1。
  • 也就是说41位可以表示个毫秒的值,转化成单位年则是年

3.10bit-数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId。

  • 可以部署在个节点,包括5位datacenterId和5位workerId
  • 5位(bit)可以表示的最大正整数是,即可以用0、1、2、3、…31这32个数字,来表示不同的datecenterId或workerId

4.12bit-序列号,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号

  • 加起来刚好64位,为一个Long型。

由于在Java中64bit的整数是long类型,所以在Java中SnowFlake算法生成的id就是long来存储的。

算法分析

  • 优点
      SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右
  • 缺点
      雪花算法在单机系统上ID是递增的,但是在分布式系统多节点的情况下,所有节点的时钟并不能保证不完全同步,所以有可能会出现不是全局递增的情况。

算法实现

package com.hsource.doctorcenter.conf.dataSource.aspect;
import java.util.HashSet;
import java.util.Set;
/**** Twitter_Snowflake<br>* SnowFlake的结构如下(每部分用-分开):<br>* <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左右。* @author yangYang* @version 1.0* @date 2020/9/24 16:25* @describe 主键雪花算法*/
public class SnowflakeIdWorker {// ==============================Fields===========================================/** 开始时间截 (2015-01-01) */private final long twepoch = 1489111610226L;/** 机器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("workerId can't be greater than %d or less than 0", maxWorkerId));}if (dataCenterId > maxDataCenterId || dataCenterId < 0) {throw new IllegalArgumentException(String.format("dataCenterId 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) {Set<Long> set = new HashSet<>();System.out.println(System.currentTimeMillis());SnowflakeIdWorker idWorker = new SnowflakeIdWorker(1, 1);long startTime = System.nanoTime();for (int i = 0; i < 1000000; i++) {long id = idWorker.nextId();set.add(id);System.out.println(id);}System.out.println((System.nanoTime()-startTime)/1000000+"ms");System.out.println(set.size());}
}

SnowflakeId - 雪花算法相关推荐

  1. java怎样生成32位全是整形的主键_你肯定会需要的分布式Id生成算法雪花算法(Java)...

    最近公司正好在做数据库迁移从oracle到mysql,因为之前oracle主键是使用的 SYS_GUID() 这个oracle提供的函数来生成全球唯一的标识符(原始值)由16个字节组成. 不过由于my ...

  2. [分布式] ------ 全局唯一id生成之雪花算法(Twitter_Snowflake)

    雪花算法(Twitter_Snowflake) 我们知道,分布式全局唯一id的生成,一般是以下几种: 基于雪花算法生成 基于数据库 基于redis 基于zookeeper 本文说下雪花算法,后面附源码 ...

  3. 分布式自增ID算法---雪花算法 (snowflake,Java版)---算法001

    一般情况,实现全局唯一ID,有三种方案,分别是通过中间件方式.UUID.雪花算法. 方案一,通过中间件方式,可以是把数据库或者redis缓存作为媒介,从中间件获取ID.这种呢,优点是可以体现全局的递增 ...

  4. 雪花算法id长度_【Java】分布式自增ID算法雪花算法 (snowflake,Java版)

    作者:H__D 转载自: https://www.cnblogs.com/h--d/p/11342741.html 一般情况,实现全局唯一ID,有三种方案,分别是通过中间件方式.UUID.雪花算法. ...

  5. php绘制雪花墙,基于雪花算法的 PHP ID 生成器

    Snowflake 是 Twitter 内部的一个 ID 生算法,可以通过一些简单的规则保证在大规模分布式情况下生成唯一的 ID 号码. 其组成为: 第一个 bit 为未使用的符号位. 第二部分由 4 ...

  6. java如何用雪花算法批量生成唯一编码(保证位数不过长)?

    最近有点忙,现在稍微闲一些,就想写写最近遇到的一些业务. 业务:一些商户.市场.档口等主体需要有唯一编码. 思路:一些前缀+雪花算法,此时位数过多,再转成六十四进制缩短位数即可.同时为了实现批量生成唯 ...

  7. 关于雪花算法id冲突的思考解决思路

    1.背景: 公司的分布式应用部署了多个pod,  利用雪花算法来生成id, 然后用来保存数据, 但是生产上跑久了之后,偶尔间就会出现id碰撞的事情, 出现的概率非常小,但是一出现就会导致该笔业务处理失 ...

  8. 分布式--雪花算法--使用/原理/实例

    原文网址:分布式--雪花算法--使用/原理/实例_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍分布式中的雪花算法.包括:用法.原理. 雪花算法用于生成全局的唯一ID. 使用时的注意事项 需要 ...

  9. 雪花算法及分布式主键生成策略详解

    目前雪花算法常应用于分布式环境下作为分布式主键的首选,本文详细介绍下雪花算法及相关分布式主键的生成策略. 如下内容已本文PPT讲解内容为基础. 本次内容共包括4部分:分布式主键生成策略,雪花算法详解, ...

最新文章

  1. android OkHttp form 上传图片和参数
  2. 数据结构与算法笔记(七)—— 选择排序
  3. Dataset之UT Zappos50K:UT Zappos50K数据集的简介、安装、使用方法之详细攻略
  4. gitblit如何迁移入gitlab合并迁移_github仓库迁移到gitlab以及gitlab仓库迁移到另一个gitlab服务器...
  5. 嵌入式linux实时化技术,嵌入式Linux实时化技术
  6. C++简介源码讲解精辟版,C++入门级C++学习,C++与C的区别值得知晓
  7. 读书印记 - 《沟通的艺术:一本手把手教你社交沟通的书》
  8. Vue路由传参及传参后刷新导致参数消失处理
  9. 错误笔记:在OleDb执行下Access ,程序不报错,但是Update也更新不成功的
  10. 使用Project客户端和Project Server进行项目管理 - android开发实例 - 博客园
  11. javascript单例模式【转载】
  12. 百度智能化测试技术及项目交付
  13. 给菜鸟看的Android应用开发全流程
  14. 如何使用Python查找文本文件的Zipf分布
  15. macOS录制系统声音及麦克风的三种方法
  16. 百度地图API:自定义途经点路线拼接
  17. 微信小游戏制作坦克大战(一)微信小游戏制作工具介绍
  18. Mockplus 3.2前瞻,五大特色功能让你惊喜!
  19. Android使用MediaRecorder的stop方法报stop failed错误的解决方案
  20. 几种典型的反病毒技术:特征码技术、覆盖法技术等

热门文章

  1. English_00000
  2. 《上帝掷骰子吗》《时间的形状:相对论史话》读后感
  3. IBM 笔记本键盘帽安装手记
  4. Dahua Lin是香港中文大学汤晓鸥教授的高徒,在计算机视觉/机器学习方面有很深的造诣。他在自己的主页上有一个推荐书表,值得大家作为参考。 全英文版的,感觉到与国际接轨的压力了!!!
  5. 自定义整型转字符串函数
  6. 安装MPlayer播放器(号称Linux中的万能播放器)
  7. Scanner 用法
  8. linux/Centos 安装GTX-1080Ti 显卡 配置显卡驱动 cuda cudnn
  9. 《啊哈算法》学习五 解救小哈
  10. Ubutun18.04安装gtx1080ti显卡驱动