分布式系统唯一ID生成方案( 二 )

用上面的算法测试一下,得到如下的结果:作为比较,前面3个是使用COMB算法得出的结果,最后12个字符串是时间序(统一毫秒生成的3个UUID),过段时间如果再次生成,则12个字符串会比图示的要大 。后面3个是直接生成的GUID 。

分布式系统唯一ID生成方案

文章插图
 
如果想把时间序放在前面,可以生成后改变12个字符串的位置,也可以修改算法类的最后两个Array.Copy 。
4、redis生成ID当使用数据库来生成ID性能不够要求的时候,我们可以尝试使用Redis来生成ID 。这主要依赖于Redis是单线程的,所以也可以用生成全局唯一的ID 。可以用Redis的原子操作 INCR和INCRBY来实现 。
可以使用Redis集群来获取更高的吞吐量 。假如一个集群中有5台Redis 。可以初始化每台Redis的值分别是1,2,3,4,5,然后步长都是5 。各个Redis生成的ID为:
A:1,6,11,16,21
B:2,7,12,17,22
C:3,8,13,18,23
D:4,9,14,19,24
E:5,10,15,20,25
这个,随便负载到哪个机确定好,未来很难做修改 。但是3-5台服务器基本能够满足器上,都可以获得不同的ID 。但是步长和初始值一定需要事先需要了 。使用Redis集群也可以方式单点故障的问题 。
另外,比较适合使用Redis来生成每天从0开始的流水号 。比如订单号=日期+当日自增长号 。可以每天在Redis中生成一个Key,使用INCR进行累加 。
优点:
1)不依赖于数据库,灵活方便,且性能优于数据库 。
2)数字ID天然排序,对分页或者需要排序的结果很有帮助 。
缺点:
1)如果系统中没有Redis,还需要引入新的组件,增加系统复杂度 。
2)需要编码和配置的工作量比较大 。
5、Twitter的snowflake算法snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID 。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0 。具体实现的代码可以参看
https://github.com/twitter/snowflake 。
C#代码如下:
/// <summary>    /// From: https://github.com/twitter/snowflake    /// An object that generates IDs.    /// This is broken into a separate class in case    /// we ever want to support multiple worker threads    /// per process    /// </summary>    public class IdWorker    {        private long workerId;        private long datacenterId;        private long sequence = 0L;        private static long twepoch = 1288834974657L;        private static long workerIdBits = 5L;        private static long datacenterIdBits = 5L;        private static long maxWorkerId = -1L ^ (-1L << (int)workerIdBits);        private static long maxDatacenterId = -1L ^ (-1L << (int)datacenterIdBits);        private static long sequenceBits = 12L;        private long workerIdShift = sequenceBits;        private long datacenterIdShift = sequenceBits + workerIdBits;        private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;        private long sequenceMask = -1L ^ (-1L << (int)sequenceBits);        private long lastTimestamp = -1L;        private static object syncRoot = new object();        public IdWorker(long workerId, long datacenterId)        {            // sanity check for workerId            if (workerId > maxWorkerId || workerId < 0)            {                throw new ArgumentException(string.Format("worker Id can't be greater than %d or less than 0", maxWorkerId));            }            if (datacenterId > maxDatacenterId || datacenterId < 0)            {                throw new ArgumentException(string.Format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));            }            this.workerId = workerId;            this.datacenterId = datacenterId;        }        public long nextId()        {            lock (syncRoot)            {                long timestamp = timeGen();                if (timestamp < lastTimestamp)                {                    throw new ApplicationException(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) << (int)timestampLeftShift) | (datacenterId << (int)datacenterIdShift) | (workerId << (int)workerIdShift) | sequence;            }        }        protected long tilNextMillis(long lastTimestamp)        {            long timestamp = timeGen();            while (timestamp <= lastTimestamp)            {                timestamp = timeGen();            }            return timestamp;        }        protected long timeGen()        {            return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;        }    }


推荐阅读