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

文章插图
如果想把时间序放在前面,可以生成后改变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; } }
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 在Linux系统上使用ls命令对文件列表进行排序
- JetBrains 2020 年开发者生态系统状况报告,JAVA 最受欢迎的语言
- 日志系统新贵Loki,确实比笨重的ELK轻
- CentOS7下简单搭建Prometheus+Grafana监控系统
- Linux-玩转系统提示符PS1
- Linux系统 交换分区swap的管理
- 这几种常见的“分布式锁”写法,搞懂再也不怕面试官,安排
- Windows 10系统更新又出BUG,据说很多人都中招了,附解决办法
- 提升系统 10 倍web应用性能的 10 个建议
- Win10系统中进入BIOS的详细操作方法
