Twitter的分布式自增ID算法snowflake (Java版)
来源:互联网 发布:淘宝商城入驻费用 编辑:程序博客网 时间:2024/04/30 03:08
概述
分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。
有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。
而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移到Cassandra,因为Cassandra没有顺序ID生成机制,所以开发了这样一套全局唯一ID生成服务。
结构
snowflake的结构如下(每部分用-分开):
0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
第一位为未使用,接下来的41位为毫秒级时间(41位的长度可以使用69年),然后是5位datacenterId和5位workerId(10位的长度最多支持部署1024个节点) ,最后12位是毫秒内的计数(12位的计数顺序号支持每个节点每毫秒产生4096个ID序号)
一共加起来刚好64位,为一个Long型。(转换成字符串长度为18)
snowflake生成的ID整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和workerId作区分),并且效率较高。据说:snowflake每秒能够产生26万个ID。
源码
(JAVA版本的源码)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/** Snowflake */
public
class
IdWorker {
private
final
long
twepoch = 1288834974657L;
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;
private
long
datacenterId;
private
long
sequence = 0L;
private
long
lastTimestamp = -1L;
public
IdWorker(
long
workerId,
long
datacenterId) {
if
(workerId > maxWorkerId || workerId <
0
) {
throw
new
IllegalArgumentException(String.format(
"worker Id can't be greater than %d or less than 0"
, maxWorkerId));
}
if
(datacenterId > maxDatacenterId || datacenterId <
0
) {
throw
new
IllegalArgumentException(String.format(
"datacenter Id can't be greater than %d or less than 0"
, maxDatacenterId));
}
this
.workerId = workerId;
this
.datacenterId = datacenterId;
}
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
static
void
main(String[] args) {
IdWorker idWorker =
new
IdWorker(
0
,
0
);
for
(
int
i =
0
; i <
1000
; i++) {
long
id = idWorker.nextId();
System.out.println(id);
}
}
}
(JAVA版本2的源码)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/** Snowflake */
private final long workerId;
private final static long twepoch = 1361753741828L;
private long sequence = 0L;
private final static long workerIdBits = 4L;
public final static long maxWorkerId = -1L ^ -1L << workerIdBits;
private final static long sequenceBits = 10L;
private final static long workerIdShift = sequenceBits;
private final static long timestampLeftShift = sequenceBits + workerIdBits;
public final static long sequenceMask = -1L ^ -1L << sequenceBits;
private long lastTimestamp = -1L;
public IdWorker(final long workerId) {
super();
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() {
long timestamp = this.timeGen();
if (this.lastTimestamp == timestamp) {
this.sequence = (this.sequence + 1) & this.sequenceMask;
if (this.sequence == 0) {
System.out.println("###########" + sequenceMask);
timestamp = this.tilNextMillis(this.lastTimestamp);
}
} else {
this.sequence = 0;
}
if (timestamp < this.lastTimestamp) {
try {
throw new Exception(
String.format(
"Clock moved backwards. Refusing to generate id for %d milliseconds",
this.lastTimestamp - timestamp));
} catch (Exception e) {
e.printStackTrace();
}
}
this.lastTimestamp = timestamp;
long nextId = ((timestamp - twepoch << timestampLeftShift))
| (this.workerId << this.workerIdShift) | (this.sequence);
// System.out.println("timestamp:" + timestamp + ",timestampLeftShift:"
// + timestampLeftShift + ",nextId:" + nextId + ",workerId:"
// + workerId + ",sequence:" + sequence);
return nextId;
}
private long tilNextMillis(final long lastTimestamp) {
long timestamp = this.timeGen();
while (timestamp <= lastTimestamp) {
timestamp = this.timeGen();
}
return timestamp;
}
private long timeGen() {
return System.currentTimeMillis();
}
public static void main(String[] args){
IdWorker worker2 = new IdWorker(2);
System.out.println(worker2.nextId());
}
}
参考
https://github.com/twitter/snowflake
0 0
- Twitter的分布式自增ID算法snowflake (Java版)
- Twitter的分布式自增ID算法snowflake (Java版)
- Twitter的分布式自增ID算法snowflake (Java版)
- Twitter的分布式自增ID算法snowflake (Java版)
- Twitter的分布式自增ID算法snowflake (Java版)
- Twitter的分布式自增ID算法snowflake (Java版)
- Twitter的分布式自增ID算法snowflake (Java版)
- Twitter的分布式自增ID算法snowflake (Java版)
- Twitter的分布式自增ID算法snowflake (Java版)
- Twitter的分布式自增ID算法snowflake(Java版)
- Twitter的分布式自增ID算法snowflake (Java版)
- [转]Twitter的分布式自增ID算法snowflake java
- Twitter的分布式自增ID算法snowflake - C#版
- Twitter的分布式自增ID算法Snowflake实现分析及其Java、Php和Python版
- Twitter的分布式自增ID算法Snowflake实现分析及其Java、Php和Python版
- Twitter的分布式自增ID雪花算法snowflake (Java版)
- Twitter的分布式自增ID算法snowflake(有改动Java版)
- Twitter分布式自增ID算法Snowflake
- js获取当前时间,返回字符格式
- Centos 6.4 python 2.6 升级到 2.7
- iOS预留
- 织梦如何修改图片水印
- modsecurity系列二:主文件配置
- Twitter的分布式自增ID算法snowflake (Java版)
- Android基于4.4沉侵式状态栏和继承BaseActivity不用findViewbyid得到控件id
- LINQ查询操作符
- RHEL/CentOS and Debian/Ubuntu上使用Nginx安装odoo9
- HTTPS
- 【C/PY】浮点型 float
- iOS9 UIStackView 简介
- tomcat configuration path报错
- 人脸识别技术在公安领域的应用浅析【识别过程描述】