雪花算法生成分布式ID
分布式主键ID生成方案
分布式主键ID的生成方案有以下几种:
数据库自增主键
缺点:
- 导入旧数据时,可能会ID重复,导致导入失败
- 分布式架构,多个Mysql实例可能会导致ID重复
UUID
缺点:
- 占用空间大
- UUID一般是字符串存储,查询效率低
- 没有排序,无法趋势递增
使用Redis生成ID
缺点:
- 依赖Redis高可用
雪花算法
缺点:
- 依赖服务器时间,如果时间回调,将会导致ID重复
雪花算法原理
雪花算法是 Twitter 开源的主键生成算法 snowflake
它用64位二进制表示主键,由5部分组成:
最高位:0,表示正数
41 位 :表示时间戳,毫秒为单位,最多表示 2^41 -1 毫秒,约69年
10 位 : 前5位用来表示机房ID,后5位表示服务器ID,最多表示 2^5 个机房,和 2^10 个服务器
最后12位:表示序列号,最多表示 2^12-1 = 4096,即每台服务器最多支持每毫秒4096次并发生成

雪花算法的优点:
- 生成效率非常高
- 占用空间相对较少,只用 64 位,即 Long 类型,转换成字符串长度最多19
- 生成的主键趋势递增
雪花算法Java实现
import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.Random;
public class SnowflakeIdGenerator {
/**
* 时间戳标识所占二进制位数
*/
private static final int TIME_STAMP_BIT_LEN = 41;
/**
* 机房标识所占二进制位数
*/
private static final int SERVER_ROOM_BIT_LEN = 5;
/**
* 服务器标识所占二进制位数
*/
private static final int SERVER_BIT_LEN = 5;
/**
* 每毫秒中序列所占二进制位数
*/
private static final int SEQ_BIT_LEN = 12;
/**
* 时间戳标识向左移动的位数(这里的1标识最高位)
*/
private static final int TIME_STAMP_LEFT_BIT_LEN = 64 - 1 - TIME_STAMP_BIT_LEN;
/**
* 机房标识左移位数
*/
private static final int SERVER_ROOM_LEFT_BIT_LEN = TIME_STAMP_LEFT_BIT_LEN - SERVER_ROOM_BIT_LEN;
/**
* 服务器标识左移位数
*/
private static final int SERVER_LEFT_BIT_LEN = SERVER_ROOM_LEFT_BIT_LEN - SERVER_BIT_LEN;
/**
* 开始时间戳,此处为 2022年4月9日
*/
private static final long START_TIME_STAMP = 1649497879948L;
/**
* 上次生成ID的时间戳
*/
private static long LAST_TIME_STAMP = -1L;
/**
* 上一次毫秒内存序列值
*/
private static long LAST_SEQ = 0L;
/**
* 获取机房标识(可以手动定义0-31之间的数)
*/
private static final long SERVER_ROOM_ID = getServerRoomId();
/**
* 获取服务器标识(可以手动定义0-31之间的数)
*/
private static final long SERVER_ID = getServerId();
/**
* 机房标识最大值 +1
*/
private static final int SERVER_ROOM_MAX_NUM_1 = ~(-1 << SERVER_ROOM_BIT_LEN) + 1;
/**
* 服务器标识最大值 +1
*/
private static final int SERVER_MAX_NUM_1 = ~(-1 << SERVER_BIT_LEN) + 1;
/**
* 毫秒内存列的最大值
*/
private static final long SEQ_MAX_NUM = ~(-1 << SEQ_BIT_LEN);
/**
* 对服务器地址的哈希码取余作为服务器标识
* TODO 根据实际环境修改该方法,该方法不能应用于开发环境,此处仅作为例子
*
* @return 服务器标识
*/
private static int getServerId() {
try {
String hostAddress = Inet4Address.getLocalHost().getHostAddress();
return (hostAddress.hashCode() & Integer.MAX_VALUE ) % SERVER_MAX_NUM_1;
} catch (UnknownHostException e) {
return new Random().nextInt(SERVER_MAX_NUM_1);
}
}
/**
* 对服务器名称的哈希码取余作为机房标识
* TODO 根据实际环境修改该方法,该方法不能应用于开发环境,此处仅作为例子
*
* @return 机房标识
*/
private static int getServerRoomId() {
try {
String hostName = Inet4Address.getLocalHost().getHostName();
return (hostName.hashCode() & Integer.MAX_VALUE) % SERVER_ROOM_MAX_NUM_1;
} catch (Exception e) {
return new Random().nextInt(SERVER_ROOM_MAX_NUM_1);
}
}
/**
* 一直循环直到获取到下毫秒的时间戳
*
* @param lastMillis
* @return 下一毫秒的时间戳
*/
private static long nextMillis(long lastMillis) {
long now = System.currentTimeMillis();
while (now <= lastMillis) {
now = System.currentTimeMillis();
}
return now;
}
/**
* 生成唯一ID
* 须加锁避免并发问题
*
* @return 返回唯一ID
*/
public synchronized static long generateUniqueId() {
long currentTimeStamp = System.currentTimeMillis();
// 如果当前时间小于上一次ID生成的时间戳,说明系统时间回退过,此时因抛出异常
if (currentTimeStamp < LAST_TIME_STAMP) {
throw new RuntimeException(String.format("系统时间错误! %d 毫秒内拒绝生成雪花ID", START_TIME_STAMP));
}
if (currentTimeStamp == LAST_TIME_STAMP) {
LAST_SEQ = (LAST_SEQ + 1) & SEQ_MAX_NUM;
if (LAST_SEQ == 0) {
currentTimeStamp = nextMillis(LAST_TIME_STAMP);
}
} else {
LAST_SEQ = 0;
}
// 上次生成ID的时间戳
LAST_TIME_STAMP = currentTimeStamp;
return ((currentTimeStamp - START_TIME_STAMP) << TIME_STAMP_LEFT_BIT_LEN | (SERVER_ROOM_ID << SERVER_ROOM_LEFT_BIT_LEN) | (SERVER_ID << SERVER_LEFT_BIT_LEN) | LAST_SEQ);
}
/**
* 主函数测试
*
* @param args
*/
public static void main(String[] args) {
long start = System.currentTimeMillis();
int num = 100;
for (int i = 0; i < num; i++) {
System.out.println(generateUniqueId());
}
long end = System.currentTimeMillis();
System.out.println("共生成 " + num + " 个ID,用时 " + (end - start) + " 毫秒");
}
}
雪花算法生成分布式ID的更多相关文章
- 基于雪花算法生成分布式ID(Java版)
SnowFlake算法原理介绍 在分布式系统中会将一个业务的系统部署到多台服务器上,用户随机访问其中一台,而之所以引入分布式系统就是为了让整个系统能够承载更大的访问量.诸如订单号这些我们需要它是全局唯 ...
- 雪花算法【分布式ID问题】【刘新宇】
分布式ID 1 方案选择 UUID UUID是通用唯一识别码(Universally Unique Identifier)的缩写,开放软件基金会(OSF)规范定义了包括网卡MAC地址.时间戳.名字空间 ...
- redis生成分布式id方案
分布式Id - redis方式 本篇分享内容是关于生成分布式Id的其中之一方案,除了redis方案之外还有如:数据库,雪花算法,mogodb(object_id也是数据库)等方案,对于redis来 ...
- 根据twitter的snowflake算法生成唯一ID
C#版本 /// <summary> /// 根据twitter的snowflake算法生成唯一ID /// snowflake算法 64 位 /// 0---0000000000 000 ...
- C# 根据twitter的snowflake算法生成唯一ID
C# 版算法: using System; using System.Collections.Generic; using System.Linq; using System.Text; using ...
- 雪花算法生成ID
前言我们的数据库在设计时一般有两个ID,自增的id为主键,还有一个业务ID使用UUID生成.自增id在需要分表的情况下做为业务主键不太理想,所以我们增加了uuid作为业务ID,有了业务id仍然还存在自 ...
- 使用雪花算法为分布式下全局ID、订单号等简单解决方案考虑到时钟回拨
1.snowflake简介 互联网快速发展的今天,分布式应用系统已经见怪不怪,在分布式系统中,我们需要各种各样的ID,既然是ID那么必然是要保证全局唯一,除此之外,不同当业务还需要不同 ...
- 分布式系统为什么不用自增id,要用雪花算法生成id???
1.为什么数据库id自增和uuid不适合分布式id id自增:当数据量庞大时,在数据库分库分表后,数据库自增id不能满足唯一id来标识数据:因为每个表都按自己节奏自增,会造成id冲突,无法满足需求. ...
- PHP使用SnowFlake算法生成唯一ID
前言:最近需要做一套CMS系统,由于功能比较单一,而且要求灵活,所以放弃了WP这样的成熟系统,自己做一套相对简单一点的.文章的详情页URL想要做成url伪静态的格式即xxx.html 其中xxx考虑过 ...
随机推荐
- c#的委托实例
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- Kruscal algorithm
#include <iostream> #include <algorithm> using namespace std; #define MAX 5 #define INF ...
- HTTPS-各种加密方式
推荐阅读:https://www.cnblogs.com/zwtblog/tag/计算机网络/ 目录 HTTPS 对称加密(AES) 非对称加密(RSA) 工作过程 分析 优缺点 常用算法 混合加密 ...
- Java Byte不能用equals
- Spring的自动装配?
在spring中,对象无需自己查找或创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋予各个对象,使用autowire来配置自动装载模式. 在Spring框架xml配置中共有5种自动装配: ...
- mybatis-01-基本流程
mybatis执行流程 1. 加载配置文件并初始化(SqlSession) 配置文件来源于两个地方,一个是配置文件(主配置文件conf.xml,mapper文件*.xml), 一个是java代码中 ...
- 乱序数组中第k大的数(顺序统计量)
该问题是顺序统计量中十分经典的问题. 使用快排中的分区法,将第k大的数排序.若双向扫描分区加上三点中值法或绝对中值法,可以保证在 O(n) 时间里找出第k大的数. 补充:可以直接使用C++STL中的n ...
- 决策树3:基尼指数--Gini index(CART)
既能做分类,又能做回归.分类:基尼值作为节点分类依据.回归:最小方差作为节点的依据. 节点越不纯,基尼值越大,熵值越大 pi表示在信息熵部分中有介绍,如下图中介绍 方差越小越好. 选择最小的那个0.3 ...
- 2022DASCTF X SU 三月春季挑战赛 ezpop
复现一道dactf的ezpop <?php class crow { public $v1; public $v2; function eval() { echo new $this->v ...
- VMware workstation16 许可证
ZF3R0-FHED2-M80TY-8QYGC-NPKYF YF390-0HF8P-M81RQ-2DXQE-M2UT6 ZF71R-DMX85-08DQY-8YMNC-PPHV8 若资金允许,请购买正 ...