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

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

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

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

  1.    /// <summary>
  2. /// 时间戳ID
  3. /// </summary>
  4. public class TimestampID
  5. {
  6. private long _lastTimestamp;
  7. private long _sequence; //计数从零开始
  8. private readonly DateTime? _initialDateTime;
  9. private static TimestampID _timestampID;
  10. private const int MAX_END_NUMBER = 9999;
  11.  
  12. private TimestampID(DateTime? initialDateTime)
  13. {
  14. _initialDateTime = initialDateTime;
  15. }
  16.  
  17. /// <summary>
  18. /// 获取单个实例对象
  19. /// </summary>
  20. /// <param name="initialDateTime">最初时间,与当前时间做个相差取时间戳</param>
  21. /// <returns></returns>
  22. public static TimestampID GetInstance(DateTime? initialDateTime = null)
  23. {
  24. if (_timestampID == null) Interlocked.CompareExchange(ref _timestampID, new TimestampID(initialDateTime), null);
  25. return _timestampID;
  26. }
  27.  
  28. /// <summary>
  29. /// 最初时间,作用时间戳的相差
  30. /// </summary>
  31. protected DateTime InitialDateTime
  32. {
  33. get
  34. {
  35. if (_initialDateTime == null || _initialDateTime.Value == DateTime.MinValue) return new DateTime(, , , , , , DateTimeKind.Utc);
  36. return _initialDateTime.Value;
  37. }
  38. }
  39. /// <summary>
  40. /// 获取时间戳ID
  41. /// </summary>
  42. /// <returns></returns>
  43. public string GetID()
  44. {
  45. long temp;
  46. var timestamp = GetUniqueTimeStamp(_lastTimestamp, out temp);
  47. return $"{timestamp}{Fill(temp)}";
  48. }
  49.  
  50. private string Fill(long temp)
  51. {
  52. var num = temp.ToString();
  53. IList<char> chars = new List<char>();
  54. for (int i = ; i < MAX_END_NUMBER.ToString().Length - num.Length; i++)
  55. {
  56. chars.Add('');
  57. }
  58. return new string(chars.ToArray()) + num;
  59. }
  60.  
  61. /// <summary>
  62. /// 获取一个时间戳字符串
  63. /// </summary>
  64. /// <returns></returns>
  65. public long GetUniqueTimeStamp(long lastTimeStamp, out long temp)
  66. {
  67. lock (this)
  68. {
  69. temp = 1;
  70. var timeStamp = GetTimestamp();
  71. if (timeStamp == _lastTimestamp)
  72. {
  73. _sequence = _sequence + ;
  74. temp = _sequence;
  75. if (temp >= MAX_END_NUMBER)
  76. {
  77. timeStamp = GetTimestamp();
  78. _lastTimestamp = timeStamp;
  79. temp = _sequence = 1;
  80. }
  81. }
  82. else
  83. {
  84. _sequence = 1;
  85. _lastTimestamp = timeStamp;
  86. }
  87. return timeStamp;
  88. }
  89. }
  90.  
  91. /// <summary>
  92. ///
  93. /// </summary>
  94. /// <returns></returns>
  95. private long GetTimestamp()
  96. {
  97. if (InitialDateTime >= DateTime.Now) throw new Exception("最初时间比当前时间还大,不合理");
  98. var ts = DateTime.UtcNow - InitialDateTime;
  99. return (long)ts.TotalMilliseconds;
  100. }
  101. }

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

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

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

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

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

2017.1.22 > 在生产环境中,突然又发生了礼券号重复问题,导致我怀疑算法的不严谨,后来发现触发生成的来源是两个服务进程,哈哈,真是自己找坑跳;故大家在部署时候一定要确保ID生成在一个进程里,如果分布式还是老话,加上必要的分布标识NO

【高性能】生成唯一时间戳ID,1毫秒预计能生成1000个的更多相关文章

  1. 生成唯一的id(转)

    很多朋友都利用md5()来生成唯一的编号,但是md5()有几个缺点:1.无序,导致数据库中排序性能下降.2.太长,需要更多的存储空间.其实PHP中自带一个函数来生成唯一的id,这个函数就是uniqid ...

  2. js生成唯一的id

    1.生成[0,1)的随机数的Math.random Math.random().toString().replace(".", "");// 生成唯一的id 2 ...

  3. 据时间生成唯一序列ID

    据时间生成唯一序列ID /** * <html> * <body> * <P> Copyright 1994 JsonInternational</p> ...

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

    直接用.NET Framework 提供的 Guid() 函数: Guid.NewGuid()是指生成唯一码的规则 System.Guid.NewGuid().ToString()全球唯一标识符 (G ...

  5. java生成唯一的id编号

    GUID是一个128位长的数字,一般用16进制表示.算法的核心思想是结合机器的网卡.当地时间.一个随即数来生成GUID.从理论上讲,如果一台机器每秒产生10000000个GUID,则可以保证(概率意义 ...

  6. 生成唯一的ID

    public class UniqueId { public static String getUUId(){ ; int hashCodeV = UUID.randomUUID().toString ...

  7. Java生成唯一的ID

    public class UIDGenerator { private static Date date = new Date(); private static StringBuilder buf ...

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

    通常数据库可以生成唯一的 ID,最多的就是数字序列,也有像 MongoDB 这样产生组合序列的,不过这种形式的 ID 由于是序列,是可以预测的.如果想得到不可预测且唯一的 ID,方法还是有的. 下面主 ...

  9. 如何使用php生成唯一ID的4种方法

    php生成唯一ID的应用场景非常普遍,如临时缓存文件名称,临时变量,临时安全码等,uniqid()函数基于以微秒计的当前时间,生成一个唯一的 ID.由于生成唯一ID与微秒时间关联,因此ID的唯一性非常 ...

随机推荐

  1. xfire集成spring构建webservice

    前言:xfire.spring都是比较流行的技术,这里就不再赘述他们各自的优点:本文着重介绍xfire和spring的整合,不会做太深入的探究. 服务端 1. web.xml配置 spring配置部分 ...

  2. SSI框架总结

    先来点文字性的描写叙述: MVC对于我们来说,已经不陌生了,它起源于20世纪80年代针对smalltalk语言的一种软件设计模式,如今已被广泛应用.近年来,随着java的盛行,MVC的低耦合性.高重用 ...

  3. 用lucene.net根据关键字检索本地word文档

    目前在做一个winform小软件,其中有一个功能是能根据关键字检索本地保存的word文档.第一次是用com读取word方式(见上一篇文章),先遍历文件夹下的word文档,读取每个文档时循环关键字查找, ...

  4. 安装Oracle 9i - 初学者系列 - 学习者系列文章

    Oracle 9i数据库是经典的Oracle版本,就象SQL Server 2000一样.笔者最初使用到的Oracle版本就是Oracle 9i.下面就介绍下Oracle 9i的安装. 1.  下载O ...

  5. 我的CSS 入门1

    CSS(Cascading Style Sheets)级联样式表.我现在所知的,她的存在能够更好的管理多个HTML文件,或者是为了使得网页设计更为丰富多彩,“简单可依赖”. 如果你对HTML一无所知, ...

  6. MVC之验证

    MVC之验证 有时候我觉得,很多人将一个具体的技术细节写的那么复杂,我觉得没有必要,搞得很多人一头雾水的,你能教会别人用就成了,具体的细节可以去查MSDN什么的,套用爱因斯坦的名言:能在网上查到的就不 ...

  7. 迷你 MVC

    深入研究 蒋金楠(Artech)老师的 MiniMvc(迷你 MVC),看看 MVC 内部到底是如何运行的 2014-04-05 13:52 by 自由的生活, 645 阅读, 2 评论, 收藏, 编 ...

  8. ant svn

    <!-- 检出代码 这里使用 export 不是checkout 二者区别 checkout会svn相关信息文件检出,export只是检出最新的文件--> <target name= ...

  9. XMPP and SIP

    过去一年多,一直关注这方面的技术和发展,这里有一个简单的介绍,我觉得比较简洁明了.我做了一点翻译,还有我的一些评估.       SIP vs XMPP (Jabber) SIP and XMPP a ...

  10. 实现WebService的调用与被调用

    之前一直用WCF来开发服务,可是从未用过WebService.对WebService有种很神奇的期待,都说WebService比较简单,但是从未用过就对我来说就是一种新的知识.起始让我来说WCF与We ...