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

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

package com.wisdombud.product.configure.snowflake;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.regex.Matcher;
import java.util.regex.Pattern; public class SnowflakeIdWorker { private static final Pattern PATTERN_LONG_ID = Pattern.compile("^([0-9]{15})([0-9a-f]{32})([0-9a-f]{3})$"); private static final Pattern PATTERN_HOSTNAME = Pattern.compile("^.*\\D+([0-9]+)$"); private static final long OFFSET = LocalDate.of(2000, 1, 1).atStartOfDay(ZoneId.of("Z")).toEpochSecond(); private static final long MAX_NEXT = 0b11111_11111111_111L; private static final long SHARD_ID = getServerIdAsLong(); private static long offset = 0; private static long lastEpoch = 0; public static long getNextId() {
return nextId(System.currentTimeMillis() / 1000);
} private static synchronized long nextId(long epochSecond) {
if (epochSecond < lastEpoch) {
epochSecond = lastEpoch;
}
if (lastEpoch != epochSecond) {
lastEpoch = epochSecond;
reset();
}
offset++;
long next = offset & MAX_NEXT;
if (next == 0) {
return nextId(epochSecond + 1);
}
return generateId(epochSecond, next, SHARD_ID);
} private static void reset() {
offset = 0;
} private static long generateId(long epochSecond, long next, long shardId) {
return ((epochSecond - OFFSET) << 21) | (next << 5) | shardId;
} private static long getServerIdAsLong() {
try {
String hostname = InetAddress.getLocalHost().getHostName();
Matcher matcher = PATTERN_HOSTNAME.matcher(hostname);
if (matcher.matches()) {
long n = Long.parseLong(matcher.group(1));
if (n >= 0 && n < 8) {
return n;
}
}
} catch (UnknownHostException e) { }
return 0;
}
}

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

64位的Snowflake 的算法

package com.wisdombud.product.configure.snowflake;

public class SnowflakeIdWorker {

    private final long twepoch            = 1420041600000L;

    private final long workerIdBits       = 5L;

    private final long datacenterIdBits   = 5L;

    private final long maxWorkerId        = -1L ^ (-1L << workerIdBits);

    private final long maxDatacenterId    = -1L ^ (-1L << datacenterIdBits);

    private final long sequenceBits       = 12L;

    private final long workerIdShift      = sequenceBits;

    private final long datacenterIdShift  = sequenceBits + workerIdBits;

    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

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

    private Long       workerId           = 2L;

    private Long       datacenterId       = 1L;

    private long       sequence           = 0L;

    private long       lastTimestamp      = -1L;

    public SnowflakeIdWorker() {

    }

    public synchronized long nextId() {
long timestamp = timeGen(); 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;
} lastTimestamp = timestamp; return ((timestamp - twepoch) << timestampLeftShift) //
| (datacenterId << datacenterIdShift) //
| (workerId << workerIdShift) //
| sequence;
} protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
} protected long timeGen() {
return System.currentTimeMillis();
} public enum SnowflakeInstance {
INSTANCE(); private SnowflakeIdWorker singleton; SnowflakeInstance() {
singleton = new SnowflakeIdWorker();
} public SnowflakeIdWorker getInstance() {
return singleton;
}
} public static Long getNextId() {
return SnowflakeInstance.INSTANCE.getInstance().nextId();
}
}

关于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. 后端程序员之路 18、朴素贝叶斯模型(Naive Bayesian Model,NBM)

    贝叶斯推断及其互联网应用(一):定理简介 - 阮一峰的网络日志http://www.ruanyifeng.com/blog/2011/08/bayesian_inference_part_one.ht ...

  2. 12张图打开JMeter体系结构全局视角

    JMeter是Java技术栈工具,在软件测试领域应用非常广泛,无论是性能测试还是接口测试,技术都很成熟和稳定.它有一个突出特点:开源,适合做二次开发,以阿里为代表的Java技术栈公司都对它青睐有加.在 ...

  3. Jacobi与SOR迭代法的实现与性能比较及均匀间距与Chebyshev插值的实现、性能分析及二者生成的插值误差比较

    这篇文章给出(1)Jacobi与SOR迭代法的实现与性能比较及(2)均匀间距与Chebyshev插值的实现.性能分析及二者生成的插值误差比较,给出完整的实现代码,没有进行性能优化,仅供参考. (1)J ...

  4. 【小菜学网络】MTU

    不同的以太网接入设备,一帧能传输的数据量是有差异的. 普通的以太网卡,一帧最多能够传输 1500 字节的数据:而某些虚拟设备,传输能力要打些折扣.此外,链路层除了以太网还有其他协议,这些协议中数据帧传 ...

  5. POJ-3436(网络流+最大流+输出路径)

    ACM Computer Factory POJ-3436 题目就是一个工厂n个加工机器,每个机器有一个效率w,q个材料入口,q个材料出口,每个口有三个数表示状态,1表示一定有入/出的材料,0表示没有 ...

  6. python flask框架详解

    Flask是一个Python编写的Web 微框架,让我们可以使用Python语言快速实现一个网站或Web服务.本文参考自Flask官方文档, 英文不好的同学也可以参考中文文档 1.安装flask pi ...

  7. python基础学习之函数基础和部分内置函数

    在函数调用的时候,必备参数必须要传入 函数定义: def  函数名: 代码块pass return  返回值 函数名命名规则: 字母.数字和下划线组成,和变量命名规则一致 pass在这里表示什么都没有 ...

  8. POJ_2828 Buy Tickets 【线段树】

    一.题目 Buy Tickets 二.分析 首先可以明确的是每个人的位置都是定的,那么如果从输入数据从后往前看,最后面的人进来的时候,他前面的人数肯定是定的. 那么可以考虑,当从后往前推时,这个人插入 ...

  9. Python模拟简易版淘宝客服机器人

    对于用Python制作一个简易版的淘宝客服机器人,大概思路是:首先从数据库中用sql语句获取相关数据信息并将其封装成函数,然后定义机器问答的主体函数,对于问题的识别可以利用正则表达式来进行分析,结合现 ...

  10. 叫练手把手教你读JVM之GC信息

    案例 众所周知,GC主要回收的是堆内存,堆内存中包含年轻代和老年代,年轻代分为Eden和Surivor,如下图所示.我们用案例分析下堆的GC信息[版本:HotSpot JDK1.8]. /** * @ ...