飞道的博客

SpringBoot集成百度uid-generator唯一ID生成器

640人阅读  评论(0)

大家好,我是猿人(猿码天地创始人),今天给码农们或即将成为码农或想成为码农的朋友讲讲SpringBoot集成百度uid-generator唯一ID生成器,现在是深夜23:10分,猿人最擅长熬夜,就是不怕掉头发!一切都是为了亲爱的粉丝朋友能学到知识,猿人熬夜也是值得的!

我是「猿码天地」,一个热爱技术、热爱编程的IT猿。技术是开源的,知识是共享的!

写作是对自己学习的总结和记录,如果您对 Java、分布式、微服务、中间件、Spring Boot、Spring Cloud等技术感兴趣,可以关注我的动态,我们一起学习,一起成长!

用知识改变命运,让家人过上更好的生活,互联网人一家亲!

Java知识学堂https://gitee.com/zhangbw666/it-knowledge

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

中文文档

https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md

官方源码

https://github.com/baidu/uid-generator

案例使用

全局ID生成器是服务化系统的基础设施,其在保障系统的正确运行和高可用方面发挥着重要作用。而关于全局ID生成算法首屈一指的当属 Snowflake雪花算法,然而 Snowflake本身很难在现实项目中直接使用,因此实际应用时需要一种可落地的方案。

UidGenerator 由百度开发,是Java实现的, 基于 Snowflake算法的唯一ID生成器。UidGenerator以组件形式工作在应用项目中, 支持自定义workerId位数和初始化策略, 从而适用于 docker等虚拟化环境下实例自动重启、漂移等场景。

本文就在项目中来集成 UidGenerator这一工程来作为项目的全局唯一 ID生成器。

案例源码地址:https://gitee.com/zhangbw666/uid-generator-boot

本案例主要是讲解springboot集成百度uid-generator唯一ID生成器,比如订单中心生成唯一订单号,可调用此服务生成全局唯一ID供业务使用。可作为单独的服务独立部署,做成一个微服务供其他服务调用。

  • 说明


   
  1. 升级spring boot 版本: 2.1 .10.RELEASE
  2. 升级 mybatis,mybatis-spring 版本
  3. 升级 mysql-connector-java 版本: 8.0 .12
  4. 升级 junit 版本
  • 启动入口

uid-provide 中的 UidProvideApplication
  • 浏览器访问

http://localhost:8080/uidGenerator
  • 返回全局UID

1071649247213936641

好了,以上步骤就是实现了全局ID的生成,通过调用http://localhost:8080/uidGenerator接口,即可很方便的生成全局ID,是不是很简单。接下来,我们需要讲解详细过程,先讲讲官方源码是怎样玩的。

官方源码实战

  • 创建数据库表

导入官网数据库SQL https://github.com/baidu/uid-generator/blob/master/src/main/scripts/WORKER_NODE.sql也就是一张表
我这里是在uid_generator库中,创建了这张表


   
  1. DROP TABLE IF EXISTS WORKER_NODE;
  2. CREATE TABLE WORKER_NODE
  3. (
  4. ID BIGINT NOT NULL AUTO_INCREMENT COMMENT  'auto increment id',
  5. HOST_NAME VARCHAR( 64) NOT NULL COMMENT  'host name',
  6. PORT VARCHAR( 64) NOT NULL COMMENT  'port',
  7. TYPE INT NOT NULL COMMENT  'node type: ACTUAL or CONTAINER',
  8. LAUNCH_DATE DATE NOT NULL COMMENT  'launch date',
  9. MODIFIED datetime NOT NULL COMMENT  'modified time',
  10. CREATED datetime NOT NULL COMMENT  'created time',
  11. PRIMARY KEY(ID)
  12. )
  13. COMMENT= 'DB WorkerID Assigner for UID Generator',ENGINE = INNODB;
  • mysql配置信息更改

因为升级到8.x ,配置文件部分也要跟着修改uid-generator 下,测试文件夹下的资源包uid/mysql.properties 以下修改为

mysql.driver=com.mysql.cj.jdbc.Driver

修改完成后,配置好数据库相关参数,这样单元测试即可执行成功。接下来,我们就讲讲在SpringBoot中如何基于百度uid-generator唯一ID生成器实现全局ID的生成。

案例详解

计划将全局生成唯一ID作为一个服务提供者,供其他微服务使用调用。这里创建了一个项目,项目中包含两个子项目一个是uid-generator官方本身,当然你也可以不需要放到本项目中,直接使用官方的自行打包即可,一个是uid-provide 服务提供者。以下说明的主要是服务提供者

  • 创建 子项目 uid-provide

POM配置文件如下


   
  1. <?xml version= "1.0" encoding= "UTF-8"?>
  2. <project xmlns= "http://maven.apache.org/POM/4.0.0" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
  3.          xsi:schemaLocation= "http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4.     <modelVersion> 4.0 .0</modelVersion>
  5.     <groupId>com.bowen</groupId>
  6.     <artifactId>uid-provide</artifactId>
  7.     <version> 1.0-SNAPSHOT</version>
  8.     <name>uid-provide</name>
  9.     <description>Demo project  for Spring Boot</description>
  10.     <parent>
  11.         <groupId>com.bowen</groupId>
  12.         <artifactId>uid-generator-boot</artifactId>
  13.         <version> 1.0-SNAPSHOT</version>
  14.     </parent>
  15.     <properties>
  16.         <java.version> 1.8</java.version>
  17.     </properties>
  18.     <dependencies>
  19.         <dependency>
  20.             <groupId>org.springframework.boot</groupId>
  21.             <artifactId>spring-boot-starter-web</artifactId>
  22.         </dependency>
  23.         <dependency>
  24.             <groupId>org.springframework.boot</groupId>
  25.             <artifactId>spring-boot-starter</artifactId>
  26.         </dependency>
  27.         <!-- for mybatis-->
  28.         <dependency>
  29.             <groupId>org.mybatis.spring.boot</groupId>
  30.             <artifactId>mybatis-spring-boot-starter</artifactId>
  31.             <version> 1.3 .2</version>
  32.         </dependency>
  33.         <!-- for Mysql-->
  34.         <dependency>
  35.             <groupId>mysql</groupId>
  36.             <artifactId>mysql-connector-java</artifactId>
  37.             <scope>runtime</scope>
  38.             <version> 8.0 .12</version>
  39.         </dependency>
  40.         <!-- druid -->
  41.         <dependency>
  42.             <groupId>com.alibaba</groupId>
  43.             <artifactId>druid-spring-boot-starter</artifactId>
  44.             <version> 1.1 .16</version>
  45.         </dependency>
  46.         <dependency>
  47.             <groupId>org.projectlombok</groupId>
  48.             <artifactId>lombok</artifactId>
  49.             <version>${lombok.version}</version>
  50.             <optional> true</optional>
  51.         </dependency>
  52.         <dependency>
  53.             <groupId>org.springframework.boot</groupId>
  54.             <artifactId>spring-boot-starter-test</artifactId>
  55.             <scope>test</scope>
  56.         </dependency>
  57.         <!-- uid-generator jar 包 -->
  58.         <dependency>
  59.             <groupId>com.bowen</groupId>
  60.             <artifactId>uid-generator</artifactId>
  61.             <version> 1.0-SNAPSHOT</version>
  62.         </dependency>
  63.     </dependencies>
  64.     <build>
  65.         <plugins>
  66.             <plugin>
  67.                 <groupId>org.springframework.boot</groupId>
  68.                 <artifactId>spring-boot-maven-plugin</artifactId>
  69.             </plugin>
  70.         </plugins>
  71.     </build>
  72. </project>
  • 复制 mapper

先在uid-provide项目资源包路径下创建mapper文件夹,然后到官方uid-generator资源包路径下META-INF/mybatis/mapper/WORKER_NODE.xml 复制WORKER_NODE.xml文件,粘贴到该文件夹mapper内。

  • cache id 配置文件

UidGenerator 有两个具体的实现类,分别是 DefaultUidGenerator 和 CachedUidGenerator,不过官方也推荐了对于性能比较敏感的项目应使用后者,因此本文也使用 CachedUidGenerator,而对于 DefaultUidGenerator不做过多阐述。

先在uid-provide项目资源包路径下创建uid文件夹,然后到官方uid-generator 测试 [注意:这里是测试资源包] 资源包路径下uid/cached-uid-spring.xml 复制cached-uid-spring.xml文件,粘贴到该文件夹uid内。


   
  1. <?xml version= "1.0" encoding= "UTF-8"?>
  2. <beans xmlns= "http://www.springframework.org/schema/beans" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
  3.        xsi:schemaLocation= "
  4.   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
  5.     <!-- UID generator -->
  6.     <bean id= "disposableWorkerIdAssigner" class= "com.baidu.fsg.uid.worker.DisposableWorkerIdAssigner" />
  7.     <bean id= "cachedUidGenerator" class= "com.baidu.fsg.uid.impl.CachedUidGenerator">
  8.         <property name= "workerIdAssigner" ref= "disposableWorkerIdAssigner" />
  9.         <property name= "epochStr" value= "2020-03-17"/>
  10.         <!-- 以下为可选配置, 如未指定将采用默认值 -->
  11.         <!-- RingBuffer size扩容参数, 可提高UID生成的吞吐量. -->
  12.         <!-- 默认: 3, 原bufferSize= 8192, 扩容后bufferSize=  8192 <<  3 =  65536 -->
  13.         <!--<property name= "boostPower" value= "3"></property>-->
  14.         <!-- 指定何时向RingBuffer中填充UID, 取值为百分比( 0100), 默认为 50 -->
  15.         <!-- 举例: bufferSize= 1024, paddingFactor= 50 -> threshold= 1024 *  50 /  100 =  512. -->
  16.         <!-- 当环上可用UID数量 <  512时, 将自动对RingBuffer进行填充补全 -->
  17.         <!--<property name= "paddingFactor" value= "50"></property>-->
  18.         <!-- 另外一种RingBuffer填充时机, 在Schedule线程中, 周期性检查填充 -->
  19.         <!-- 默认:不配置此项, 即不实用Schedule线程. 如需使用, 请指定Schedule线程时间间隔, 单位:秒 -->
  20.         <!--<property name= "scheduleInterval" value= "60"></property>-->
  21.         <!-- 拒绝策略: 当环已满, 无法继续填充时 -->
  22.         <!-- 默认无需指定, 将丢弃Put操作, 仅日志记录. 如有特殊需求, 请实现RejectedPutBufferHandler接口(支持Lambda表达式) -->
  23.         <!--<property name= "rejectedPutBufferHandler" ref= "XxxxYourPutRejectPolicy"></property>-->
  24.         <!-- 拒绝策略: 当环已空, 无法继续获取时 -->
  25.         <!-- 默认无需指定, 将记录日志, 并抛出UidGenerateException异常. 如有特殊需求, 请实现RejectedTakeBufferHandler接口(支持Lambda表达式) -->
  26.         <!--<property name= "rejectedPutBufferHandler" ref= "XxxxYourPutRejectPolicy"></property>-->
  27.     </bean>
  28. </beans>

最后根据需要配置参数,可以看官方说明。

  • 创建 spring boot 启动入口

主要就是加上注解@MapperScan("com.baidu.fsg.uid")mybatis能扫描到Mapper类的包的路径。


   
  1. package com.bowen;
  2. import org.mybatis.spring.annotation.MapperScan;
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. @SpringBootApplication
  6. @MapperScan( "com.baidu.fsg.uid")
  7. public class UidProvideApplication {
  8.  public static void main(String[] args) {
  9.   SpringApplication.run(UidProvideApplication.class, args);
  10.  }
  11. }
  • 创建配置


   
  1. package com.bowen.config;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.context.annotation.ImportResource;
  4. @Configuration
  5. @ImportResource(locations = {  "classpath:uid/cached-uid-spring.xml" })
  6. public class UidConfig {
  7. }
  • 创建服务接口


   
  1. package com.bowen.service;
  2. import com.baidu.fsg.uid.UidGenerator;
  3. import org.springframework.stereotype.Service;
  4. import javax.annotation.Resource;
  5. @Service
  6. public class UidGenService {
  7.     @Resource(name =  "cachedUidGenerator")
  8.     private UidGenerator uidGenerator;
  9.     public long getUid() {
  10.          return uidGenerator.getUID();
  11.     }
  12. }

主要说明一下@Resource(name = "cachedUidGenerator") 以往错误都是少了这里,没有标明注入来源

  • 控制器


   
  1. @RestController
  2. public class UidController {
  3.     @Autowired
  4.     private UidGenService uidGenService;
  5.     @GetMapping( "/uidGenerator")
  6.     public String UidGenerator() {
  7.          return String.valueOf(uidGenService.getUid());
  8.     }
  9. }
  • 项目配置文件


   
  1. server.port= 8080
  2. spring.datasource.url=jdbc:mysql: //localhost:3306/uid_generator?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
  3. spring.datasource.username=root
  4. spring.datasource.password= 123456
  5. spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
  6. mybatis.mapper-locations=classpath:mapper /*.xml
  7. mybatis.configuration.map-underscore-to-camel-case=true
  • 具体演示

我们每启动一次 Spring Boot工程,其即会自动去 MySQL数据的 WORKER_NODE表中插入一行关于工作节点的记录,类似下图所示:

接下来我们浏览器访问:http://localhost:8080/uidGenerator

OK,全局唯一全局IDID已经成功生成并返回!由于能力有限,若有错误或者不当之处,还请大家批评指正,一起学习交流!

到此,我们就实现了在SpringBoot中基于百度uid-generator唯一ID生成器实现全局ID的生成,我们将此项目部署到服务器中,独立成一个微服务,即可对外提供生成全局ID服务。

猿人于2021年3月13日 0点30分 于深圳整理,整理完这篇文章头发还有10万零550根,今天掉了一根头发,持续记录头发根数,加油!

你多学一样本事,就少说一句求人的话,现在的努力,是为了以后的不求别人,实力是最强的底气。记住,活着不是靠泪水博得同情,而是靠汗水赢得掌声。——《写给程序员朋友》 

点赞&在看是最大的支持

转载:https://blog.csdn.net/zbw125/article/details/114770695
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场