Twitter-Snowflake算法产生的背景至关简单,为了知足Twitter每秒上万条消息的请求,每条消息都必须分配一条惟一的id,这些id还须要一些大体的顺序(方便客户端排序),而且在分布式系统中不一样机器产生的id必须不一样。算法
snowflake把时间戳,工做机器id,序列号组合在一块儿。less
除了最高位bit标记为不可用之外,其他三组bit占位都可浮动,看具体的业务需求而定。如下关于此算法的可行性研究分布式
Console.WriteLine("41bit的时间戳能够支持该算法使用年限:{0}", (1L << 41) / (3600L * 24 * 365 * 1000.0)); Console.WriteLine("10bit的工做机器id数量:{0}", (1L << 10) - 1); Console.WriteLine("12bit序列id数量:{0}", (1L << 12) - 1);
运行结果:spa
41bit的时间戳能够支持该算法使用年限:69.7305700010147 10bit的工做机器id数量:1023 12bit序列id数量:4095
默认状况下41bit的时间戳(从当前开始计算)能够支持该算法使用近70年,10bit的工做机器id能够支持1023台机器,序列号支持1毫秒产生4095个自增序列id。那么理论上,一个应用1秒钟能够产生409万条自增ID,此算法可持续使用近70年。彻底能知足咱们平常开发项目的需求。code
工做机器id严格意义上来讲这个bit段的使用能够是进程级,机器级的话你可使用MAC地址来惟一标示工做机器,工做进程级可使用IP+Path来区分工做进程。若是工做机器比较少,可使用配置文件来设置这个id是一个不错的选择,若是机器过多配置文件的维护是一个灾难性的事情。这个工做机器id的bit段也能够进一步拆分,好比用前5个bit标记workerid,后5个bit标记datacenterid,具体代码以下:orm
class Snowflake { //工做机器id的bit段拆分为前5个bit标记workerid,后5个bit标记datacenterid const int WorkerIdBits = 5; const int DatacenterIdBits = 5; //序列号bit数 const int SequenceBits = 12; //最大编号限制 const long MaxWorkerId = -1L ^ (-1L << WorkerIdBits); const long MaxDatacenterId = -1L ^ (-1L << DatacenterIdBits); private const long SequenceMask = -1L ^ (-1L << SequenceBits); //位左运算移动量 public const int WorkerIdShift = SequenceBits; public const int DatacenterIdShift = SequenceBits + WorkerIdBits; public const int TimestampLeftShift = SequenceBits + WorkerIdBits + DatacenterIdBits; //序列号记录 private long _sequence = 0L; //时间戳记录 private long _lastTimestamp = -1L; public long WorkerId { get; protected set; } public long DatacenterId { get; protected set; } public Snowflake(long workerId, long datacenterId, long sequence = 0L) { WorkerId = workerId; DatacenterId = datacenterId; _sequence = sequence; // sanity check for workerId if (workerId > MaxWorkerId || workerId < 0) { throw new ArgumentException( String.Format("worker Id can't be greater than {0} or less than 0", MaxWorkerId) ); } if (datacenterId > MaxDatacenterId || datacenterId < 0) { throw new ArgumentException( String.Format("datacenter Id can't be greater than {0} or less than 0", MaxDatacenterId)); } } /// <summary> /// 格林时间戳 /// </summary> /// <returns></returns> public long TimeGen() { DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);// return (long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds; } readonly object _lock = new Object(); public virtual long NextId() { lock (_lock) { var timestamp = TimeGen(); if (timestamp < _lastTimestamp) { throw new InvalidSystemClock(String.Format( "发现最新时间戳少{0}毫秒的异常", _lastTimestamp - timestamp)); } if (_lastTimestamp == timestamp) { _sequence = (_sequence + 1) & SequenceMask; if (_sequence == 0) { //序列号超过限制,从新取时间戳 timestamp = TilNextMillis(_lastTimestamp); } } else { _sequence = 0; } _lastTimestamp = timestamp; //snowflake算法 var id = (timestamp << TimestampLeftShift) | (DatacenterId << DatacenterIdShift) | (WorkerId << WorkerIdShift) | _sequence; return id; } } /// <summary> /// 从新取时间戳 /// </summary> protected virtual long TilNextMillis(long lastTimestamp) { var timestamp = TimeGen(); while (timestamp <= lastTimestamp) { //新的时间戳要大于旧的时间戳,才算做有效时间戳 timestamp = TimeGen(); } return timestamp; } }