分布式自增id生成器 snowflake一定是自增的么

Twitter分布式ID算法Snowflake | 海纳百川的博客
Snowflake是Twitter开发的一个分布式ID生成算法,有以下几个特点:
1)默认情况下41bit的时间戳可以支持该算法使用到2082年,10bit的工作机器id可以支持1023台机器,序列号支持1毫秒产生4095个自增序列id,即理论上1秒产生409万id
2)高性能,不依赖其他第三方服务,稳定性高
3)强依赖于机器时钟
下面看看它的算法结构图:
可以看到它是由三部分组成
1)当前时间戳
2)工作机器ID:包括dataCenterId和workId,可自己配置
3)12bit序列号,即从0增长到4095
算法其实很简单,因为不依赖于其它服务器,都是做时间比较和位移操作,流程图如下:
下面针对JAVA版的算法具体分析
// ==============================Fields===========================================
/** 开始时间截 () */
private final long twepoch = 0L;
/** 机器id所占的位数 */
private final long workerIdBits = 5L;
/** 数据标识id所占的位数 */
private final long datacenterIdBits = 5L;
/** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
private final long maxWorkerId = -1L ^ (-1L && workerIdBits);
/** 支持的最大数据标识id,结果是31 */
private final long maxDatacenterId = -1L ^ (-1L && datacenterIdBits);
/** 序列在id中占的位数 */
private final long sequenceBits = 12L;
/** 机器ID向左移12位 */
private final long workerIdShift = sequenceB
/** 数据标识id向左移17位(12+5) */
private final long datacenterIdShift = sequenceBits + workerIdB
/** 时间截向左移22位(5+5+12) */
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdB
/** 生成序列的掩码,这里为xfff=4095) */
private final long sequenceMask = -1L ^ (-1L && sequenceBits);
/** 工作机器ID(0~31) */
private long workerId;
/** 数据中心ID(0~31) */
private long datacenterId;
/** 毫秒内序列(0~4095) */
private long sequence = 0L;
/** 上次生成ID的时间截 */
private long lastTimestamp = -1L;
因为算法都是基于二进制的位移操作,所以上面定义了一大堆变量,基本都是一些需要位移的长度
如序列IDsequenceBits在定义了它的二进制长度,序列号最大为4095,它的二进制占用长度就是12
同样datacenterId和workId最大数为31,二进制占用的长度就是5,workerIdShift,datacenterIdShift,timestampLeftShift定义了他们需要的位移数
为啥都要基于二进制的位移来操作呢?因为这样对于机器来说计算更快
核心方法生成ID
// ==============================Methods==========================================
* 获得下一个ID (该方法是线程安全的)
* @return SnowflakeId
public synchronized long nextId() {
long timestamp = timeGen();
//如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
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) & sequenceM
//毫秒内序列溢出
if (sequence == 0) {
//阻塞到下一个毫秒,获得新的时间戳
timestamp = tilNextMillis(lastTimestamp);
//时间戳改变,毫秒内序列重置
sequence = 0L;
//上次生成ID的时间截
lastTimestamp =
//移位并通过或运算拼到一起组成64位的ID
return ((timestamp - twepoch) && timestampLeftShift) //
| (datacenterId && datacenterIdShift) //
| (workerId && workerIdShift) //
* 阻塞到下一个毫秒,直到获得新的时间戳
* @param lastTimestamp 上次生成ID的时间截
* @return 当前时间戳
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp &= lastTimestamp) {
timestamp = timeGen();
* 返回以毫秒为单位的当前时间
* @return 当前时间(毫秒)
protected long timeGen() {
return System.currentTimeMillis();
1)首先调用timeGen()获取当前时间戳
2)如果当前时间戳小于上次记录的时间戳,则抛出异常,表示始终回拨了(所以要保证每台机器上时间统一)
3)如果当前时间戳等于上一次时间戳,表示同一秒内有多个并发请求,此时序列号就发挥作用了,递增+1,这里有一个操作(sequence + 1) & sequenceMask,就是要与最大序列号4095做&操作,即如果它大于了最大的序列号,那么sequence就等于0了,此时调用tilNextMillis()方法做等待操作,直到生成的时间戳大于上一次时间戳,因为同一秒只支持4095个并发
4)如果当前时间戳大于上一次,则直接把sequence置0
5)将上一次时间戳更新为当前时间戳
6)最后一步也是关键,通过位移操作,把sequence(序列号),workId(工作ID),datacenterId(数据中心ID),timestamps(时间戳)拼到一起
说明这里还有一个twepoch,表示起始的时间点,这里的作用主要是控制生成ID的大小,如果你想从较小的ID开始递增,那么twepoch就可以设置的大一些,可以等于当前的时间戳,因为(timestamp – twepoch)的值就越小,反之则时间越往前ID越大
传入一个datacenterId和workId就可以了,说明下不同机器可以使用不同的datacenterId,一台机器上不同的项目可以使用不同的wokId
* 构造函数
* @param workerId 工作ID (0~31)
* @param datacenterId 数据中心ID (0~31)
public SnowflakeIdWorker(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;
最后说说snowflake的优缺点:
1)毫秒数在高位,自增序列在低位,整个ID都是趋势递增的。
2)不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成ID的性能也是非常高的。
3)可以根据自身业务特性分配bit位,非常灵活。
使用场景如:生成订单ID,因为ID不是连续递增的,所以可以保证订单数的隐蔽性
1)强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或者服务会处于不可用状态。
2)分布式部署时,服务器最好开启Network Time Protocol (NTP)服务,保证每个机器时间一致
下次说说如何使用zookeeper调度生成ID及保证服务的高可用。
This entry was posted in ,分布式ID自增算法 Snowflake - dotNET跨平台 - CSDN博客
分布式ID自增算法 Snowflake
近在尝试EF的多数据库移植,但是原始项目中主键用的Sqlserver的GUID。MySQL没法移植了。
其实发现GUID也没法保证数据的递增性,又不太想使用int递增主键,就开始探索别的ID形式。
后来发现twitter的Snowflake算法。
一开始我尝试过直接引用Nuget里的Snowflake的扩展包(有Framework版和Core版),不过有些Bug,就是初始化参数有的时候不一定好用,最大问题是,这个需要实例化对象,并且通过同一个对象来实生成ID,否则会出现ID冲突问题。而且,我们还要考虑对象在内存的生存问题。学习这种算法是够用了,但是用到实际生产中则有很多问题,虽然我们可以通过一些技术来避免这种问题,但是总觉得不够优雅,不符合我的美学!&
后来看到这篇博客&C# 实现 Snowflake算法&先感谢一下这个大神。但是同样有上述的部分问题,做5线程的并发测试的时候效率不如扩展的。后面我们会提到。
我从这篇博客里摘来了源码,对有的地方做了一些改动使得其更适合(至少我认为是)更适合生产环境。
public class SFID
& & & & /// &summary&
& & & & /// 机器码
& & & & /// &/summary&
& & & & private static long _workerId;
& & & & /// &summary&
& & & & /// 初始基准时间戳,小于当前时间点即可
& & & & /// 分布式项目请保持此时间戳一致
& & & & /// &/summary&
& & & & private static long _twepoch = 0L;
& & & & /// &summary&
& & & & /// 毫秒计数器
& & & & /// &/summary&
& & & & private static long sequence = 0L;
& & & & /// &summary&
& & & & /// 机器码字节数。4个字节用来保存机器码(定义为Long类型会出现,最大偏移64位,所以左移64位没有意义)
& & & & /// &/summary&
& & & & private static int workerIdBits = 4;&
& & & & /// &summary&
& & & & /// 最大机器ID所占的位数
& & & & /// &/summary&
& & & & private static long maxWorkerId = -1L ^ -1L && workerIdB
& & & & /// &summary&
& & & & /// 计数器字节数,10个字节用来保存计数码
& & & & /// &/summary&
& & & & private static int sequenceBits = 12;
& & & & /// &summary&
& & & & /// 机器码数据左移位数,就是后面计数器占用的位数
& & & & /// &/summary&
& & & & private static int workerIdShift = sequenceB
& & & & /// &summary&
& & & & /// 时间戳左移动位数就是机器码和计数器总字节数
& & & & /// &/summary&
& & & & private static int timestampLeftShift = sequenceBits + workerIdB
& & & & /// &summary&
& & & & /// 一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成
& & & & /// &/summary&
& & & & private static long sequenceMask = -1L ^ -1L && sequenceB
& & & & /// &summary&
& & & & /// 最后一次的时间戳
& & & & /// &/summary&
& & & & private static long lastTimestamp = -1L;
& & & & /// &summary&
& & & & /// 线程锁对象
& & & & /// &/summary&
& & & & private static object locker = new object();
& & & & static SFID()
& & & & & & _workerId = new Random(DateTime.Now.Millisecond).Next(1, (int)maxWorkerId);
& & & & & & _twepoch = timeGen(, 0, 0, 0);
& & & & /// &summary&
& & & & /// 机器编号
& & & & /// &/summary&
& & & & public static long WorkerID
& & & & & & get { return _workerId; }
& & & & & & set
& & & & & & {
& & & & & & & & if (value & 0 && value & maxWorkerId)
& & & & & & & & & & _workerId =
& & & & & & & & else
& & & & & & & & & & throw new Exception("Workerid must be greater than 0 or less than " + maxWorkerId);
& & & & & & }
& & & & /// &summary&
& & & & /// 获取新的ID
& & & & /// &/summary&
& & & & /// &returns&&/returns&
& & & & public static long NewID()
& & & & & & lock (locker)
& & & & & & {
& & & & & & & & long timestamp = timeGen();
& & & & & & & & if (lastTimestamp == timestamp)
& & & & & & & & { //同一微妙中生成ID
& & & & & & & & & & sequence = (sequence + 1) & sequenceM //用&运算计算该微秒内产生的计数是否已经到达上限
& & & & & & & & & & if (sequence == 0)
& & & & & & & & & & {
& & & & & & & & & & & & //一微妙内产生的ID计数已达上限,等待下一微妙
& & & & & & & & & & & & timestamp = tillNextMillis(lastTimestamp);
& & & & & & & & & & }
& & & & & & & & }
& & & & & & & & else
& & & & & & & & { //不同微秒生成ID
& & & & & & & & & & sequence = 0; //计数清0
& & & & & & & & }
& & & & & & & & if (timestamp & lastTimestamp)
& & & & & & & & {&
& & & & & & & & & & //如果当前时间戳比上一次生成ID时时间戳还小,抛出异常,因为不能保证现在生成的ID之前没有生成过
& & & & & & & & & & throw new Exception(string.Format("Clock moved backwards. &Refusing to generate id for {0} milliseconds", lastTimestamp - timestamp));
& & & & & & & & }
& & & & & & & & lastTimestamp = //把当前时间戳保存为最后生成ID的时间戳
& & & & & & & & return (timestamp - _twepoch && timestampLeftShift) | _workerId && workerIdShift |
& & & & & & }
& & & & /// &summary&
& & & & /// 获取下一微秒时间戳
& & & & /// &/summary&
& & & & /// &param name="lastTimestamp"&&/param&
& & & & /// &returns&&/returns&
& & & & private static long tillNextMillis(long lastTimestamp)
& & & & & & long timestamp = timeGen();
& & & & & & while (timestamp &= lastTimestamp)
& & & & & & {
& & & & & & & & timestamp = timeGen();
& & & & & & }
& & & & & &
& & & & /// &summary&
& & & & /// 当前时间戳
& & & & /// &/summary&
& & & & /// &returns&&/returns&
& & & & private static long timeGen()
& & & & & & return (long)(DateTime.UtcNow - new DateTime(, 0, 0, 0, DateTimeKind.Utc)).TotalM
& & & & /// &summary&
& & & & /// 指定时间戳
& & & & /// &/summary&
& & & & /// &param name="Time"&指定时间&/param&
& & & & /// &returns&&/returns&
& & & & private static long timeGen(int Year, int Month, int Day, int Hour, int Minute, int Second)
& & & & & & var UtcTime = new DateTime(Year, Month, Day, Hour, Minute, Second, DateTimeKind.Utc);
& & & & & & return (long)(UtcTime - new DateTime(, 0, 0, 0, DateTimeKind.Utc)).TotalM
说下使用,理论上如果是单机部署,不用做任何配置工作
直接&SFID.NewID() 就可以使用。&
如果分布式的话
.Net Framework项目在Application_Start中,.Net Core项目在Configure中添加&SFID.WorkerID = 1L; 就可以 1L换成你的不同机器代号就可以,建议从配置文件读取可以保证代码一致性。另外不要部署ID相同的服务器,很可能会出现ID冲突。
因为就用了4位,所以最大只支持16台机器,如果不够用,可以去改workerIdBits的值,但是注意,这样会压缩ID的使用寿命,如果改为10位的话,大概可以用69年。
起始时间,我的为了保持一致使用了日0时。ID的使用寿命则是以这个时间点进行计算的。如果觉得不够用修代码中构造方法里的时间。但是注意多台保持一致。否则不能保证ID顺序递增。&
然后大概说说修改思路。
1、关于实例化ID算法对象这个事,我觉得与其每次都初始化,然后费了半天劲保持对象生存,不如直接使用单例模式。所以方法不需要再单独实例化。
但是这么做也是有缺点的,如果我想业务A和业务B分别使用不同ID的序列,那么多实例模式则更适合,两个不同的业务,占位可以不一样,并且允许出现相同ID,更节省ID,效率也相对较高。
2、关于效率不高的问题,其实是原来的代码中计数器位过短造成的,并发达到数量达到可分配ID的峰值后,线程就会锁死不再发放ID,直到下一毫秒。
知道问题就很好解决了,调整大计数器长度,压缩服务器编号占位(我觉得实际生产中,很少有机会会用到1K台机器并发)。
相关文章:&
原文地址:/kasimlz/p/7511131.html
.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注
我的热门文章分布式自增ID解决方案-Twitter Snowflake - CSDN博客
分布式自增ID解决方案-Twitter Snowflake
在大型互联网应用中,随着用户数的增加,为了提高应用的性能,我们经常需要对进行分库分表操作。在单表时代,我们可以完全依赖于数据库的自增ID来唯一标识一
个用户或数据对象。
&&&但是当我们对数据库进行了分库分表后,就不能依赖于每个表的自增ID来全局唯一标识这些数据了。因为自增的id不能在分库分表的场景下,准确的路由到正确的数据。
&&&因此,我们需要提供一个全局唯一的ID号生成策略来支持分库分表的环境
&&& Twitter-Snowflake算法产生的背景相当简单,为了满足Twitter每秒上万条消息的请求,每条消息都必须分配一条唯一的id,这些id还需要一些大致的顺序(方
便客户端排序),并且在分布式系统中不同机器产生的id必须不同。
&&& 除了最高位bit标记为不可用以外,其余三组bit占位均可浮动,看具体的业务需求而定。默认情况下41bit的时间戳可以支持该算法使用到2082年,10bit的工作机器id可以支持
1023台机器,序列号支持1毫秒产生4095个自增序列id。
&&& 根据twitter的业务需求,snowflake系统生成64位的ID。由3部分组成:
41位的时间序列(精确到毫秒,41位的长度可以使用69年)
10位的机器标识(10位的长度最多支持部署1024个节点)
12位的计数顺序号(12位的计数顺序号支持每个节点每毫秒产生4096个ID序号)
本文已收录于以下专栏:
相关文章推荐
全局唯一订单号生成方法(参考snowflake)Snowflake is a network service for generating unique ID numbers at high scal...
实际开发中
一般数据库系统自带serial字段或者通过创建sequence实现自增字段
o数据库自带,使用简单
oID从小到大产生,便于识别
o占用空间小,4byte
Mybatis管理事务是分为两种方式:
(1)使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交
(2)使用MANAGED的事务管理机制,这种机制myb...
分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。
有些时候我们希...
1.snowflake简介
        互联网快速发展的今天,分布式应用系统已经见怪不怪,在分布式系统中,我们需要各种各样的ID,既然是ID那么必然是要保证全局唯一,除此之外,不同当业务还需要不同...
分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。
有些时候我们希望能使用...
详解Twitter开源分布式自增ID算法snowflake,附演算验证过程.
snowflake简介,snowflake算法原理,snowflake算法源码(java版),snowflake算法推导和...
在分布式系统中,需要生成全局UID的场合还是比较多的,twitter的snowflake解决了这种需求,实现也还是很简单的,除去配置信息,核心代码就是毫秒级时间41位+机器ID 10位+毫秒内序列12...
分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能...
分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。
有些时候我们希...
他的最新文章
讲师:王禹华
讲师:宋宝华
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)twitter的分布式自增ID算法snowflake实现分析及其Java、php和pyth...
我的图书馆
twitter的分布式自增ID算法snowflake实现分析及其Java、php和pyth...
在分布式系统中,需要生成全局UID的场合还是比较多的,twitter的snowflake解决了这种需求,实现也还是很简单的,除去配置信息,核心代码就是毫秒级时间41位+机器ID 10位+毫秒内序列12位。
该项目地址为:是用Scala实现的。
python版详见开源项目。
核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:
0 --- 00000 ---00000 --- 00
在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
且看其核心代码:
1&/pre&2/** Copyright
Twitter, Inc.*/3package com.twitter.service.snowflake4&5import com.twitter.ostrich.stats.Stats6import com.twitter.service.snowflake.gen._7import java.util.Random8import com.twitter.logging.Logger9&10/**11&* An object that generates IDs.12&* This is broken into a separate class in case13&* we ever want to support multiple worker threads14&* per process15&*/16class IdWorker(val workerId: Long, val datacenterId: Long, private val reporter: Reporter, var sequence: Long = 0L)17extends Snowflake.Iface {18&&private[this] def genCounter(agent: String) = {19&&&&Stats.incr("ids_generated")20&&&&Stats.incr("ids_generated_%s".format(agent))21&&}22&&private[this] val exceptionCounter = Stats.getCounter("exceptions")23&&private[this] val log = Logger.get24&&private[this] val rand = new Random25&26&&val twepoch = 7L27&28&//机器标识位数29&30&&private[this] val workerIdBits = 5L31&32//数据中心标识位数33&&private[this] val datacenterIdBits = 5L34&35//机器ID最大值36&&private[this] val maxWorkerId = -1L ^ (-1L && workerIdBits)37&38//数据中心ID最大值39&&private[this] val maxDatacenterId = -1L ^ (-1L && datacenterIdBits)40&41//毫秒内自增位42&&private[this] val sequenceBits = 12L43&44//机器ID偏左移12位45&46&&private[this] val workerIdShift = sequenceBits47&48//数据中心ID左移17位49&&private[this] val datacenterIdShift = sequenceBits + workerIdBits50&51//时间毫秒左移22位52&&private[this] val timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits53&&private[this] val sequenceMask = -1L ^ (-1L && sequenceBits)54&55&&private[this] var lastTimestamp = -1L56&57&&// sanity check for workerId58&&if (workerId & maxWorkerId || workerId & 0) {59&&&&exceptionCounter.incr(1)60&&&&throw new IllegalArgumentException("worker Id can't be greater than %d or less than 0".format(maxWorkerId))61&&}62&63&&if (datacenterId & maxDatacenterId || datacenterId & 0) {64&&&&exceptionCounter.incr(1)65&&&&throw new IllegalArgumentException("datacenter Id can't be greater than %d or less than 0".format(maxDatacenterId))66&&}67&68&&<("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d",69&&&&timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId)70&71&&def get_id(useragent: String): Long = {72&&&&if (!validUseragent(useragent)) {73&&&&&&exceptionCounter.incr(1)74&&&&&&throw new InvalidUserAgentError75&&&&}76&77&&&&val id = nextId()78&&&&genCounter(useragent)79&80&&&&reporter.report(new AuditLogEntry(id, useragent, rand.nextLong))81&&&&id82&&}83&84&&def get_worker_id(): Long = workerId85&&def get_datacenter_id(): Long = datacenterId86&&def get_timestamp() = System.currentTimeMillis87&88&&protected[snowflake] def nextId(): Long = synchronized {89&&&&var timestamp = timeGen()90&91&//时间错误92&93&&&&if (timestamp & lastTimestamp) {94&&&&&&exceptionCounter.incr(1)95&&&&&&log.error("clock is moving backwards.& Rejecting requests until %d.", lastTimestamp);96&&&&&&throw new InvalidSystemClock("Clock moved backwards.& Refusing to generate id for %d milliseconds".format(97&&&&&&&&lastTimestamp - timestamp))98&&&&}99&100&&&&if (lastTimestamp == timestamp) {101//当前毫秒内,则+1102&&&&&&sequence = (sequence + 1) & sequenceMask103&&&&&&if (sequence == 0) {104//当前毫秒内计数满了,则等待下一秒105&&&&&&&&timestamp = tilNextMillis(lastTimestamp)106&&&&&&}107&&&&} else {108&&&&&&sequence = 0109&&&&}110&111&&&&lastTimestamp = timestamp112//ID偏移组合生成最终的ID,并返回ID&&&113&114((timestamp - twepoch) && timestampLeftShift) |115&&&&&&(datacenterId && datacenterIdShift) |116&&&&&&(workerId && workerIdShift) |117&&&&&&sequence118&&}119&120//等待下一个毫秒的到来&121&122protected def tilNextMillis(lastTimestamp: Long): Long = {123&&&&var timestamp = timeGen()124&&&&while (timestamp &= lastTimestamp) {125&&&&&&timestamp = timeGen()126&&&&}127&&&&timestamp128&&}129&130&&protected def timeGen(): Long = System.currentTimeMillis()131&132&&val AgentParser = """([a-zA-Z][a-zA-Z\-0-9]*)""".r133&134&&def validUseragent(useragent: String): Boolean = useragent match {135&&&&case AgentParser(_) =& true136&&&&case _ =& false137&&}138}139&pre&
上述为twitter的实现,下面且看一个Java实现,貌似为淘宝的朋友写的。
1public class IdWorker {2&private final long workerId;3&private final static long twepoch = 8L;4&private long sequence = 0L;5&private final static long workerIdBits = 4L;6&public final static long maxWorkerId = -1L ^ -1L && workerIdB7&private final static long sequenceBits = 10L;8&9&private final static long workerIdShift = sequenceB10&private final static long timestampLeftShift = sequenceBits + workerIdB11&public final static long sequenceMask = -1L ^ -1L && sequenceB12&13&private long lastTimestamp = -1L;14&15&public IdWorker(final long workerId) {16&&super();17&&if (workerId & this.maxWorkerId || workerId & 0) {18&&&throw new IllegalArgumentException(String.format(19&&&&&"worker Id can't be greater than %d or less than 0",20&&&&&this.maxWorkerId));21&&}22&&this.workerId = workerId;23&}24&25&public synchronized long nextId() {26&&long timestamp = this.timeGen();27&&if (this.lastTimestamp == timestamp) {28&&&this.sequence = (this.sequence + 1) & this.sequenceM29&&&if (this.sequence == 0) {30&&&&System.out.println("###########" + sequenceMask);31&&&&timestamp = this.tilNextMillis(this.lastTimestamp);32&&&}33&&} else {34&&&this.sequence = 0;35&&}36&&if (timestamp & this.lastTimestamp) {37&&&try {38&&&&throw new Exception(39&&&&&&String.format(40&&&&&&&&"Clock moved backwards.& Refusing to generate id for %d milliseconds",41&&&&&&&&this.lastTimestamp - timestamp));42&&&} catch (Exception e) {43&&&&e.printStackTrace();44&&&}45&&}46&47&&this.lastTimestamp =48&&long nextId = ((timestamp - twepoch && timestampLeftShift))49&&&&| (this.workerId && this.workerIdShift) | (this.sequence);50//&&System.out.println("timestamp:" + timestamp + ",timestampLeftShift:"51//&&&&+ timestampLeftShift + ",nextId:" + nextId + ",workerId:"52//&&&&+ workerId + ",sequence:" + sequence);53&&return nextId;54&}55&56&private long tilNextMillis(final long lastTimestamp) {57&&long timestamp = this.timeGen();58&&while (timestamp &= lastTimestamp) {59&&&timestamp = this.timeGen();60&&}61&&return 62&}63&64&private long timeGen() {65&&return System.currentTimeMillis();66&}67&&68&&69&public static void main(String[] args){70&&IdWorker worker2 = new IdWorker(2);71&&System.out.println(worker2.nextId());72&73&&&74&}75&76}
再来看一个php的实现
1&?php2class Idwork3{4const debug = 1;5static $workerId;6static $twepoch = 8;7static $sequence = 0;8const workerIdBits = 4;9static $maxWorkerId = 15;10const sequenceBits = 10;11static $workerIdShift = 10;12static $timestampLeftShift = 14;13static $sequenceMask = 1023;14private& static $lastTimestamp = -1;15&16function __construct($workId){17if($workId & self::$maxWorkerId || $workId& 0 )18{19throw new Exception("worker Id can't be greater than 15 or less than 0");20}21self::$workerId=$workId;22&23echo 'logdebug-&__construct()-&self::$workerId:'.self::$workerId;24echo '&/br&';25&26}27&28function timeGen(){29//获得当前时间戳30$time = explode(' ', microtime());31$time2= substr($time[0], 2, 3);32$timestramp = $time[1].$time2;33echo 'logdebug-&timeGen()-&$timestramp:'.$time[1].$time2;34echo '&/br&';35return& $time[1].$time2;36}37function& tilNextMillis($lastTimestamp) {38$timestamp = $this-&timeGen();39while ($timestamp &= $lastTimestamp) {40$timestamp = $this-&timeGen();41}42&43echo 'logdebug-&tilNextMillis()-&$timestamp:'.$timestamp;44echo '&/br&';45return $timestamp;46}47&48function& nextId()49{50$timestamp=$this-&timeGen();51echo 'logdebug-&nextId()-&self::$lastTimestamp1:'.self::$lastTimestamp;52echo '&/br&';53if(self::$lastTimestamp == $timestamp) {54self::$sequence = (self::$sequence + 1) & self::$sequenceMask;55if (self::$sequence == 0) {56&&&&echo "###########".self::$sequenceMask;57&&&&$timestamp = $this-&tilNextMillis(self::$lastTimestamp);58&&&&echo 'logdebug-&nextId()-&self::$lastTimestamp2:'.self::$lastTimestamp;59&&&&echo '&/br&';60&&}61} else {62self::$sequence& = 0;63&&&&echo 'logdebug-&nextId()-&self::$sequence:'.self::$sequence;64&&&&echo '&/br&';65}66if ($timestamp & self::$lastTimestamp) {67&&&throw new Excwption("Clock moved backwards.& Refusing to generate id for ".(self::$lastTimestamp-$timestamp)." milliseconds");68&&&}69self::$lastTimestamp& = $timestamp;70echo 'logdebug-&nextId()-&self::$lastTimestamp3:'.self::$lastTimestamp;71echo '&/br&';72&73echo 'logdebug-&nextId()-&(($timestamp - self::$twepoch && self::$timestampLeftShift )):'.((sprintf('%.0f', $timestamp) - sprintf('%.0f', self::$twepoch) ));74echo '&/br&';75$nextId = ((sprintf('%.0f', $timestamp) - sprintf('%.0f', self::$twepoch)& )) | ( self::$workerId && self::$workerIdShift ) | self::$sequence;76echo 'timestamp:'.$timestamp.'-----';77echo 'twepoch:'.sprintf('%.0f', self::$twepoch).'-----';78echo 'timestampLeftShift ='.self::$timestampLeftShift.'-----';79echo 'nextId:'.$nextId.'----';80echo 'workId:'.self::$workerId.'-----';81echo 'workerIdShift:'.self::$workerIdShift.'-----';82return $nextId;83}84&85}86$Idwork = new Idwork(1);87$a= $Idwork-&nextId();88$Idwork = new Idwork(2);89$a= $Idwork-&nextId();90?&
TA的最新馆藏
喜欢该文的人也喜欢

我要回帖

更多关于 c 分布式id自增算法 的文章

 

随机推荐