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. KMP(超详细复杂度分析)

    从 stackoverflow中找到了一个时间复杂度分析很棒的链接 https://www.inf.hs-flensburg.de/lang/algorithmen/pattern/kmpen.htm ...

  2. Mybatis系列全解(八):Mybatis的9大动态SQL标签你知道几个?提前致女神!

    封面:洛小汐 作者:潘潘 2021年,仰望天空,脚踏实地. 这算是春节后首篇 Mybatis 文了~ 跨了个年感觉写了有半个世纪 ... 借着女神节 ヾ(◍°∇°◍)ノ゙ 提前祝男神女神们越靓越富越嗨 ...

  3. 开发过程中遇到的js知识点总结,面试题等,持续更新

     1.Object.freeze() 方法用于冻结一个对象,即将对象设置为不可扩展.将对象的所有自有的属性和方法(包括Symbol值的属性和方法)配置为不可配置,不可写. Object.freeze( ...

  4. (十三)数据库查询处理之QueryExecution(2)

    (十三)数据库查询处理之QueryExecution(2) 实验室这一周真的忙爆(虽然都是各种打杂的活)所以拖了很久终于在周末(摸鱼)把实验3做完了.同时准备把和查询这一块有关的博客补一下.然后就进入 ...

  5. 在C++中实现aligned_malloc

    malloc的默认行为 大家都知道C++中可以直接调用malloc请求内存被返回分配成功的内存指针,该指针指向的地址就是分配得到的内存的起始地址.比如下面的代码 int main() { void * ...

  6. 关于主机不能访问虚拟机的web服务解决

    centos7默认并没有开启80端口,我们只有开启就行 [root@localhost sysconfig]# firewall-cmd --permanent --add-port=3032/tcp ...

  7. WPF 基础 - Binding 对数据的转换和校验

    1. Binding 对数据的转换和校验 Binding 中,有检验和转换关卡. 1.1 数据校验 源码: namespace System.Windows.Data { public class B ...

  8. arcgis for js 4.6加载本地发布好的2维地图

    我本地发布好的地图服务信息如下图所示: 我们在代码中使用到的url是图中所示的REST URL 加载代码如下: <!DOCTYPE html> <html> <head& ...

  9. 解决unbutu网络编程socket_tcp连接不上网络助手

    unbutu开放指定端口 开放端口8080 sudo iptables -I INPUT -p tcp --dport 8080 -j ACCEPT 保存设置 iptables-save 在终端中输入 ...

  10. ASP.NET Core与Redis搭建一个简易分布式缓存

    ​本文主要介绍了缓存的概念,以及如何在服务器内存中存储内容.今天的目标是利用IDistributedCache来做一些分布式缓存,这样我们就可以横向扩展我们的web应用程序. 在本教程中,我将使用Re ...