实用向—总结一些唯一ID生成方式

实用向—总结一些唯一ID生成方式

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<10;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生成的方式的考量就需要更加全面,如并发量、持久化、获取方式等,都需要具体问题具体分析,这里不再深入探讨,希望本文对大家能有所帮助,其中如有不足与不正确的地方还望指出与海涵。

关注微信公众号,查看更多技术文章。

相关推荐

1、洛克王国冰冻状态
365需要什么系统

1、洛克王国冰冻状态

📅 06-29 👁️ 2833
索尼电视坏了换块屏比买台新的还贵?
365bet体育在线娱乐场

索尼电视坏了换块屏比买台新的还贵?

📅 06-29 👁️ 854
如何解决魔秀桌面取闪烁或崩溃的问题?
365bet体育在线娱乐场

如何解决魔秀桌面取闪烁或崩溃的问题?

📅 01-14 👁️ 5962