通用 ID 产生器 Vesta

Vesta 发号器是一个通用的发号器,它不但可以嵌入在原生 Java 程序中,还可以作为 Restful 服务进行发布,你只需要简单的几个步骤就可以成功搭建 Vesta 的 Rest 服务,并且在任何语言中都可以使用 HTTP 协议来获取全局唯一的 ID。

关于 Vesta 的基本文档可以参考 Vesta 官网的介绍:

官网和项目都挂了,有需要的可以访问我 fork 的仓库:
https://gitee.com/free/vesta-id-generator

目前(20180330) Vesta 官网还是 0.0.1 版本的用法和介绍,本文主要介绍的是未来 0.0.2 版本增加和修改的各项内容。如果你已经在使用或者正在寻找一款稳定的发号器,来试试 Vesta。

Vesta 0.0.2 版本

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

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

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

解决思路:

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

所以这种思路就是为了保证主键不重复,忽略时间对整体顺序的影响。

保证时间有序可以采用缓存来解决,但是对于极低概率的时钟回拨来说,会导致频繁刷新缓存,缓存命中率极低,所以没有提供这种实现。

想要使用切换 ID 的这种策略,可以通过下面的配置启用:

<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.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 原来提供了两种可选的类型,根据时间的位数和序列号的位数,可分为最大峰值型和最小粒度型。

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

字段版本类型生成方式秒级时间序列号机器ID
位数636260-6140-5910-390-9

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

字段版本类型生成方式毫秒级时间序列号机器ID
位数636260-6120-5910-190-9

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

ID类型在配置时指定,需要重启服务才能互相切换。

0.0.2 版本后,可以通过设置 typeseconds(秒) 或 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="seconds"/>
        <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
位数636260-6130-5916-290-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 的缘故,该配置已经过期了,在启动时会抛出异常)。

计算单机最大理论峰值

例如这里的序列号是 14位,通过 1<<14-1 可以计算出最大峰值为 16383

总位数没有限制(<64)

默认提供的两种方式和这里的例子,都采用了64位的ID,实际上通过自定义时,不是必须满足 64 位,通过缩短机器ID、序列号位可以让最终生成的 Long 类型更短。

如果想让生成的 Long 缩小 1000 倍,也就是短 3 位,可以通过 2 的次方计算要缩短几位,缩小1000倍时,最接近的值为 1024,也就是 IdMeta 整体要缩短 10 位才能保证生成的 Long 短 3 位。

当你想要自定义时,一定要根据自己的业务需要和时间、峰值的预期来进行配置。

3. 启动时针对当前配置给出提醒

由于 IdMeta 可以自定义配置了,因此为了避免配置不合理,Vesta 在启动时会输出类似下面的信息:

The current time bit length is 30, the expiration date is Sat Jan 09 13:37:03 CST 2049, this can be used for 11251 days.

如果配置的时间已经过期,会有类似下面的错误信息,并且会终止 Vesta 的运行:

The current timestamp (101641074191 >= 1073741823) has overflowed, Vesta Service will be terminate.

这个提示不仅仅启动时有效,在运行期间如果时间位已经用完,也会抛出相同的异常信息,并且终止运行。

4. 自定义实现

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

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

5. 增加 zookeeper 和 zkclient 依赖

相关代码:

https://gitee.com/robertleepeak/vesta-id-generator/pulls/4

后续 0.0.2 版本打包的时候会包含这两个依赖,因此如果使用 dubbo + zookeeper 提供服务,可以直接配置注册中心。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

isea533

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值