唯一ID在系统中是常用的,生成唯一ID的方式也有很多,各有各的优点,也有各自的缺点。
现在介绍几种常用的,系统时间,数据库方式,UUID,分布式(SnowFlake,Leaf,UID-generator,Redis,zk)等。
1、在单机程序中,可以利用系统时间来生成ID,这种方式理论上可以每秒最多1千个,如果是单体web系统集群部署方式,可以为每台机器加个标识。在并发比较低的情况下还是可以使用的。
SimpleDateFormatsdf=newSimpleDateFormat(yyyyMMddHHmmssSSSS);
Stringid=ORD+sdf.format(System.currentTimeMillis());
2、数据库方式,数据库方式比较简单,比如Oracle的序列,Mysql中的AUTO_INCREMENT等,这样可以生成唯一的ID,性能和稳定性依赖于数据库,如果数据库挂了,生成ID的服务就用不了了。在分布式的高并发系统中生成ID的服务需要支持高并发,高性能,此时可能就需要多台机器来支持,每台机器设置不同的初始值,且步长和机器数相等。比如有两台机器。设置步长step为2,Server1的初始值为1(1,3,5,7,9,11…)、Server2的初始值为2(2,4,6,8,10…),示意图如下:
数据库多台机器生成ID示意图3、UUID方式,UUID的十六个八位字节被表示为32个十六进制数字,以连字号分隔的五组来显示,形式为8-4-4-4-12,总共有36个字符(即三十二个英数字母和四个连字号),java.util.UUID类可以生成uuid。
UUIDuuid=UUID.randomUUID();
//da6feb86-f-49e0-bb48-fb
UUID的优点就是简单唯一,但是缺点也明显,就是无序和长度较长,占用空间;如果用做MySQL的主键,数据会按照主键进行排序,由于UUID的无序性,插入数据存在性能问题。
4、Redis可以用来在分布式环境中生成唯一ID,ID可以做到递增。优点就是支持高并发下获取ID,缺点就是依赖Redis,稳定性依赖Redis。
5、ZK生成唯一ID,可以通过顺序节点和版本号来生产唯一的ID。
6、Snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。把64-bit分别划分成多段,分开来标识序列号,工作机器和时间戳等
Snowflake1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截-开始时间截)得到的值),这里的开始时间截,一般是我们的id生成器开始使用的时间。41位的时间截,可以使用69年,年T=(1L41)/(L*60*60*24*)=位的数据机器位,可以部署在个节点,包括5位datacenterId和5位workerId。12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生个ID序号。理论上snowflake方案的QPS约为.6w/s。雪花算法的优点就是基本有序性和高性能,缺点就是时钟回拨,会产生重复的ID。
7、Leaf算法,leaf算计就是在一定程度上解决了数据库和雪花算法的问题。
第一种Leaf-segment方案,在使用数据库的方案上,做了如下改变:-1)原方案每次获取ID都得读写一次数据库,造成数据库压力大。改为利用proxyserver批量获取,每次获取一个segment(step决定大小)号段的值。用完之后再去数据库获取新的号段,可以大大地减轻数据库的压力。2)各个业务不同的发号需求用biz_tag字段来区分,每个biz-tag的ID获取相互隔离,互不影响。如果以后有性能需求需要对数据库扩容,不需要上述描述的复杂的扩容操作,只需要对biz_tag分库分表就行。通过双buffer做了优化,DB取号段的过程能够做到无阻塞,不需要在DB取号段的时候阻塞请求线程,即当号段消费到某个点时就异步的把下一个号段加载到内存中。而不需要等到号段用尽的时候才去更新号段。Leaf-snowflake方案完全沿用snowflake方案的bit位设计,通过写zk来校验时钟是否回拨,解决时钟回拨问题,
解决时钟回退的问题8、UID-generator是百度的开源ID生成算法。UidGenerator是Java实现的,基于Snowflake算法的唯一ID生成器。UidGenerator以组件形式工作在应用项目中,支持自定义workerId位数和初始化策略,从而适用于docker等虚拟化环境下实例自动重启、漂移等场景。在实现上,UidGenerator通过借用未来时间来解决sequence天然存在的并发限制;采用RingBuffer来缓存已生成的UID,并行化UID的生产和消费,同时对CacheLine补齐,避免了由RingBuffer带来的硬件级「伪共享」问题.最终单机QPS可达万。