环境:sprinboot2.3.12.RELEASE+uid-generator1.0.0简介UidGenerator是Java实现的基于Snowflake算法的唯一ID生成器。UidGenerator以组件的形式工作在应用项目中,支持自定义workerId位数和初始化策略,适用于docker等虚拟化环境中实例自动重启、漂移等场景。在实现上,UidGenerator通过借用未来时间解决了序列固有的并发限制;使用RingBuffer缓存生成的UID,将UID的生产和消费并行化,同时对CacheLine进行补充,避免了RingBuffer带来的硬件层面的“伪共享”问题。最终单机QPS可达600万。依赖版本:Java8及以上,MySQL(内置WorkerID分配器,启动阶段通过DB分配;如果自定义实现,DB不是强制依赖)Snowflake算法Snowflake算法说明:指定机器&同时&某台并发序列,只有一个。以此为基础,可以生成一个64位的唯一ID(long)。默认采用上述字节分配方式:sign(1bit)固定1bit符号标识,即生成的UID为正数。deltaseconds(28bits)当前时间,相对于时间基点“2016-05-20”的增量值,单位:秒,最多可支持约8.7年workerid(22bits)machineid,可支持最多约420w次机器启动。内置实现由数据库在启动时分配。默认分配策略是一次性的,以后可以提供复用策略。sequence(13bits)每秒并发数序列,13位可以支持每秒8192个并发数。以上参数可以通过Spring自定义。CachedUidGeneratorRingBuffer环形数组,数组的每个元素成为一个槽。RingBuffer容量,默认为Snowflake算法中序列的最大值,为2^N。可以通过boostPower配置进行扩展,提高RingBuffer的读写吞吐量。Tail指针和Cursor指针用于读写环形数组上的槽:Tail指针表示Producer生产的最大序号(序号从0开始,不断递增)。Tail不能超过Cursor,即生产者不能覆盖未被消费的槽。当Tail追上curosr后,可以通过rejectedPutBufferHandler指定PutRejectPolicyCursor指针,表示Consumer消费的最小序号(序号顺序与Producer序号一致)。Cursor不能超过Tail,即不能消耗未产生的slot。当Cursor追上尾巴时,可以通过rejectedTakeBufferHandler指定TakeRejectPolicyCachedUidGenerator使用doubleRingBuffer,Uid-RingBuffer用于存储Uid,Flag-RingBuffer用于存储Uid状态(是否可以填充或消费),因为数组元素在内存中是连续分配的,可以最大限度地利用CPU缓存来提高性能。但同时也会带来“虚假分享”FalseSharing的问题。为此,在Tail、Cursor指针、Flag-RingBuffer中采用了CacheLine补全方式。RingBuffer填充时机Initializationpre-filling当RingBuffer被初始化时,整个RingBuffer被预填充。即时充值取消费时,实时查看剩余可用槽位(尾部-光标)。如果小于设定的阈值,则填充空闲槽。threshold可以通过paddingFactor进行配置,参考QuickStart中CachedUidGenerator的配置Periodicfilling通过Schedule线程,定时填充idleslots。scheduleInterval配置可以应用定时填充功能,指定Schedule时间间隔是百度官方介绍的。接下来我们将其集成到Springboot项目中。IDBIGINTNOTNULLAUTO_INCREMENTCOMMENT'autoincrementid',HOST_NAMEVARCHAR(64)NOTNULLCOMMENT'hostname',PORTVARCHAR(64)NOTNULLCOMMENT'port',TYPEINTNOTNULLCOMMENT'nodetype:ACTUALorCONTAINER',LAUNCH_DATEDATENOTNULLCOMMENT'launchdate',MODIFIEDTIMESTAMPNOTNULLCOMMENT'modifiedtime',CREATEDTIMESTAMPNOTNULLCOMMENT'createdtime',PRIMARYKEY(ID))COMMENT='DBWorkerIDAssignerforUIDGenerator',ENGINE=INNODB;将其项目中的mapper.xml文件复制到自己的项目中,将对应的WorkerNodeEntity、WorkerNodeDAO、DisposableWorkerIdAssigner复制到自己的项目中。DisposableWorkerIdAssigner主要是修改注入的dao,因为这里需要修改默认的dao相关配置。项目配置依赖
