1, bug现象: 没有经过处理的Snowflake 生成的是64位bit的唯一ID,但由于多数时候我们前台用到js,但是js只支持53位bit的数值。这样就导致了传到前台的64位的丢失精度。

解决思路:修改SnowFlake 的算法,使它生成 53bit的唯一ID,就可以了,代码如下

  1. package com.wisdombud.product.configure.snowflake;
  2.  
  3. import java.net.InetAddress;
  4. import java.net.UnknownHostException;
  5. import java.time.LocalDate;
  6. import java.time.ZoneId;
  7. import java.util.regex.Matcher;
  8. import java.util.regex.Pattern;
  9.  
  10. public class SnowflakeIdWorker {
  11.  
  12. private static final Pattern PATTERN_LONG_ID = Pattern.compile("^([0-9]{15})([0-9a-f]{32})([0-9a-f]{3})$");
  13.  
  14. private static final Pattern PATTERN_HOSTNAME = Pattern.compile("^.*\\D+([0-9]+)$");
  15.  
  16. private static final long OFFSET = LocalDate.of(2000, 1, 1).atStartOfDay(ZoneId.of("Z")).toEpochSecond();
  17.  
  18. private static final long MAX_NEXT = 0b11111_11111111_111L;
  19.  
  20. private static final long SHARD_ID = getServerIdAsLong();
  21.  
  22. private static long offset = 0;
  23.  
  24. private static long lastEpoch = 0;
  25.  
  26. public static long getNextId() {
  27. return nextId(System.currentTimeMillis() / 1000);
  28. }
  29.  
  30. private static synchronized long nextId(long epochSecond) {
  31. if (epochSecond < lastEpoch) {
  32. epochSecond = lastEpoch;
  33. }
  34. if (lastEpoch != epochSecond) {
  35. lastEpoch = epochSecond;
  36. reset();
  37. }
  38. offset++;
  39. long next = offset & MAX_NEXT;
  40. if (next == 0) {
  41. return nextId(epochSecond + 1);
  42. }
  43. return generateId(epochSecond, next, SHARD_ID);
  44. }
  45.  
  46. private static void reset() {
  47. offset = 0;
  48. }
  49.  
  50. private static long generateId(long epochSecond, long next, long shardId) {
  51. return ((epochSecond - OFFSET) << 21) | (next << 5) | shardId;
  52. }
  53.  
  54. private static long getServerIdAsLong() {
  55. try {
  56. String hostname = InetAddress.getLocalHost().getHostName();
  57. Matcher matcher = PATTERN_HOSTNAME.matcher(hostname);
  58. if (matcher.matches()) {
  59. long n = Long.parseLong(matcher.group(1));
  60. if (n >= 0 && n < 8) {
  61. return n;
  62. }
  63. }
  64. } catch (UnknownHostException e) {
  65.  
  66. }
  67. return 0;
  68. }
  69. }

参考自: https://my.oschina.net/u/2552286/blog/3115621/print

64位的Snowflake 的算法

  1. package com.wisdombud.product.configure.snowflake;
  2.  
  3. public class SnowflakeIdWorker {
  4.  
  5. private final long twepoch = 1420041600000L;
  6.  
  7. private final long workerIdBits = 5L;
  8.  
  9. private final long datacenterIdBits = 5L;
  10.  
  11. private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
  12.  
  13. private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
  14.  
  15. private final long sequenceBits = 12L;
  16.  
  17. private final long workerIdShift = sequenceBits;
  18.  
  19. private final long datacenterIdShift = sequenceBits + workerIdBits;
  20.  
  21. private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
  22.  
  23. private final long sequenceMask = -1L ^ (-1L << sequenceBits);
  24.  
  25. private Long workerId = 2L;
  26.  
  27. private Long datacenterId = 1L;
  28.  
  29. private long sequence = 0L;
  30.  
  31. private long lastTimestamp = -1L;
  32.  
  33. public SnowflakeIdWorker() {
  34.  
  35. }
  36.  
  37. public synchronized long nextId() {
  38. long timestamp = timeGen();
  39.  
  40. if (timestamp < lastTimestamp) {
  41. throw new RuntimeException(String
  42. .format("Clock moved backwards. Refusing to generate id for %d milliseconds",
  43. lastTimestamp - timestamp));
  44. }
  45.  
  46. if (lastTimestamp == timestamp) {
  47. sequence = (sequence + 1) & sequenceMask;
  48.  
  49. if (sequence == 0) {
  50.  
  51. timestamp = tilNextMillis(lastTimestamp);
  52. }
  53. }
  54.  
  55. else {
  56. sequence = 0L;
  57. }
  58.  
  59. lastTimestamp = timestamp;
  60.  
  61. return ((timestamp - twepoch) << timestampLeftShift) //
  62. | (datacenterId << datacenterIdShift) //
  63. | (workerId << workerIdShift) //
  64. | sequence;
  65. }
  66.  
  67. protected long tilNextMillis(long lastTimestamp) {
  68. long timestamp = timeGen();
  69. while (timestamp <= lastTimestamp) {
  70. timestamp = timeGen();
  71. }
  72. return timestamp;
  73. }
  74.  
  75. protected long timeGen() {
  76. return System.currentTimeMillis();
  77. }
  78.  
  79. public enum SnowflakeInstance {
  80. INSTANCE();
  81.  
  82. private SnowflakeIdWorker singleton;
  83.  
  84. SnowflakeInstance() {
  85. singleton = new SnowflakeIdWorker();
  86. }
  87.  
  88. public SnowflakeIdWorker getInstance() {
  89. return singleton;
  90. }
  91. }
  92.  
  93. public static Long getNextId() {
  94. return SnowflakeInstance.INSTANCE.getInstance().nextId();
  95. }
  96. }

关于Snowflake 生成53位ID的更多相关文章

  1. SnowFlake 生成全局唯一id

    public class SnowFlakeUtil { private long workerId; private long datacenterId; private long sequence ...

  2. 高并发分布式系统中生成全局唯一Id汇总

    数据在分片时,典型的是分库分表,就有一个全局ID生成的问题.单纯的生成全局ID并不是什么难题,但是生成的ID通常要满足分片的一些要求:   1 不能有单点故障.   2 以时间为序,或者ID里包含时间 ...

  3. 一秒可生成500万ID的分布式自增ID算法—雪花算法 (Snowflake,Delphi 版)

    概述 分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的. 有些时候我们希望能使用一种 ...

  4. Mybatis-Plus默认主键策略导致自动生成19位长度主键id的坑

    原创/朱季谦 某天检查一位离职同事写的代码,发现其对应表虽然设置了AUTO_INCREMENT自增,但页面新增功能生成的数据主键id很诡异,长度达到了19位,且不是从1开始递增的-- 我检查了一下,发 ...

  5. java 生成20位唯一ID,生成不会重复的20位数字----https://blog.csdn.net/weixin_36751895/article/details/70331781

    java 生成20位唯一ID,生成不会重复的20位数字----https://blog.csdn.net/weixin_36751895/article/details/70331781

  6. excel中生成32位随机id

    记录下如何在EXCEL中利用公式生成32位的随机id(无符号,只有数字和小写字母). ,,)),),"",DEC2HEX(RANDBETWEEN(,,)),),"&quo ...

  7. 动态生成16位不重复随机数、随机创建2位ID

    /** 1. * 动态生成16位不重复随机数 * * @return */ public synchronized static String generate16() { StringBuffer ...

  8. 5位ID生成方案

    最近在某微信技术群,有人问到如何生成5位唯一数字+字母字符串的算法,要保证生成的字符串唯一,且字符串内部也要唯一. 怎么样,这个需求是不是很简单,也有点特殊呢?简单是指需求简单,特殊是指,字符串长度要 ...

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

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

随机推荐

  1. 区分函数防抖&函数节流

    1. 概念区分 函数防抖:触发事件后,在n秒内函数只能执行一次,如果触发事件后在n秒内又触发了事件,则会重新计算函数延执行时间. 简单说: 频繁触发, 但只在特定的时间内才执行一次代码,如果特定时间内 ...

  2. 微信小程序弹出层

    1.消息提示     wx.showToast wx.showToast({ title: '成功', icon: 'success', duration: 2000 })2.模态弹窗 wx.show ...

  3. POJ-3281(最大流+EK算法)

    Dining POJ-3281 这道题目其实也是网络流中求解最大流的一道模板题. 只要建模出来以后直接套用模板就行了.这里的建模还需要考虑题目的要求:一种食物只能给一只牛. 所以这里可以将牛拆成两个点 ...

  4. MySql数据库列表数据分页查询、全文检索API零代码实现

    数据条件查询和分页 前面文档主要介绍了元数据配置,包括表单定义和表关系管理,以及表单数据的录入,本文主要介绍数据查询和分页在crudapi中的实现. 概要 数据查询API 数据查询主要是指按照输入条件 ...

  5. 漏洞复现-CVE-2014-3120-ElasticSearch 命令执行漏洞

        0x00 实验环境 攻击机:Win 10 靶机也可作为攻击机:Ubuntu18 (docker搭建的vulhub靶场) 0x01 影响版本 < ElasticSearch 1.2的版本 ...

  6. httpPost的两种方式

    1,post-Body流和post参数,以下客户端代码和服务端代码可共用 客户端代码 /** * post 方法 * 抛送给EDI * @param url http://127.0.0.1:9003 ...

  7. Python爬虫学习三------requests+BeautifulSoup爬取简单网页

    第一次第一次用MarkDown来写博客,先试试效果吧! 昨天2018俄罗斯世界杯拉开了大幕,作为一个伪球迷,当然也得为世界杯做出一点贡献啦. 于是今天就编写了一个爬虫程序将腾讯新闻下世界杯专题的相关新 ...

  8. 在 .NET 中使用 Flurl 高效处理Http请求

    简介 官方介绍,Flurl是一个现代的,流利的,支持异步的,可测试的,可移植的,URL增强和Http客户端组件. Url构建 现在有一个登录的接口,地址如下: https://www.some-api ...

  9. vue 折线柱状图

    需求:折线柱状图实现,显示不同提示,颜色,标记等等. 图例: 实现: <template> <div class="transaction-barline"> ...

  10. UI透明欺诈

    判断是否存在的代码:   private static boolean c(Activity paramActivity)   {     List localList = ((ActivityMan ...