Redis Incr 命令会将 key 中储存的数字值增一。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。
这里以jedis为例提供两种自增ID的生成方式
第一种方式直接通过Incr命令获取自增ID
JedisUtils.incr("inc-test1")
第二张方式获取带有时间戳的唯一编码,时间细度为分钟
/**
* 基于Redis生成 时间+递增ID 的唯一编码
* @param key
* @return
*/
public static String getRedisTimeSeq(String key) {
String time = DateUtils.parseDateToStr("yyyyMMddHHmm",new Date());
StringBuilder sBuilder = new StringBuilder(time);
sBuilder.append(JedisUtils.incr(key+":"+time,120));//保证一分钟内KEY有效
return sBuilder.toString();
}
二、测试
下面我们从冲突率与时间性能上,对以上几种唯一ID的生成方式进行一个简单的测试,同时基于并发安全的考虑,测试分为单线程与多线程两种
// ---------------测试---------------
public static void main(String[] args) throws InterruptedException {
int length = 10000000;
SnowFlake snowFlake = new SnowFlake(1, 1);
final CountDownLatch countDownLatch = new CountDownLatch(10);
Map map = new ConcurrentHashMap();
long begin = System.currentTimeMillis();
for(int i=0;i) {
Thread thread = new Thread(new Runnable() {
public void run() {
for (int i = 0; i != 1000000; ++i) {
String str = String.valueOf(snowFlake.nextId());
// String str = StringUtils.getUUIDHashCode(); //根据UUID产生命令唯一标识 长度 32 字母数字组合
//
// String str = StringUtils.getOrderSeq();//根据UUID取hash值+随机数,产生命令唯一标识 长度 16位纯数字
//
// String str =StringUtils.getRandomHexString(); //长度16的16进制字符串
map.put(str, str);
}
countDownLatch.countDown();
}
});
thread.start();
}
countDownLatch.await();
System.out.println("冲突数为: " + (length - map.size()));
System.out.println("sync time: " + (System.currentTimeMillis() - begin));
Map map1 = new ConcurrentHashMap();
begin = System.currentTimeMillis();
for (int i = 0; i != length; ++i) {
String str = String.valueOf(snowFlake.nextId());
// String str = StringUtils.getUUIDHashCode();//根据UUID产生命令唯一标识
// String str = StringUtils.getOrderSeq();//根据UUID取hash值+随机数,产生命令唯一标识
// String str =StringUtils.getRandomHexString();
map1.put(str, str);
}
System.out.println("冲突数为: " + (length - map1.size()));
System.out.println("sync time: " + (System.currentTimeMillis() - begin));
}
测试结果如下:
生成方式 生成总数 并发 冲突数 耗时
UUID产生命令唯一标识
1000W 单线程 0 26166ms
UUID产生命令唯一标识
1000W 多线程 0 27915ms
根据UUID取hash值+随机数,产生命令唯一标识
1000W 单线程 0 25405ms
根据UUID取hash值+随机数,产生命令唯一标识
1000W 多线程 0 25023ms
十六位随机的十六进制字符串
1000W 单线程 0 25723ms
十六位随机的十六进制字符串
1000W 多线程 0 28094ms
雪花算法
1000W 单线程 0 10100ms
雪花算法
1000W 多线程 0 11713ms
针对 Redis Incr 命令进行了本地和局域网两种测试, 由于千万级数据耗时太长,数据量改为了百万级,结果如下:
生成方式 网络环境 生成总数 并发 冲突数 耗时 Redis Incr命令获取自增ID 本地 100W 单线程 0 72445ms Redis Incr命令获取自增ID 本地 100W 多线程 0 47879ms Redis Incr命令获取自增ID 局域网 100W 单线程 0 71447ms Redis Incr命令获取自增ID 局域网 100W 多线程 0 45888ms
Redis Incr命令生成 时间+递增ID 的唯一编码
局域网 100W 单线程 0 236795ms
Redis Incr命令生成 时间+递增ID 的唯一编码
局域网 100W 多线程 0 39281ms
可以看到Redis相比前面一些轻量级的ID生成方式,生成效率上有明显差距,但在分布式环境下,且业务场景对全局唯一ID的生成样式有要求, redis做为统一的ID生成器还是很有必要的。
由于测试受机器配置、网络带宽等条件影响,以上得出的结果只是一个简单的测试结果,证明这几种唯一ID生成方式具备一定的可用性,大家如果有兴趣可以进行更深入的测试与优化;
三、总结
其实在日常开发中唯一ID的的生成方式与整体服务的架构与复杂度是密切相关的,本文从并发安全、冲突率、性能等多个方面列举了几种唯一ID的生成方式,相对比较简单实用,但在更复杂的架构与业务场景下,对唯一ID生成的方式的考量就需要更加全面,如并发量、持久化、获取方式等,都需要具体问题具体分析,这里不再深入探讨,希望本文对大家能有所帮助,其中如有不足与不正确的地方还望指出与海涵。
关注微信公众号,查看更多技术文章。
Original: https://www.cnblogs.com/dafanjoy/p/13690888.html
Author: DaFanJoy
Title: 实用向—总结一些唯一ID生成方式
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/715077/
转载文章受原作者版权保护。转载请注明原作者出处!