引入依赖:

     <dependency><groupId>com.robert.vesta</groupId><artifactId>vesta-service</artifactId><version>0.0.1</version></dependency><dependency><groupId>com.robert.vesta</groupId><artifactId>vesta-intf</artifactId><version>0.0.1</version></dependency>

jar包需要自己根据源码打包:源码地址:https://github.com/iweisi/vesta-id-generator

也可以下载:https://download.csdn.net/download/lyf_ldh/11303673

或者留言说明

vesta-rest.properties配置:

vesta.machine=1021  # 机器ID
vesta.genMethod=0   # 生成方式,0表示 嵌入发布模式 1表示 中心服务器发布模式 2表示 REST发 布模式
vesta.type=1        # ID类型,1表示最小粒度型  0表示最大峰值

引入 vesta-rest-main.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><beanclass="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="locations" value="classpath:vesta-rest.properties"/></bean><bean id="idService" class="com.robert.vesta.service.factory.IdServiceFactoryBean"init-method="init"><property name="providerType" value="PROPERTY"/><property name="type" value="${vesta.type}"/><property name="genMethod" value="${vesta.genMethod}"/><property name="machineId" value="${vesta.machine}"/></bean></beans>

创建一个 Config配置类来将 vesta-rest-main.xml:

@Configuration
@ImportResource( locations = { "classpath:ext/vesta/vesta-rest-main.xml" } )
public class UidConfig {
}

编写 Vesta Service

这里面包含的是和 ID生成器相关的几个重要工具接口,主要有:

  • genId 生成全局唯一 ID号
  • explainId 反解全局唯一 ID号,得到可以解释 ID号含义的 JSON数据
  • makeId 手工制造 ID
  • transTime对产生的日期反解
@Service
public class UidService {@Resourceprivate IdService idService;public long genId() {return idService.genId();}public Id explainId( long id ) {return idService.expId(id);}public long makeId( long version, long type, long genMethod, long machine, long time, long seq ) {long madeId = -1;if (time == -1 || seq == -1)throw new IllegalArgumentException( "Both time and seq are required." );else if (version == -1) {if (type == -1) {if (genMethod == -1) {if (machine == -1) {madeId = idService.makeId(time, seq);} else {madeId = idService.makeId(machine, time, seq);}} else {madeId = idService.makeId(genMethod, machine, time, seq);}} else {madeId = idService.makeId(type, genMethod, machine, time, seq);}} else {madeId = idService.makeId(version, type, genMethod, time,seq, machine);}return madeId;}}

编写测试 Controller:

@RestController
public class UidController {@Autowiredprivate UidService uidService;@RequestMapping(value = "/genid",method = RequestMethod.GET)public long genId() {return uidService.genId();}@RequestMapping(value ="/expid/{id}",method = RequestMethod.GET)public Id explainId(@PathVariable("id") long id) {return uidService.explainId( id );}@RequestMapping(value ="/makeid",method = RequestMethod.GET)public long makeId(@RequestParam(value = "version", defaultValue = "-1") long version,@RequestParam(value = "type", defaultValue = "-1") long type,@RequestParam(value = "genMethod", defaultValue = "-1") long genMethod,@RequestParam(value = "machine", defaultValue = "-1") long machine,@RequestParam(value = "time", defaultValue = "-1") long time,@RequestParam(value = "seq", defaultValue = "-1") long seq) {return uidService.makeId( version, type, genMethod, machine, time, seq );}
}

Vesta 0.0.2 版本
Vesta 0.0.1 版本已经能提供高效服务,但是对服务器的时钟有一定的要求,如果出现时钟回拨,Vesta 在此期间会拒绝提供服务。

所以 0.0.2 版本首先从解决该问题出发,然后又完善了各个接口的自定义配置和主键元数据的细粒度配置。

1. 通过切换机器ID解决时钟回拨
解决思路:

如果我们针对一个提供服务的Vesta配置多个机器ID,那么当出现时钟回拨时,可以按照机器ID的顺序和一定的规则切换当前的机器ID。这样就能通过机器ID位的不同来避免主键重复。虽然在整体的顺序上会因为时间位出现倒退,对大多数系统来说没有任何影响。

所以这种思路就是为了保证主键不重复,忽略时间对整体顺序的影响。
vesta-rest-main.xml配置:

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="idService" class="com.robert.vesta.service.impl.MachineIdsIdServiceImpl"init-method="init"><property name="machineIdProvider" ref="propertyMachineIdsProvider"/></bean><bean id="propertyMachineIdsProvider"class="com.robert.vesta.service.impl.provider.PropertyMachineIdsProvider"><property name="machineIds" value="1,2,3,4,5"/></bean></beans>

MachineIdsIdServiceImpl 的功能不只是简单的切换机器ID,在每次切换的时候还会把当前的机器ID和最近的一个时间戳保存到本地文件中,因此当所有机器ID都使用一轮后。本地文件中记录了所有机器ID以及最后使用的时间戳。当时钟再次出现回拨时,会根据这些信息找到一个满足 最后使用的时间戳 < 当前时间戳 的机器 ID。使用这种方式时,基本可以避免各种情况的时钟回拨。

2. 自定义主键配置(IdMeta)
Vesta 原来提供了两种可选的类型,根据时间的位数和序列号的位数,可分为最大峰值型和最小粒度型。

public enum IdType {MAX_PEAK("max-peak"),MIN_GRANULARITY("min-granularity");private String name;private IdType(String name) {this.name = name;}......
}

1. 最大峰值型(seconds):采用秒级有序,秒级时间占用30位,序列号占用20位

字段 版本 类型 生成方式 秒级时间 序列号 机器ID
位数 63 62 60-61 30-59 10-29 0-9

2. 最小粒度型(milliseconds):采用毫秒级有序,毫秒级时间占用40位,序列号占用10位

字段 版本 类型 生成方式 毫秒级时间 序列号 机器ID
位数 63 62 60-61 20-59 10-19 0-9

最大峰值型能够承受更大的峰值压力,但是粗略有序的粒度有点大,最小粒度型有较细致的粒度,但是每个毫秒能承受的理论峰值有限,为1k,同一个毫秒如果有更多的请求产生,必须等到下一个毫秒再响应。

ID类型在配置时指定,需要重启服务才能互相切换。
0.0.2 版本后,可以通过设置 type 为 seconds(秒) 或 milliseconds(毫秒)来选择上面两种类型。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="idService" class="com.robert.vesta.service.impl.IdServiceImpl"init-method="init"><constructor-arg value="max-peak"/><property name="machineIdProvider" ref="propertyMachineIdProvider"/></bean><bean id="propertyMachineIdProvider" class="com.robert.vesta.service.impl.provider.PropertyMachineIdProvider"><property name="machineId" value="1"/></bean></beans>

除了默认的两种方式外,还可以更灵活的自定义,自定义方式如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="idService" class="com.robert.vesta.service.impl.IdServiceImpl"init-method="init"><property name="machineIdProvider" ref="propertyMachineIdProvider"/><property name="idMeta" ref="idMeta"/></bean><bean id="idMeta" class="com.robert.vesta.service.impl.bean.IdMeta"><constructor-arg value="16"/><constructor-arg value="14"/><constructor-arg value="30"/><constructor-arg value="2"/><constructor-arg value="1"/><constructor-arg value="1"/></bean><bean id="propertyMachineIdProvider"class="com.robert.vesta.service.impl.provider.PropertyMachineIdProvider"><property name="machineId" value="1"/></bean></beans>

上述配置中 IdMeta 自定义配置如下

字段 版本 类型 生成方式 秒级时间 序列号 机器ID
位数 63 62 60-61 30-59 16-29 0-15

特别注意

在选择 seconds 时,如果时间位是 30,使用((1<<30)-1)/(365*24*3600) 可以计算出当前配置可以使用多少年(此例是34年,还需要考虑 Timer 中定义的 EPOCH,这个值 0.0.2 中也能自定义了)。

在选择 milliseconds 时,如果时间位是 30,使用((1<<30)-1)/(365*24*3600000) 可以计算出当前配置可以使用多少年(此例是 298 小时,只够使用 12 天,并且由于 EPOCH 的缘故,该配置已经过期了,在启动时会抛出异常)。

自定义实现
Vesta 提供了以下接口,都可以通过配置替换为自己的实现。

IdConvert 接口,根据 IdMeta 和 Id 的信息转换为 Long 类型的值。
IdPopulator 接口,用于根据 Timer 生成 Id 的基础数据。
ResetPopulator 接口,配合 IdPopulator 使用,当使用可切换机器ID的方式运行时,用于重置 IdPopulator 的状态。
MachineIdProvider 和 MachineIdsProvider 接口,用于提供机器 ID,第二个用于可切换机器ID时使用。
Timer 接口,处理时间戳生成的方式。

源码分析:

IdServiceImpl通过构造调用父类的构造:
    public IdServiceImpl(String type) {super(type);this.initPopulator();}
父类构造:public AbstractIdServiceImpl(String type) {this.idType = IdType.parse(type);}

init-method使用的是父类的方法:

public void init() {this.machineId = this.machineIdProvider.getMachineId();if (this.machineId < 0L) {this.log.error("The machine ID is not configured properly so that Vesta Service refuses to start.");throw new IllegalStateException("The machine ID is not configured properly so that Vesta Service refuses to start.");} else {if (this.idMeta == null) {this.setIdMeta(IdMetaFactory.getIdMeta(this.idType));this.setType(this.idType.value());} else if (this.idMeta.getTimeBits() == 30) {this.setType(0L);} else {if (this.idMeta.getTimeBits() != 40) {throw new RuntimeException("Init Error. The time bits in IdMeta should be set to 30 or 40!");}this.setType(1L);}this.setIdConverter(new IdConverterImpl(this.idMeta));}}

这个是版本0.0.1中的方法,0.0.2中会对这个方法做改进,对else if增加自定义的判断和对枚举类IdType增加自定类型,这样就能够使用自定义的IdMeta,暂时没找到0.0.2版本,自己根据需要可以对源码进行改进,重新编译为jar包。

全局唯一id生成器----Vesta相关推荐

  1. Spring Boot 工程集成全局唯一ID生成器 Vesta

    2019独角兽企业重金招聘Python工程师标准>>> 本文内容脑图如下: 文章共 760字,阅读大约需要 2分钟 ! 概 述 在前一篇文章 <Spring Boot工程集成全 ...

  2. 基于百度的UidGenerator改造的全局唯一id生成器

    其实百度的UidGenerator生成器也是基于snowflake算法的,在原生的项目中使用的基于数据库的,我改造成了基于zookpeer的,用zookpeer的序列号实现分布式seq的生成(代替了算 ...

  3. 分布式全局唯一 ID生成器(百度UidGenerator)

    文章目录 为什么要使用全局ID生成器? 使用UUID作为主键? 使用数据库主键自增? UidGenerator简介 雪花算法snowflake SpringBoot整合百度UidGenerator 为 ...

  4. springboot项目创建全局唯一id生成器

    springboot项目创建全局唯一id生成方法,参考 Snowflake算法 yml文件 #app 全局唯一id生成 app:idGenerator:workerId: 1datacenterId: ...

  5. 【Redis】解决全局唯一 id 问题

    永远要记得坚持的意义 一.全局唯一 id 场景 概念: 以订单表的 id 为例 使用自增 id 会产生的问题: id 的规律性太明显,容易让用户猜测到一些信息 受表单数据量的限制 -- 分布式存储时, ...

  6. 唯一ID生成器snowflake

    分布式全局唯一ID生成器 很多场景需要使用全局唯一ID,用来标识唯一一条消息,唯一一笔交易,唯一一个用户,唯一一张图片等等. 传统数据库表的自增主键是很简单的一种实现方式,前提是你没有分库,也没有分表 ...

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

    大家好,我是猿人(猿码天地创始人),今天给码农们或即将成为码农或想成为码农的朋友讲讲SpringBoot集成百度uid-generator唯一ID生成器,现在是深夜23:10分,猿人最擅长熬夜,就是不 ...

  8. Redis生成全局唯一ID

    简介: 全局唯一ID生成器是一种在分布式系统下用来生成全局唯一ID的工具 特性: 唯一性 高性能 安全性 高可用 递增性 生成规则: 有时为了增加ID的安全性,我们可以不直接使用Redis自增的数值, ...

  9. SnowFlake唯一ID生成器

    写在前面 架构是权衡的结果,架构也是一层层的组件拼接起来的,如果没有好用的组件,架构势必会做阉割,架构的理想态是建立在一堆友好.易用.标准化的组件之上的.在我过去的经验中,有两类组件经常会出现在我的架 ...

最新文章

  1. SpringJpa多对多映射关系
  2. 多视图立体匹配论文分享CasMVSNet
  3. CVPR2018上关于目标检测(object detection)
  4. 微软和谷歌的人工智能,在SuperGLUE基准测试中超越了人类
  5. python3 http.server 本地服务支持跨域
  6. numpy练习100道题
  7. 在.NET Core中使用Exceptionless分布式日志收集框架
  8. c语言编程数学黑洞,一个数学黑洞——6174
  9. 项目部署—移除Spring Boot内置Tomcat,部署到云服务器Tomcat
  10. mysql undo log回收_MySQL5.7 可以回收(收缩)undo log回滚日志物理文件空间
  11. [ZJOI2008]泡泡堂
  12. 计算机二级c语言模拟题,2016下半年计算机二级C语言模拟试题及答案
  13. 简单介绍Javascript匿名函数和面向对象编程
  14. HDU-2063-过山车(最大匹配)
  15. Java搭建网站相关知识整理(新手上路)
  16. Java连接数据库驱动包下载
  17. matlab 实现排序
  18. win10硬盘读写速度测试-crystaldiskmark
  19. 无线网卡插到服务器 没有反应,无线网卡插上没反应怎么办
  20. 60个有趣的经济学定律!

热门文章

  1. 4K 蓝光影片规范出炉,定名 Ultra HD Blu-ray
  2. 2018-05-10 面试上海宝信软件的心得
  3. 直播带货app源码搭建,从直播CDN原理说起
  4. Linux系统Deepin/Ubuntu解决IDEA输入中文光标无法跟随的问题
  5. 百度网盘非会员转存文件的正确姿势
  6. 织田信长《人间五十年》
  7. C#中纯代码实现界面设计,不受VS中的拖拽图像界面限制
  8. 中国石油大学《机械电气安全技术(含课程设计)》第一阶段作业
  9. iOS 解决 dyld: Library not loaded: /System/Library/Frameworks/CoreMedia.framework/CoreMedia
  10. ImageMagick windows历史版本