Springboot整合百度开源分布式ID生成器UIDGenerator

环境:sprinboot2.3.12.RELEASE uid-generator1.0.0


简介

UidGenerator是Java实现的, 基于Snowflake算法的唯一ID生成器。UidGenerator以组件形式工作在应用项目中, 支持自定义workerId位数和初始化策略, 从而适用于docker等虚拟化环境下实例自动重启、漂移等场景。 在实现上, UidGenerator通过借用未来时间来解决sequence天然存在的并发限制; 采用RingBuffer来缓存已生成的UID, 并行化UID的生产和消费, 同时对CacheLine补齐,避免了由RingBuffer带来的硬件级「伪共享」问题. 最终单机QPS可达600万。

依赖版本:Java8及以上版本, MySQL(内置WorkerID分配器, 启动阶段通过DB进行分配; 如自定义实现, 则DB非必选依赖)

Snowflake算法

Snowflake算法描述:指定机器 & 同一时刻 & 某一并发序列,是唯一的。据此可生成一个64 bits的唯一ID(long)。默认采用上图字节分配方式:

  • sign(1bit) 固定1bit符号标识,即生成的UID为正数。

  • delta seconds (28 bits) 当前时间,相对于时间基点'2016-05-20'的增量值,单位:秒,最多可支持约8.7年

  • worker id (22 bits) 机器id,最多可支持约420w次机器启动。内置实现为在启动时由数据库分配,默认分配策略为用后即弃,后续可提供复用策略。

  • sequence (13 bits) 每秒下的并发序列,13 bits可支持每秒8192个并发。

以上参数均可通过Spring进行自定义

CachedUidGenerator

RingBuffer环形数组,数组每个元素成为一个slot。RingBuffer容量,默认为Snowflake算法中sequence最大值,且为2^N。可通过boostPower配置进行扩容,以提高RingBuffer 读写吞吐量。

Tail指针、Cursor指针用于环形数组上读写slot:

  • Tail指针 表示Producer生产的最大序号(此序号从0开始,持续递增)。Tail不能超过Cursor,即生产者不能覆盖未消费的slot。当Tail已赶上curosr,此时可通过rejectedPutBufferHandler指定PutRejectPolicy

  • Cursor指针 表示Consumer消费到的最小序号(序号序列与Producer序列相同)。Cursor不能超过Tail,即不能消费未生产的slot。当Cursor已赶上tail,此时可通过rejectedTakeBufferHandler指定TakeRejectPolicy

CachedUidGenerator采用了双RingBuffer,Uid-RingBuffer用于存储Uid、Flag-RingBuffer用于存储Uid状态(是否可填充、是否可消费)

由于数组元素在内存中是连续分配的,可最大程度利用CPU cache以提升性能。但同时会带来「伪共享」FalseSharing问题,为此在Tail、Cursor指针、Flag-RingBuffer中采用了CacheLine 补齐方式。

RingBuffer填充时机

  • 初始化预填充 RingBuffer初始化时,预先填充满整个RingBuffer.

  • 即时填充 Take消费时,即时检查剩余可用slot量(tail - cursor),如小于设定阈值,则补全空闲slots。阈值可通过paddingFactor来进行配置,请参考Quick Start中CachedUidGenerator配置

  • 周期填充 通过Schedule线程,定时补全空闲slots。可通过scheduleInterval配置,以应用定时填充功能,并指定Schedule时间间隔

以上为百度的官方介绍,接下来我们将其整合到Springboot项目中

UIDGenerator下载

在下面地址下载uid-generator

UIDGenerator环境配置

创建表

DROP TABLE IF EXISTS WORKER_NODE;CREATE TABLE WORKER_NODE( ID BIGINT NOT NULL AUTO_INCREMENT COMMENT 'auto increment id', HOST_NAME VARCHAR(64) NOT NULL COMMENT 'host name', PORT VARCHAR(64) NOT NULL COMMENT 'port', TYPE INT NOT NULL COMMENT 'node type: ACTUAL or CONTAINER', LAUNCH_DATE DATE NOT NULL COMMENT 'launch date', MODIFIED TIMESTAMP NOT NULL COMMENT 'modified time', CREATED TIMESTAMP NOT NULL COMMENT 'created time', PRIMARY KEY(ID))COMMENT='DB WorkerID Assigner for UID Generator',ENGINE = INNODB;

将其项目中的mapper.xml文件copy到自己项目中,对应的WorkerNodeEntity,WorkerNodeDAO,
DisposableWorkerIdAssigner都copy到自己的项目中。

DisposableWorkerIdAssigner主要是修改注入的dao,因为这里我们需要修改默认的dao相关的配置。

项目配置

依赖

<dependency>  <groupId>mysql</groupId>  <artifactId>mysql-connector-java</artifactId>  <scope>runtime</scope></dependency><dependency>  <groupId>org.mybatis.spring.boot</groupId>  <artifactId>mybatis-spring-boot-starter</artifactId>  <version>2.1.4</version></dependency><dependency>  <groupId>com.github.pagehelper</groupId>  <artifactId>pagehelper-spring-boot-starter</artifactId>  <version>1.3.0</version></dependency>

mybatis配置

pagehelper: helperDialect: mysql reasonable: true pageSizeZero: true offsetAsPageNum: true rowBoundsWithCount: true---mybatis: type-aliases-package: com.pack.domain mapper-locations: - classpath:/mappers/*.xml configuration: lazy-loading-enabled: false aggressive-lazy-loading: false

mapper文件中的namespace及对应domain修改为自己路径下的。

配置UIDGenerator

@Configurationpublic class UIDConfig {@Beanpublic DefaultUidGenerator defaultUidGenerator(DisposableWorkerIdAssigner disposableWorkerIdAssigner) {DefaultUidGenerator defaultUidGenerator = new DefaultUidGenerator() ;defaultUidGenerator.setWorkerIdAssigner(disposableWorkerIdAssigner) ;defaultUidGenerator.setTimeBits(29) ;defaultUidGenerator.setWorkerBits(21) ;defaultUidGenerator.setSeqBits(13) ;defaultUidGenerator.setEpochStr('2021-01-01') ;return defaultUidGenerator ;}}

注意这里的
DisposableWorkerIdAssigner是copy到自己项目中的,不是百度提供的。

@Componentpublic class DisposableWorkerIdAssigner implements WorkerIdAssigner { @Resource private WorkerNodeMapper workerNodeDAO; // other code}

到此所有的都配置完成了。

测试

@Resourceprivate DefaultUidGenerator uidGenerator ;@Testpublic void testGeneratorId() {  for (int i = 0; i < 10; i  ) {    System.out.println(uidGenerator.getUID()) ;  }}

完毕!!

(0)

相关推荐

  • 百度分布式ID生成器:uid-generator

    摘要:https://github.com/baidu/uid-generator   源码下载 百度的uid-generator产生就是基于这种情况做的(每次取一批回来,很好的思想,性能也非常不错) ...

  • Hive 自定义UDF函数实现日期格式化和字段AES加密

    Hive 自定义UDF函数实现日期格式化和字段AES加密 自定义日期格式化UDF函数 自定义字段AES加密函数 函数的临时注册和永久注册 测试UDF函数使用 项目pom.xml 自定义日期格式化UDF ...

  • 手把手教你使用Java开发在线生成pdf文档

    一.介绍 在实际的业务开发的时候,研发人员往往会碰到很多这样的一些场景,需要提供相关的电子凭证信息给用户,例如网银/支付宝/微信购物支付的电子发票.订单的库存打印单.各种电子签署合同等等,以方便用户查 ...

  • 手把手教你SpringBoot整合MybatisPlus 代码生成器

    一.在pom.xml中添加所需依赖 <!-- MyBatis-Plus代码生成器--><dependency> <groupId>com.baomidou</ ...

  • 来吧,自己动手撸一个分布式ID生成器组件

    在经过了众多轮的面试之后,小林终于进入到了一家互联网公司的基础架构组,小林目前在公司有使用到架构组研究到分布式id生成器,前一阵子大概看了下其内部的实现,发现还是存在一些架构设计不合理之处.但是又由于 ...

  • SpringBoot整合分布式事务,JTA+Atomikos实现多数据源

    在整合MySQL,JDBCTemplate这篇中的结尾,我们成功的向两个数据库中分别添加了一条数据.但是我们思考一下,如果PetsServiceImpl.java中的savePets()中如果发生异常 ...

  • SpringBoot整合Redis正确的实现分布式锁的示例代码

    前言 最近在做分块上传的业务,使用到了Redis来维护上传过程中的分块编号. 每上传完成一个分块就获取一下文件的分块集合,加入新上传的编号,手动接口测试下是没有问题的,前端通过并发上传调用就出现问题了 ...

  • 排名考前的基于SpringBoot搭建的开源项目

    SpringBoot一直是开发者比较青睐的一款轻量级框架,他不仅继承了Spring框架原有的优秀特性,而且还通过简化配置来进一步简化了Spring应用的整个搭建和开发过程. Halo Halo [ˈh ...

  • jackson学习之九:springboot整合(配置文件)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 系列文章汇总 jackson学习之一:基本信息 jac ...

  • Leaf——美团点评分布式ID生成系统

    背景 在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识.如在美团点评的金融.支付.餐饮.酒店.猫眼电影等产品的系统中,数据日渐增长,对数据分库分表后需要有一个唯一ID来标识一条数据或消息,数 ...

  • Microsoft Blazor Platz.SqlForms开源-使用架构生成器设计和维护SQL Server数据库

    当您需要为客户构建有效的原型或公司没有用于企业发展的预算时,您别无选择,并且需要使用一些捷径和生活技巧,通常是低代码或无代码方法.在这篇文章中,我提出了一种有趣的方法,它关于如何使用开源库Platz. ...