雪花算法是twitter开源的一个算法。

由64位0或1组成,其中41位是时间戳,10位工作机器id,12位序列号,该类通过方法nextID()实现id的生成,用Long数据类型去存储。

我们使用idworker不建议每次都通过new的方式使用,如果在Spring中,可以通过如下方式将该bean注入到Spring容器中

  1. <bean id="idWorker" class="utils.IdWorker">
  2. <!-- 工作机器ID:值范围是0-31 数据中心ID:值范围是0-31,两个参数可以不写 -->
  3. <constructor-arg index="0" value="0"></constructor-arg>
  4. <constructor-arg index="1" value="0"></constructor-arg>
  5. </bean>

工具类IdWorker 的完整代码如下

  1. import java.lang.management.ManagementFactory;
  2. import java.net.InetAddress;
  3. import java.net.NetworkInterface;
  4.  
  5. /**
  6. * <p>名称:IdWorker.java</p>
  7. * <p>描述:分布式自增长ID</p>
  8. * <pre>
  9. * Twitter的 Snowflake JAVA实现方案
  10. * </pre>
  11. * 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:
  12. * 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
  13. * 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,
  14. * 然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),
  15. * 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
  16. * 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),
  17. * 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
  18. * <p>
  19. * 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))
  20. *
  21. * @author Polim
  22. */
  23. public class IdWorker {
  24. // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
  25. private final static long twepoch = 1288834974657L;
  26. // 机器标识位数
  27. private final static long workerIdBits = 5L;
  28. // 数据中心标识位数
  29. private final static long datacenterIdBits = 5L;
  30. // 机器ID最大值
  31. private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
  32. // 数据中心ID最大值
  33. private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
  34. // 毫秒内自增位
  35. private final static long sequenceBits = 12L;
  36. // 机器ID偏左移12位
  37. private final static long workerIdShift = sequenceBits;
  38. // 数据中心ID左移17位
  39. private final static long datacenterIdShift = sequenceBits + workerIdBits;
  40. // 时间毫秒左移22位
  41. private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
  42.  
  43. private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
  44. /* 上次生产id时间戳 */
  45. private static long lastTimestamp = -1L;
  46. // 0,并发控制
  47. private long sequence = 0L;
  48.  
  49. private final long workerId;
  50. // 数据标识id部分
  51. private final long datacenterId;
  52.  
  53. public IdWorker(){
  54. this.datacenterId = getDatacenterId(maxDatacenterId);
  55. this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
  56. }
  57. /**
  58. * @param workerId
  59. * 工作机器ID
  60. * @param datacenterId
  61. * 序列号
  62. */
  63. public IdWorker(long workerId, long datacenterId) {
  64. if (workerId > maxWorkerId || workerId < 0) {
  65. throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
  66. }
  67. if (datacenterId > maxDatacenterId || datacenterId < 0) {
  68. throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
  69. }
  70. this.workerId = workerId;
  71. this.datacenterId = datacenterId;
  72. }
  73. /**
  74. * 获取下一个ID
  75. *
  76. * @return
  77. */
  78. public synchronized long nextId() {
  79. long timestamp = timeGen();
  80. if (timestamp < lastTimestamp) {
  81. throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
  82. }
  83.  
  84. if (lastTimestamp == timestamp) {
  85. // 当前毫秒内,则+1
  86. sequence = (sequence + 1) & sequenceMask;
  87. if (sequence == 0) {
  88. // 当前毫秒内计数满了,则等待下一秒
  89. timestamp = tilNextMillis(lastTimestamp);
  90. }
  91. } else {
  92. sequence = 0L;
  93. }
  94. lastTimestamp = timestamp;
  95. // ID偏移组合生成最终的ID,并返回ID
  96. long nextId = ((timestamp - twepoch) << timestampLeftShift)
  97. | (datacenterId << datacenterIdShift)
  98. | (workerId << workerIdShift) | sequence;
  99.  
  100. return nextId;
  101. }
  102.  
  103. private long tilNextMillis(final long lastTimestamp) {
  104. long timestamp = this.timeGen();
  105. while (timestamp <= lastTimestamp) {
  106. timestamp = this.timeGen();
  107. }
  108. return timestamp;
  109. }
  110.  
  111. private long timeGen() {
  112. return System.currentTimeMillis();
  113. }
  114.  
  115. /**
  116. * <p>
  117. * 获取 maxWorkerId
  118. * </p>
  119. */
  120. protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
  121. StringBuffer mpid = new StringBuffer();
  122. mpid.append(datacenterId);
  123. String name = ManagementFactory.getRuntimeMXBean().getName();
  124. if (!name.isEmpty()) {
  125. /*
  126. * GET jvmPid
  127. */
  128. mpid.append(name.split("@")[0]);
  129. }
  130. /*
  131. * MAC + PID 的 hashcode 获取16个低位
  132. */
  133. return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
  134. }
  135.  
  136. /**
  137. * <p>
  138. * 数据标识id部分
  139. * </p>
  140. */
  141. protected static long getDatacenterId(long maxDatacenterId) {
  142. long id = 0L;
  143. try {
  144. InetAddress ip = InetAddress.getLocalHost();
  145. NetworkInterface network = NetworkInterface.getByInetAddress(ip);
  146. if (network == null) {
  147. id = 1L;
  148. } else {
  149. byte[] mac = network.getHardwareAddress();
  150. id = ((0x000000FF & (long) mac[mac.length - 1])
  151. | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
  152. id = id % (maxDatacenterId + 1);
  153. }
  154. } catch (Exception e) {
  155. System.out.println(" getDatacenterId: " + e.getMessage());
  156. }
  157. return id;
  158. }
  159.  
  160. public static void main(String[] args) {
  161. IdWorker idWorker = new IdWorker(0,1);
  162. for (int i = 0; i < 50; i++) {
  163. long nextId = idWorker.nextId();
  164. System.out.println(nextId);
  165. }
  166. }
  167. }

除了使用雪花算法之外还可以采用

redis生成唯一key值、数据库单键一张表生成id、UUID(缺点无序)

分布式id的生成方式——雪花算法的更多相关文章

  1. 分布式ID生成器 snowflake(雪花)算法

    在springboot的启动类中引入 @Bean public IdWorker idWorkker(){ return new IdWorker(1, 1); } 在代码中调用 @Autowired ...

  2. 分布式id生成器,雪花算法IdWorker

    /** * <p>名称:IdWorker.java</p> * <p>描述:分布式自增长ID</p> * <pre> * Twitter的 ...

  3. 全局唯一iD的生成 雪花算法详解及其他用法

    一.介绍 雪花算法的原始版本是scala版,用于生成分布式ID(纯数字,时间顺序),订单编号等. 自增ID:对于数据敏感场景不宜使用,且不适合于分布式场景.GUID:采用无意义字符串,数据量增大时造成 ...

  4. 分布式ID方案SnowFlake雪花算法分析

    1.算法 SnowFlake算法生成的数据组成结构如下: 在java中用long类型标识,共64位(每部分用-分开): 0 - 0000000000 0000000000 0000000000 000 ...

  5. 雪花算法【分布式ID问题】【刘新宇】

    分布式ID 1 方案选择 UUID UUID是通用唯一识别码(Universally Unique Identifier)的缩写,开放软件基金会(OSF)规范定义了包括网卡MAC地址.时间戳.名字空间 ...

  6. 使用雪花算法为分布式下全局ID、订单号等简单解决方案考虑到时钟回拨

    1.snowflake简介         互联网快速发展的今天,分布式应用系统已经见怪不怪,在分布式系统中,我们需要各种各样的ID,既然是ID那么必然是要保证全局唯一,除此之外,不同当业务还需要不同 ...

  7. 分布式ID系列(5)——Twitter的雪法算法Snowflake适合做分布式ID吗

    介绍Snowflake算法 SnowFlake算法是国际大公司Twitter的采用的一种生成分布式自增id的策略,这个算法产生的分布式id是足够我们我们中小公司在日常里面的使用了.我也是比较推荐这一种 ...

  8. 如何设计一个分布式 ID 发号器?

    大家好,我是树哥. 在复杂的分布式系统中,往往需要对大量的数据和消息进行唯一标识,例如:分库分表的 ID 主键.分布式追踪的请求 ID 等等.于是,设计「分布式 ID 发号器」就成为了一个非常常见的系 ...

  9. 雪花算法(snowflake)的JAVA实现

    snowflake算法由twitter公司出品,原始版本是scala版,用于生成分布式ID,结构图: 算法描述: 最高位是符号位,始终为0,不可用. 41位的时间序列,精确到毫秒级,41位的长度可以使 ...

随机推荐

  1. 笔记:Java Language Specification - 章节17- 线程和锁

    回答一个问题:多线程场景下,有时一个线程对shared variable的修改可能对另一个线程不可见.那么,何时一个线程对内存的修改才会对另一个线程可见呢? 基本的原则: 如果 读线程 和 写线程 不 ...

  2. Mybatis源码解析(三) —— Mapper代理类的生成

    Mybatis源码解析(三) -- Mapper代理类的生成   在本系列第一篇文章已经讲述过在Mybatis-Spring项目中,是通过 MapperFactoryBean 的 getObject( ...

  3. 【开发笔记】-通过js控制input禁止输入空格

    <input type="text" id="fname" onkeyup="myFunction(id)"> <scri ...

  4. CentOS 7 - 安装Python 3

    Enable Software Collections (SCL) Software Collections, also known as SCL is a community project tha ...

  5. .Net core 使用swagger进行Api管理

    上次我们讲过如何在swagger上隐藏接口,众所周知,swagger是一个强大的api文档工具,可以帮助我们记录文档并且测试接口,也是一个可视化操作接口的工具. 那么如果我们写的接口非常多的时候怎么办 ...

  6. ubuntu用samba来实现和虚拟机的文件共享

    1.安装samba sudo apt install -y samba sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.bak 2.创建文件夹并修改权限 ...

  7. U盘启动安装CentOS 7出现 -dracut initqueue timeout

    使用U盘启动安装CentOS7出现 Warning: dracut-initqueue timeout - starting timeout scripts 的解决办法 原因: ISO下,在/isol ...

  8. linux启动脚本

    1. linux启动脚本 :  /etc/init.d/脚本例如:/etc/init.d/iptables start init.d/ 下面的每一个文件就是一个启动脚本 2. 以上的/etc/init ...

  9. chrome开发者工具--使用 Network 面板测量您的网站网络性能。

    转自:Tools for Web Developers   Network 面板记录页面上每个网络操作的相关信息,包括详细的耗时数据.HTTP 请求与响应标头和 Cookie,等等. TL;DR 使用 ...

  10. Unity历史版本的文档

    前言 在我们的开发过程中,如果要查找Unity文档,通常会有以下两种方式: 1. 打开Unity的官网,查找文档 2. 查找本地安装的Unity文档 但是Unity官网上的文档,总是当前最新版本的文档 ...