首页 > 代码库 > 【高性能】生成唯一时间戳ID,如果性能不高可以不用来看

【高性能】生成唯一时间戳ID,如果性能不高可以不用来看

凡事涉及到高性能貌似都是高大上的东西,所以嘛我也试试;其实这个时间戳ID的生成主要为了解决我们公司内部的券号生成,估计有小伙伴认为券号生成有这么麻烦嘛,搞个自增ID完全可以用起来,或者时间取毫微米时间戳等。

如果以上真是这样简单的话,那我要说道说道;首先自增ID资源耗尽的时候,特别礼券号生成的越频繁,毕竟bigInt也有耗尽那天(当然如果有更长数字字段就是慢慢耗呗),而且依靠数据库进行被动生成,在有些业务上比较软肋;我还有一个同事说搞一张表定时去自增生成ID,这样就能随时取已经存在的ID资源数据,我只能说这是一种笨办法,而且你都不知道外部业务对券号的需要量有多少,万一立马要个1000万,你来得及?

还有就是毫微米时间戳也是会出问题,因为在多并发请求下也会大概率出现同样ID,大家不信可以去试试,想想我们的CPU运算有多快;当然防止重复可以考虑休眠例如一毫秒,但这样就会丢失性能,想想雪花算法一毫秒能产生4095个不重复ID,我们好歹也可以向它学习吧,以上说了这么多少就明白了这个要求也是蛮苛刻的,当中我也想过用雪花算法,但由于生成的ID比较长(后面我会说为什么不适宜)!

下面来看看我对这个唯一时间戳ID生成的代码算法,借鉴了点雪花算法:

   /// <summary>    /// 时间戳ID    /// </summary>    public class TimestampID    {        private long _lastTimestamp;        private long _sequence; //计数从零开始        private readonly DateTime? _initialDateTime;        private static TimestampID _timestampID;        private const int MAX_END_NUMBER = 9999;        private TimestampID(DateTime? initialDateTime)        {            _initialDateTime = initialDateTime;        }        /// <summary>        /// 获取单个实例对象        /// </summary>        /// <param name="initialDateTime">最初时间,与当前时间做个相差取时间戳</param>        /// <returns></returns>        public static TimestampID GetInstance(DateTime? initialDateTime = null)        {            if (_timestampID == null) Interlocked.CompareExchange(ref _timestampID, new TimestampID(initialDateTime), null);            return _timestampID;        }        /// <summary>        /// 最初时间,作用时间戳的相差        /// </summary>        protected DateTime InitialDateTime        {            get            {                if (_initialDateTime == null || _initialDateTime.Value =http://www.mamicode.com/= DateTime.MinValue) return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);                return _initialDateTime.Value;            }        }        /// <summary>        /// 获取时间戳ID        /// </summary>        /// <returns></returns>        public string GetID()        {            long temp;            var timestamp = GetUniqueTimeStamp(_lastTimestamp, out temp);            return $"{timestamp}{Fill(temp)}";        }        private string Fill(long temp)        {            var num = temp.ToString();            IList<char> chars = new List<char>();            for (int i = 0; i < MAX_END_NUMBER.ToString().Length - num.Length; i++)            {                chars.Add(0);            }            return new string(chars.ToArray()) + num;        }        /// <summary>        /// 获取一个时间戳字符串        /// </summary>        /// <returns></returns>        public long GetUniqueTimeStamp(long lastTimeStamp, out long temp)        {            lock (this)            {                temp = 1;                var timeStamp = GetTimestamp();                if (timeStamp == _lastTimestamp)                {                    _sequence = _sequence + 1;                    temp = _sequence;                    if (temp >= MAX_END_NUMBER)                    {                        timeStamp = GetTimestamp();                        _lastTimestamp = timeStamp;                        temp = _sequence = 1;                    }                }                else                {                    _sequence = 1;                    _lastTimestamp = timeStamp;                }                return timeStamp;            }        }        /// <summary>        ///         /// </summary>        /// <returns></returns>        private long GetTimestamp()        {            if (InitialDateTime >= DateTime.Now) throw new Exception("最初时间比当前时间还大,不合理");            var ts = DateTime.UtcNow - InitialDateTime;            return (long)ts.TotalMilliseconds;        }    }

当中我加了一点补位算法,保证每次出来的ID长度一致,之前提到了是用在礼券号上的,那就应该不能这么长,后续我又继续进行了32进制计算,缩短到8-10位左右,但大家估计觉的还是长,那就看取决你把相差时间应该缩短。但如果直接用雪花算法生成的ID进行32位进制缩短也是在10位以上,所以我没有用到。

对了,忘记说了性能问题,一毫秒预计能生成1000个,呵呵,还算过得去

接下来谈谈礼券这块业务,类似我们初创电商公司这种需要去互联网上大量拉拢会员,所以也相对需要大量的推广礼券号,如果成熟的电商如京东和天猫等,他们所有礼券都已经绑定到自己会员身上,在使用上根本不用去关注填写什么礼券号,也是他们的礼券体系相对完整和成熟,故我们对礼券号的的生成需求也是一块心病。

下面再说说雪花算法生成的ID,比较适合使用一些流水数据,如果分布式上生成时就需要考虑一台吞吐量好的服务统一生成ID,或者也可以进行多台服务器+负载均衡,当然每台机器出的ID还是需要标识补位(比如机器自定义的编号ID)增加长度防止同一时间重复ID。

以上如有不对之处请留言,大家共同学习进步!!!

【高性能】生成唯一时间戳ID,如果性能不高可以不用来看