在系统中,咱们须要为每一个资源设置一个惟一ID,单表时代,使用数据库的自增ID能够很简单的达到咱们的目的,可是在分布式系统、多库多表的状况下,数据库自增ID就不灵了,所以,咱们须要另外一种算法来实现分布式环境下的惟一ID。html
Snowflake核心算法:java
把时间戳、工做id和序列号拼装起来,生成一个64bit的惟一id,符号位不用,其余三组bit能够根据业务须要来进行调整,默认方案下,能使用69年,部署1023台机器,每毫秒能产生4095个自增ID。python
这里的69年,1023台机器,4095个自增ID是怎么算出来的的?git
假设41个bit都是1,那么转换成10进制就是 2**41-1 = 2199023255552毫秒≈69年,机器数量、自增ID数量也是如此计算。github
生成惟一ID的方式不少,为何是Snowflake?算法
一、相对有序,数据库插入性能好。数据库
二、Long 型存储,相对于guid uuid占用空间小。less
JAVA 实现:分布式
public final class Snowflake { private static final Long workerIdBits = 10L; private static final Long maxWorkerId = -1L ^ (-1L << workerIdBits); private static final Long sequenceBits = 12L; private static final Long maxSequence = -1L ^ (-1L << sequenceBits); private static final Long workerIdShift = sequenceBits; private static final Long timestampLeftShift = sequenceBits + workerIdBits; private final SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSS"); private final Long workerId; private Long sequence = 0L; private Long lastTimestamp = -1L; private Long since = 0l; public Snowflake(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; Calendar calendar = Calendar.getInstance(); calendar.set(2017, Calendar.NOVEMBER, 3, 0, 0, 0); this.since = calendar.getTimeInMillis(); } public synchronized Long nextId() { long timestamp = this.timeGen(); if (this.lastTimestamp == timestamp) { this.sequence = (this.sequence + 1) & this.maxSequence; if (this.sequence == 0) { timestamp = this.tilNextMillis(this.lastTimestamp); } } else { this.sequence = 0L; } if (timestamp < this.lastTimestamp) { throw new RuntimeException( String.format( "Clock moved backwards. Refusing to generate id for %d milliseconds", this.lastTimestamp - timestamp)); } this.lastTimestamp = timestamp; return ((timestamp - since) << timestampLeftShift) | (this.workerId << this.workerIdShift) | (this.sequence); } /** * 生成 * prefix 长度最多3个字符 * 返回的字符串长度最多26个字符 * * @param prefix * @return */ public synchronized String nextSerialNumber(String prefix) { prefix = StringUtils.trimToEmpty(prefix); if (prefix.length() > 3) throw new BusinessException("prefix长度不能大于3", Error.ILLEGAL_ARGUMENT); long timestamp = this.timeGen(); if (this.lastTimestamp == timestamp) { this.sequence = (this.sequence + 1) & this.maxSequence; if (this.sequence == 0) { timestamp = this.tilNextMillis(this.lastTimestamp); } } else { this.sequence = 0L; } if (timestamp < this.lastTimestamp) { throw new RuntimeException( String.format( "Clock moved backwards. Refusing to generate id for %d milliseconds", this.lastTimestamp - timestamp)); } this.lastTimestamp = timestamp; String time = format.format(new Date()); return String.format("%s%s%s%6d", prefix, time, workerId, this.sequence); } private long tilNextMillis(final long lastTimestamp) { long timestamp = this.timeGen(); while (timestamp <= lastTimestamp) { timestamp = this.timeGen(); } return timestamp; } private long timeGen() { return System.currentTimeMillis(); } }
py3实现性能
# -*- coding: utf-8 -*- import time WORKER_ID_BITS = 10 MAX_WORK_ID = -1^(-1<<WORKER_ID_BITS) SEQUENCE_BITS = 12 MAX_SEQUENCE = -1^(-1<<SEQUENCE_BITS) TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS+WORKER_ID_BITS WORKER_ID_SHIFT = SEQUENCE_BITS class Snowflake(object): def __init__(self,workerId): self.workerId = workerId self.sequence = 0 self.lastTimestamp = -1 self.since = 0 def nextId(self): timestamp = self._timestamp() if self.lastTimestamp == timestamp: self.sequence = (self.sequence + 1) & MAX_SEQUENCE if self.sequence == 0: timestamp = self._tilNextMillis() else: self.sequence = 0 self.lastTimestamp = timestamp return (timestamp - self.since) << TIMESTAMP_LEFT_SHIFT | self.workerId << WORKER_ID_SHIFT | self.sequence def _timestamp(self): return int(round(time.time()*1000)) def _tilNextMillis(self): timestamp=self._timestamp() while timestamp<self.lastTimestamp: timestamp = self._timestamp() return timestamp
参考:
1. https://github.com/twitter/snowflake
2. http://www.cnblogs.com/relucent/p/4955340.html
3.http://www.lanindex.com/twitter-snowflake%EF%BC%8C64%E4%BD%8D%E8%87%AA%E5%A2%9Eid%E7%AE%97%E6%B3%95%E8%AF%A6%E8%A7%A3/