再来安利一款优秀的开源全局唯一流水号 ID 生成器: Vesta - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
hansonwang99
V2EX    程序员

再来安利一款优秀的开源全局唯一流水号 ID 生成器: Vesta

 
  •   hansonwang99
    hansonwang99 2018-11-22 06:42:48 +08:00 6731 次点击
    这是一个创建于 2520 天前的主题,其中的信息可能已经有所发展或是发生改变。

    本文内容脑图如下:

    本文内容脑图

    文章共 760 字,阅读大约需要 2 分钟 !


    概 述

    在前一篇文章 《 Spring Boot 工程集成全局唯一 ID 生成器 UidGenerator 》 中给大家推荐了一款由百度开发的基于 Snowflake 算法实现的全局唯一 ID 生成器 UidGenerator,而本文则给大家再度推荐一款优秀的全局唯一 ID 生成器,名叫 Vesta。

    Vesta 是艳鹏大佬的开源作品,基于 Java 开发,其体验地址 在此。Vesta 是一款通用的 ID 产生器,互联网俗称统一发号器,其具有几大很具有优势的特性:

    • 全局唯一
    • 粗略有序
    • 可反解
    • 可制造
    • 分布式

    而且支持三种发布模式:

    • 嵌入式发布模式
    • 中心服务器发布模式
    • REST 发布模式

    根据业务的性能需求,它可以产生 最大峰值型最小粒度型 两种类型的 ID,它的实现架构使其具有高性能,高可用和可伸缩等互联网产品需要的质量属性,是一款通用的高性能的发号器产品。

    本文就在 Spring Boot 项目中将 Vesta 耍起来!


    基础工程搭建

    Spring Boot 基础工程的搭建我不再赘述,创建好工程后 pom中需要加入如下依赖:

     <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 包去编译一下 Vesta 源码即可获得,源码在此


    Vesta 配置导入

    • 在项目resources目录中加入 Vesta 的配置文件

    引入vesta-rest.properties,配置如下:

    vesta.machine=1021 # 机器 ID vesta.genMethod=0 # 生成方式,0 表示使用嵌入发布模式 vesta.type=1 # ID 类型,1 表示最小粒度型 

    引入 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"> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations" value="classpath:ext/vesta/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配置文件加载进项目

    • 创建 UidConfig 配置类
    @Configuration @ImportResource( locatiOns= { "classpath:ext/vesta/vesta-rest-main.xml" } ) public class UidConfig { } 

    编写 Vesta Service

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

    • genId 生成全局唯一 ID 号
    • explainId 反解全局唯一 ID 号,得到可以解释 ID 号含义的 JSON 数据
    • makeId 手工制造 ID

    来看代码吧

    @Service public class UidService { @Resource private 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

    我们针对上述 UidService中提供的三个工具接口来各自编写一个测试接口:

    @RestController public class UidController { @Autowired private UidService uidService; @RequestMapping("/genid") public long genId() { return uidService.genId(); } @RequestMapping("/expid") public Id explainId(@RequestParam(value = "id", defaultValue = "0") long id) { return uidService.explainId( id ); } @RequestMapping("/makeid") 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 ); } } 

    实验验证

    • 实验一

    首先我们用浏览器调用接口 genid,来返回生成的全局唯一 ID 流水号,一切都是那么的简单优雅:

    生成全局唯一流水号

    • 实验二

    由于 Vesta 生成的全局唯一流水号具有 可反解 的优良特性,因此我们可以先生成一个流水号,然后调用 expid接口来反解出流水号所代表的意义:

    全局唯一流水号的反解效果


    后 记

    由于能力有限,若有错误或者不当之处,还请大家批评指正,一起学习交流!



    14 条回复    2018-11-27 21:36:41 +08:00
    li27962278
        1
    li27962278  
       2018-11-22 08:33:17 +08:00
    学习 mark
    hanxiV2EX
        2
    hanxiV2EX  
       2018-11-22 08:36:55 +08:00 via Android
    额。。。uuid
    hansonwang99
        3
    hansonwang99  
    OP
       2018-11-22 08:38:44 +08:00 via iPhone
    @hanxiV2EX UUID 的短板很明显的
    Antihank
        4
    Antihank  
       2018-11-22 09:12:01 +08:00
    还不了解这个意义,战略 mark。
    SuperNovaSonic
        5
    SuperNovaSonic  
       2018-11-22 09:13:56 +08:00
    有大佬简单说下怎么实现的吗?
    baicheng10
        6
    baicheng10  
       2018-11-22 09:14:28 +08:00
    还不了解这个意义,战略 mark。
    inreality
        7
    inreality  
       2018-11-22 09:22:27 +08:00
    想知道算法用的什么,和 snowflake 比有什么优势?
    fy
        8
    fy  
       2018-11-22 09:41:04 +08:00
    我记得 Snowflake 是 Twitter 推出的算法。

    @SuperNovaSonic #5
    @inreality #7

    参考实现:

    ObjectID ( MongoDB 的算法,在 Snowflake 之后实现)
    https://github.com/fy0/slim/blob/master/slim/utils/myobjectid.py

    一个修改版(调整了字段位置)
    https://github.com/fy0/slim/blob/master/slim/utils/customid.py

    要问 Snowflake 这个算法比 uuid 强在哪,我认为是长度。
    “ uuid 短板很多”甚至不算是个说法。
    Tengdw
        9
    Tengdw  
       2018-11-22 09:52:49 +08:00
    @fy 还有一个 SnowFlake 对数据库索引比较友好
    cyhulk
        10
    cyhulk  
       2018-11-22 10:07:51 +08:00
    都算是类 snowflake 吧,我比较好奇的是它的序号是怎么生成的,文档中没有写,机器 id 也没有写,不如 mac 地址+random 安全吧,我比较关心的是序列号的生成方式,random ???
    passerbytiny
        11
    passerbytiny  
       2018-11-22 10:23:37 +08:00
    这么长的序号,反解意义不大,我觉得在“业务>性能”的前提下,还不如一个 findByID 接口。

    粗略有序性这一块应该大有看头,不过楼主并没有实验。

    最后再提一点偏见,程序员不应该使用脑图。
    iyangyuan
        12
    iyangyuan  
       2018-11-22 10:38:19 +08:00
    具体实现不清楚,不过这个序列号太长了。
    建议底层使用位操作,不要直接用字符串或者十进制表示信息,太过浪费。
    还有,时间戳可以用相对值(偏移量),这样可以大大节省存储空间。
    passerbytiny
        13
    passerbytiny  
       2018-11-22 10:47:48 +08:00   1
    看了一下 snowflake 算法,跟 UUID 相比,最主要的优势就是“有序”了,“有序”了自然可读性就高了、索引就好弄了。长度优势( 64bit vs 128bit)并不重要,而且 64bit 并不是算法要求的,而是习惯要求的(正好等于一个 Long )。

    因为要“有序”,劣势也是有的:算法复杂,生成方式易用性和生成速度上不及 UUID ;系统内全局唯一,但出了系统并不是全球唯一。在不需要“有序”的地方,还是用 UUID 更好。
    xiaojinmaolove
        14
    xiaojinmaolove  
       2018-11-27 21:36:41 +08:00 via iPhone
    Mark 了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     904 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 22:04 PVG 06:04 LAX 15:04 JFK 18:04
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86