雪花算法生成分布式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考虑过 ...
随机推荐
- TiDB 5.0认证指南之PCTA PCTP
1. TiDB简介 TiDB 是 PingCAP 公司自主设计.研发的开源分布式关系型数据库,是一款同时支持在线事务处理与在线分析处理 (Hybrid Transactional and Analyt ...
- 常见的反爬措施:UA反爬和Cookie反爬
摘要:为了屏蔽这些垃圾流量,或者为了降低自己服务器压力,避免被爬虫程序影响到正常人类的使用,开发者会研究各种各样的手段,去反爬虫. 本文分享自华为云社区<Python爬虫反爬,你应该从这篇博客开 ...
- 【死磕NIO】— 探索 SocketChannel 的核心原理
大家好,我是大明哥,一个专注于[死磕 Java]系列创作的程序员. [死磕 Java ]系列为作者「chenssy」 倾情打造的 Java 系列文章,深入分析 Java 相关技术核心原理及源码. 死磕 ...
- Shiro集成多个Realm,认证都不通过返回y configured realms. Please ensure that at least one realm can authenticate these tokens.
异常内容:Authentication token of type [class org.apache.shiro.authc.UsernamePasswordToken] could not be ...
- SpringBoot使用JdbcTemplate批量保存
@Autowired DataSourceProperties dataSourceProperties; @Autowired ApplicationContext applicationConte ...
- Simulink仿真时间、步长、精度和解法器设置
在Simulink模型中Configuration Parameters里的Solver页设置仿真时间.步长.精度和解法器. 一.仿真时间:注意这里的时间概念与真实的时间并不一样,只是计算机仿真中对时 ...
- uniapp-npm install 进入版本后 优先运行全局安装,在HBuilder X终端输入 npm install 点击回车
uniapp-npm install 进入版本后 优先运行全局安装,在HBuilder X终端输入 npm install 点击回车
- 关于css布局、居中的问题以及一些小技巧
CSS的两种经典布局 左右布局 一栏定宽,一栏自适应 <!-- html --> <div class="left">定宽</div> < ...
- canvas元素内容生成图像文件
准备工作 想要将canvas元素当前显示的内容生成为图像文件,我们首先要获取canvas中的数据,在HTML5 <canvas>元素的标准中提供了toDataURL()的方法可以将canv ...
- 订单突破10000+,仅花1小时,APPx独家深入剖析背后的秘密!
拼多多:成立三年,获客三亿,月订单成交额达到恐怖的400亿,成功上市! 糕妈优选:营销活动推送1小时,订单超过10000+,商品成功刷屏朋友圈! 寻慢:一场活动净增7000+粉丝,付款转化率高达71% ...