关于Snowflake 生成53位ID
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的更多相关文章
- SnowFlake 生成全局唯一id
public class SnowFlakeUtil { private long workerId; private long datacenterId; private long sequence ...
- 高并发分布式系统中生成全局唯一Id汇总
数据在分片时,典型的是分库分表,就有一个全局ID生成的问题.单纯的生成全局ID并不是什么难题,但是生成的ID通常要满足分片的一些要求: 1 不能有单点故障. 2 以时间为序,或者ID里包含时间 ...
- 一秒可生成500万ID的分布式自增ID算法—雪花算法 (Snowflake,Delphi 版)
概述 分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的. 有些时候我们希望能使用一种 ...
- Mybatis-Plus默认主键策略导致自动生成19位长度主键id的坑
原创/朱季谦 某天检查一位离职同事写的代码,发现其对应表虽然设置了AUTO_INCREMENT自增,但页面新增功能生成的数据主键id很诡异,长度达到了19位,且不是从1开始递增的-- 我检查了一下,发 ...
- 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
- excel中生成32位随机id
记录下如何在EXCEL中利用公式生成32位的随机id(无符号,只有数字和小写字母). ,,)),),"",DEC2HEX(RANDBETWEEN(,,)),),"&quo ...
- 动态生成16位不重复随机数、随机创建2位ID
/** 1. * 动态生成16位不重复随机数 * * @return */ public synchronized static String generate16() { StringBuffer ...
- 5位ID生成方案
最近在某微信技术群,有人问到如何生成5位唯一数字+字母字符串的算法,要保证生成的字符串唯一,且字符串内部也要唯一. 怎么样,这个需求是不是很简单,也有点特殊呢?简单是指需求简单,特殊是指,字符串长度要 ...
- 分布式ID系列(5)——Twitter的雪法算法Snowflake适合做分布式ID吗
介绍Snowflake算法 SnowFlake算法是国际大公司Twitter的采用的一种生成分布式自增id的策略,这个算法产生的分布式id是足够我们我们中小公司在日常里面的使用了.我也是比较推荐这一种 ...
随机推荐
- KMP(超详细复杂度分析)
从 stackoverflow中找到了一个时间复杂度分析很棒的链接 https://www.inf.hs-flensburg.de/lang/algorithmen/pattern/kmpen.htm ...
- Mybatis系列全解(八):Mybatis的9大动态SQL标签你知道几个?提前致女神!
封面:洛小汐 作者:潘潘 2021年,仰望天空,脚踏实地. 这算是春节后首篇 Mybatis 文了~ 跨了个年感觉写了有半个世纪 ... 借着女神节 ヾ(◍°∇°◍)ノ゙ 提前祝男神女神们越靓越富越嗨 ...
- 开发过程中遇到的js知识点总结,面试题等,持续更新
1.Object.freeze() 方法用于冻结一个对象,即将对象设置为不可扩展.将对象的所有自有的属性和方法(包括Symbol值的属性和方法)配置为不可配置,不可写. Object.freeze( ...
- (十三)数据库查询处理之QueryExecution(2)
(十三)数据库查询处理之QueryExecution(2) 实验室这一周真的忙爆(虽然都是各种打杂的活)所以拖了很久终于在周末(摸鱼)把实验3做完了.同时准备把和查询这一块有关的博客补一下.然后就进入 ...
- 在C++中实现aligned_malloc
malloc的默认行为 大家都知道C++中可以直接调用malloc请求内存被返回分配成功的内存指针,该指针指向的地址就是分配得到的内存的起始地址.比如下面的代码 int main() { void * ...
- 关于主机不能访问虚拟机的web服务解决
centos7默认并没有开启80端口,我们只有开启就行 [root@localhost sysconfig]# firewall-cmd --permanent --add-port=3032/tcp ...
- WPF 基础 - Binding 对数据的转换和校验
1. Binding 对数据的转换和校验 Binding 中,有检验和转换关卡. 1.1 数据校验 源码: namespace System.Windows.Data { public class B ...
- arcgis for js 4.6加载本地发布好的2维地图
我本地发布好的地图服务信息如下图所示: 我们在代码中使用到的url是图中所示的REST URL 加载代码如下: <!DOCTYPE html> <html> <head& ...
- 解决unbutu网络编程socket_tcp连接不上网络助手
unbutu开放指定端口 开放端口8080 sudo iptables -I INPUT -p tcp --dport 8080 -j ACCEPT 保存设置 iptables-save 在终端中输入 ...
- ASP.NET Core与Redis搭建一个简易分布式缓存
本文主要介绍了缓存的概念,以及如何在服务器内存中存储内容.今天的目标是利用IDistributedCache来做一些分布式缓存,这样我们就可以横向扩展我们的web应用程序. 在本教程中,我将使用Re ...