由于传统UUID序列号存在储存信息少、性能低、高并发下存在序列号重复的问题,所以经过技术探讨,决定基于SnowFlake算法,在其基础上进行技术创新,融入了全系统业务链路需要的订单日期数据及服务节点id,生成金融系统特色的tranceid;此ID具有以下优点:
1. 毫秒数在高位,自增序列在低位,整体处于递增趋势;
2. 容量大,可以做到秒级百万自增ID;
3. 根据自身业务扩展,可以灵活分配bit位。
同时基于原本SnowFlake算法的时钟回拨导致服务发号重复或者服务不可用问题做了技术优化,增加了数字段位,避免了服务器之间毫秒级误差引起时间回拨问题。
技术说明
在过往项目中,我司业务的唯一流水号用的是UUID,随着业务扩展,技术革新,该技术的短板越发明显:字符串占用空间较大、索引效率低、生成ID随机性、在高并发下重复几率大等问题;
经过技术小组讨论选型,决定初步使用SnowFlake生成traceID。雪花算法是技术不断革新的产物,它的出现是为了解决高并发环境下对于唯一ID生成的需求。
该算法生成的唯一ID主要分为5个部分组成:1位标识部分(在java中由于long的最高位是符号位,正数是0,负数是1,一般生成的ID为正数,所以为0)、41位时间戳部分(这个是毫秒级的时间,一般实现上不会存储当前的时间戳,而是时间戳的差值(当前时间-固定的开始时间),这样可以使产生的ID从更小值开始;41位的时间戳可以使用69年,(1L << 41) / (1000L 60 60 24 365) = 69年)
10位节点部分(前5位作为数据中心标识,后5位作为机器标识,可以部署1024个节点)、12位序列号部分(支持同一毫秒内同一个节点可以生成4096个ID)。
它的特点有以下几点:
1、能满足高并发分布式系统环境下ID不重复
2、生成效率高
3、基于时间戳,可以保证基本有序递增
4、不依赖于第三方的库或者中间件
5、生成的id具有时序性和唯一性
但是在原生的技术当中也存在一些问题,依赖机器时钟,如果机器时钟回拨,会导致重复ID生成。
对于该缺陷,我们在随机数层面增加了数字段位,避免了服务器之间毫秒级误差引起时间回拨,同时我们在ID生成源码中对当前时间和上一次时间进行了判断,如果当前时间小于上一次的时间那么肯定是发生了回拨:
1、如果时间回拨时间较短,比如配置5ms以内,那么可以直接等待一定的时间,让机器的时间追上来。
2、如果时间的回拨时间较长,我们不能接受这么长的阻塞等待,那么又有两个策略:
直接拒绝,抛出异常,打日志,通知RD时钟回滚。
利用扩展位,不同业务场景位数可能用不到那么多,我们可以把扩展位数利用起来,比如当这个时间回拨比较长的时候,我们不需要等待,直接在扩展位加1,2位的扩展位允许我们有3次大的时钟回拨,一般来说就够了,如果其超过三次我们还是选择抛出异常,打日志。
最后,我们在改ID中加入了全链路订单秒级时间戳,做到了所有订单日期的秒级业务跟踪和状态查询。