分布式的Id生成器
项目中需要一个分布式的Id生成器,twitter的Snowflake中这个既简单又高效,网上找的Java版本
package com.cqfc.id; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; /**
* tweeter的snowflake 移植到Java:
* (a) id构成: 42位的时间前缀 + 10位的节点标识 + 12位的sequence避免并发的数字(12位不够用时强制得到新的时间前缀)
* 注意这里进行了小改动: snowkflake是5位的datacenter加5位的机器id; 这里变成使用10位的机器id
* (b) 对系统时间的依赖性非常强,需关闭ntp的时间同步功能。当检测到ntp时间调整后,将会拒绝分配id
*/ public class IdWorker { private final static Logger logger = LoggerFactory.getLogger(IdWorker.class); private final long workerId;
private final long epoch = 1403854494756L; // 时间起始标记点,作为基准,一般取系统的最近时间
private final long workerIdBits = 10L; // 机器标识位数
private final long maxWorkerId = -1L ^ -1L << this.workerIdBits;// 机器ID最大值: 1023
private long sequence = 0L; // 0,并发控制
private final long sequenceBits = 12L; //毫秒内自增位 private final long workerIdShift = this.sequenceBits; //
private final long timestampLeftShift = this.sequenceBits + this.workerIdBits;//
private final long sequenceMask = -1L ^ -1L << this.sequenceBits; // 4095,111111111111,12位
private long lastTimestamp = -1L; private IdWorker(long workerId) {
if (workerId > this.maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", this.maxWorkerId));
}
this.workerId = workerId;
} public synchronized long nextId() throws Exception {
long timestamp = this.timeGen();
if (this.lastTimestamp == timestamp) { // 如果上一个timestamp与新产生的相等,则sequence加一(0-4095循环); 对新的timestamp,sequence从0开始
this.sequence = this.sequence + 1 & this.sequenceMask;
if (this.sequence == 0) {
timestamp = this.tilNextMillis(this.lastTimestamp);// 重新生成timestamp
}
} else {
this.sequence = 0;
} if (timestamp < this.lastTimestamp) {
logger.error(String.format("clock moved backwards.Refusing to generate id for %d milliseconds", (this.lastTimestamp - timestamp)));
throw new Exception(String.format("clock moved backwards.Refusing to generate id for %d milliseconds", (this.lastTimestamp - timestamp)));
} this.lastTimestamp = timestamp;
return timestamp - this.epoch << this.timestampLeftShift | this.workerId << this.workerIdShift | this.sequence;
} private static IdWorker flowIdWorker = new IdWorker(1);
public static IdWorker getFlowIdWorkerInstance() {
return flowIdWorker;
} /**
* 等待下一个毫秒的到来, 保证返回的毫秒数在参数lastTimestamp之后
*/
private long tilNextMillis(long lastTimestamp) {
long timestamp = this.timeGen();
while (timestamp <= lastTimestamp) {
timestamp = this.timeGen();
}
return timestamp;
} /**
* 获得系统当前毫秒数
*/
private static long timeGen() {
return System.currentTimeMillis();
} public static void main(String[] args) throws Exception {
System.out.println(timeGen()); IdWorker idWorker = IdWorker.getFlowIdWorkerInstance();
// System.out.println(Long.toBinaryString(idWorker.nextId()));
System.out.println(idWorker.nextId());
System.out.println(idWorker.nextId());
} }
分布式的Id生成器的更多相关文章
- 分布式全局ID生成器设计
项目是分布式的架构,需要设计一款分布式全局ID,参照了多种方案,博主最后基于snowflake的算法设计了一款自用ID生成器.具有以下优势: 保证分布式场景下生成的ID是全局唯一的 生成的全局ID整体 ...
- Jedis使用总结【pipeline】【分布式的id生成器】【分布式锁【watch】【multi】】【redis分布式】(转)
前段时间细节的了解了Jedis的使用,Jedis是redis的java版本的客户端实现.本文做个总结,主要分享如下内容: [pipeline][分布式的id生成器][分布式锁[watch][multi ...
- 分布式唯一id生成器的想法
0x01 起因 前端时间遇到一个问题,怎么快速生成唯一的id,后来采用了hashid的方法.最近在网上读到了美团关于分布式唯一id生成器的解决方案, 其中提到了三种生成法:(建议看一下这篇文章,写得很 ...
- 百度开源的分布式唯一ID生成器UidGenerator,解决了时钟回拨问题
UidGenerator是百度开源的Java语言实现,基于Snowflake算法的唯一ID生成器.而且,它非常适合虚拟环境,比如:Docker.另外,它通过消费未来时间克服了雪花算法的并发限制.Uid ...
- 分布式唯一ID生成器Twitter
分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的. 有些时候我们希望能使用一种简单一 ...
- 分布式全局ID生成器原理剖析及非常齐全开源方案应用示例
为何需要分布式ID生成器 **本人博客网站 **IT小神 www.itxiaoshen.com **拿我们系统常用Mysql数据库来说,在之前的单体架构基本是单库结构,每个业务表的ID一般从1增,通过 ...
- snowflake 分布式唯一ID生成器
本文来自我的github pages博客http://galengao.github.io/ 即www.gaohuirong.cn 摘要: 原文参考运维生存和开源中国上的代码整理 我的环境是pytho ...
- 分布式唯一ID生成器
在应用程序中,经常需要全局唯一的ID作为数据库主键.如何生成全局唯一ID? 首先,需要确定全局唯一ID是整型还是字符串?如果是字符串,那么现有的UUID就完全满足需求,不需要额外的工作.缺点是字符串作 ...
- 分布式ID生成器
最近会写一篇分布式的ID生成器的文章,先占位.借鉴Mongodb的ObjectId的生成: 4byte时间戳 + 3byte机器标识 + 2byte PID + 3byte自增id 简单代码: imp ...
随机推荐
- 如何把select默认的小三角替换成自己的图片
不同的浏览器默认的select的选项图标是不同的,例如: 在chrome中,是这样的: 未点击时 点击时 在Firefox中是这样的: 未点击时 点击时 在IE9中是这样的: 未点击时 ...
- mac上设置新版chrome浏览器跨域
设置方法 打开一个新的可跨域的chrome窗口实现方法: 1. 打开终端 2. 输入下面的命令( 需要替换路径中的yourname ) open -n /Applications/Google\ Ch ...
- 使用haproxy的ACL封禁IP
http://www.360doc.com/content/11/1226/13/834950_175075893.shtml 该方法,用户访问得到的是403页面 或者尝试用http-request拒 ...
- 常用的一些linux命令
最近接触到一些linux环境部署的事情,下面分享一些最近使用的比较频繁的一些linux命令~ 1.一次性移动多个文件到一个文件夹里 mv 被移动文件名 -t 目标文件夹 如:mv a.txt b.t ...
- 北京培训记day1
数学什么的....简直是丧心病狂啊好不好 引入:Q1:前n个数中最多能取几个,使得没有一个数是另一个的倍数 答案:(n/2)上取整 p.s.取后n/2个就好了 Q2:在Q1条件下,和最小为多少 答 ...
- OS命令注入中的空格
1.bash 空格可以替换为%20.%09(tab).%2b(+) in url.{IFS} 2.Win shell 空格可以替换为%20.%09(tab).%0b.%0c.%2b(+) in url
- SQL注入判断方法总结(持续更新)
http://e.com/1.php?id=1 http://e.com/1.php?id=1-- sd http://e.com/1.php?id=aaa http://e.com/1.php?id ...
- maven引入多个spring jar包中存在同名文件的问题
项目打包后执行报错:Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespaceht ...
- MySQL 新装数据库不能链接解决方法
在my.ini的[mysqld]字段加入: skip-grant-tables 重启mysql服务,这时的mysql不需要密码即可登录数据库 然后进入mysql mysql>use mysql; ...
- entrar en su zapatilla de deporte en este lugar
Mientras que yo apareció su campo usando nuestro Nike Glide Wildhorse sólo dos ($ 110) zapatillas de ...