【高性能】生成唯一时间戳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 == 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。

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

时间: 2024-08-11 09:49:32

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

js生成唯一的id

1.生成[0,1)的随机数的Math.random Math.random().toString().replace(".", "");// 生成唯一的id 原文地址:https://www.cnblogs.com/ilimengyang/p/8986615.html

C#生成唯一的ID保存到数据库

直接用.NET Framework 提供的 Guid() 函数: Guid.NewGuid()是指生成唯一码的规则 System.Guid.NewGuid().ToString()全球唯一标识符 (GUID) 是一个字母数字标识符 System.Guid.NewGuid().ToString(format):生成的ID值的格式: 说明符       返回值的格式   N                  32   位: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx   D  

利用python的标准库hashlib 的md5()生成唯一的id

1 import hashlib 2 import time 3 4 def generate_md5(): 5 m = hashlib.md5() 6 m.update(bytes(str(time.perf_counter()),encoding='utf8')) #perf_counter() 可以精确到纳秒级别(保证不会重名) 7 return m.hexdigest() 8 9 class School(): 10 def __init__(self,s_id,name,addr):

Java生成唯一的ID

public class UIDGenerator { private static Date date = new Date(); private static StringBuilder buf = new StringBuilder(); private static int seq = 0; private static final int ROTATION = 99999; public static synchronized long next(){ if (seq > ROTATI

生成唯一的ID

public class UniqueId { public static String getUUId(){ int machineld = 1; int hashCodeV = UUID.randomUUID().toString().hashCode(); if(hashCodeV<0){ hashCodeV = - hashCodeV; } return machineld+String.format("%015d",hashCodeV); } } 原文地址:https:

如何生成唯一且不可预测的 ID

通常数据库可以生成唯一的 ID,最多的就是数字序列,也有像 MongoDB 这样产生组合序列的,不过这种形式的 ID 由于是序列,是可以预测的.如果想得到不可预测且唯一的 ID,方法还是有的. 下面主要以 Node.js 的环境为例. Node-uuid Github 上有个 node-uuid 项目,它可以快速地生成符合 RFC4122 规范 version 1 或者 version 4 的 UUID. 安装,既可以通过 npm install node-uuid ,也可以在 package.

C#生成唯一值的方法汇总

生成唯一值的方法很多,下面就不同环境下生成的唯一标识方法一一介绍,作为工作中的一次总结,有兴趣的可以自行测试: 一.在 .NET 中生成 1.直接用.NET Framework 提供的 Guid() 函数,此种方法使用非常广泛.GUID(全局统一标识符)是指在一台机器上生成的数字,它保证对在同一时空中的任何两台计算机都不会生成重复的 GUID 值(即保证所有机器都是唯一的).关于GUID的介绍在此不作具体熬述,想深入了解可以自行查阅MSDN.代码如下: 1 using System; 2 usi

PHP获取时间戳和微秒数以及生成唯一ID

microtime函数 描述:返回当前Unix时间戳和微秒数 语法:mixed microtime( [ bool $get_as_float ] ) //直接输出 echo microtime(); //得到的是 如:0.26672100 1585622985 前面是当前微秒数,后面是正常时间戳,中间以空格分隔开 //如果带有参数(布尔型参数) echo microtime(true); //输出结果:1585623020.7408 刚才的微秒数就会以浮点数的形式表现在原有的时间戳之后 浮点数

生成唯一id

有时候在某些业务中需要先生成一个唯一id,然后再进行存储.可以使用一下的方法: 1.借助mysql或者redis这类能够自增的数据库 这种方式可以满足需求但是需要跟数据库有一次额外的操作.对性能有一定的影响 2.毫秒级的时间加上一个随机数. 这种方式不需要借助数据,性能高些,但是随机数可能会重复,所以结果可能不是全局唯一的 3.毫秒级的时间加上进程id 这种方式可以既满足性能,又是唯一的 对于多核的cpu,每个cpu可以同时执行不同的进程,而每个进程有唯一的id,所以时间可能相同,但是进程的id