论坛
潜水/灌水快乐,沉淀知识,认识更多同行。
ToB圈子
加入IT圈,遇到更多同好之人。
朋友圈
看朋友圈动态,了解ToB世界。
ToB门户
了解全球最新的ToB事件
博客
Blog
排行榜
Ranklist
文库
业界最专业的IT文库,上传资料也可以赚钱
下载
分享
Share
导读
Guide
相册
Album
记录
Doing
搜索
本版
文章
帖子
ToB圈子
用户
免费入驻
产品入驻
解决方案入驻
公司入驻
案例入驻
登录
·
注册
只需一步,快速开始
账号登录
立即注册
找回密码
用户名
Email
自动登录
找回密码
密码
登录
立即注册
首页
找靠谱产品
找解决方案
找靠谱公司
找案例
找对的人
专家智库
悬赏任务
圈子
SAAS
ToB企服应用市场:ToB评测及商务社交产业平台
»
论坛
›
软件与程序人生
›
后端开发
›
Java
›
开源通用高性能的分布式id序列组件
开源通用高性能的分布式id序列组件
饭宝
金牌会员
|
2023-6-30 23:58:05
|
显示全部楼层
|
阅读模式
楼主
主题
935
|
帖子
935
|
积分
2805
原文地址:
https://ntopic.cn/p/2023062101/
Gitee源代码仓库:
https://gitee.com/obullxl/sequence-jdbc
GitHub源代码仓库:
https://github.com/obullxl/sequence-jdbc
分布式id序列说明
业务数据的存储,少不了数据记录的id序列。
id序列(或称序列)的生成方式有很多种,比如当前时间戳、数据库的序列值(Oracle的序列,MySQL的自增ID等)、UUID等方式。
这些生成方式都有一定的局限性,如时间戳在业务量较大时容易重复、Oracle序列和MySQL的自增ID限定了数据库类型(且MySQL的自增ID只能保证单库唯一,在分库分表的场景下也不适用)、UUID容易重复且无法保证递增等。
同时,一般业务数据的id序列通常会带上一些业务信息,比如增加业务标识前缀、增加年月日等信息。业务id序列的处理变得多样,则进一步要求业务id序列的生成通用且高效。
通用分布式id序列组件
为了屏蔽业务获取id序列因数据库类型、分库分表等带来的研发和维护成本,我们把分布式id序列的获取抽取为一个通用组件,对业务统一接口和规范。
通用分布式id序列实现方式有很多,本文主要介绍一种基于数据表的实现方式,通过一张表记录所有的业务序列名和值,业务根据序列名获取下一个序列值(和Oracle序列类型,但是无需为每个序列创建序列,因此更简单):
本方案的设计主要考量点:
通用性:仅依赖一张序列数据表,JDBC支持的数据库均可使用,包括SQLite、MySQL、Oracle、OceanBase等。
高性能:本地缓存一个序列区间,缓存使用完之前无DB交互;缓存的区间可设置,区间越大,DB访问越少,性能越高。
分布式:受益于集中式的序列数据表,保证了序列全局唯一。
分布式id序列组件设计
组件接口设计
组件接口只有1个,就是获取序列:
/**
* Author: obullxl@163.com
* Copyright (c) 2020-2023 All Rights Reserved.
*/
package cn.ntopic.sequence;
/**
* 分布式序列服务
*
* @author obullxl 2023年06月21日: 新增
*/
public interface NTSequence {
/**
* 默认序列名称
*/
String DEFAULT_SEQUENCE_NAME = "DEFAULT";
/**
* 序列名称最大长度
*/
int MAX_SEQUENCE_NAME_LENGTH = 64;
/**
* 获取下一个序列值
*
* @return 获取默认序列的新的唯一的序列值 {@link #DEFAULT_SEQUENCE_NAME}
* @throws IllegalArgumentException 参数非法
*/
default long next() {
return this.next(DEFAULT_SEQUENCE_NAME);
}
/**
* 获取下一个序列值
*
* @param sequenceName 序列名称,非空,1~64字符,业务可随意指定(如:用户模块为`USER`,订单模块为`ORDER`等)
* @return 新的唯一的序列值
* @throws IllegalArgumentException 参数非法
*/
long next(String sequenceName);
}
复制代码
组件可控参数
在追求通用性和性能的同时,以参数的方式供个性化调控:
id序列数据表名:默认值为nt_sequence;但对于不同的业务,对数据表名有要求规范(如:表名前置等),因此序列数据表名可设置
id序列起始值:默认值为1,即序列值从1开始递增;但对于存量业务,id值起始值需要比存量最大值要大,否则容易重复
id序列最大值:默认值为99999999,序列值递增到最大值,则循环从起始值开始
序列更新重试次数:默认值为10,当缓存序列用尽,需要查询和更新序列数据表,比较存在网络通讯和DB操作,不可避免存在异常失败,失败后会进行重试
序列缓存大小:默认值为1000,值越大,访问DB越少,性能越高,序列的连续性越差(如:缓存大小为1000,当序列用到400时,服务器重启了,那么401~1000直接的序列就丢失了);相反,值越小,访问DB越多,性能越低,序列的连续性越好。
/**
* 属性-数据源
*/
private final DataSource ntDataSource;
/**
* 属性-重试次数
*/
private int retryTimes = 10;
/**
* 属性-数据表名
*/
private String tableName = "nt_sequence";
/**
* 属性-序列获取步长(即序列缓存大小)
*/
private long step = 1000L;
/**
* 属性-序列最小值
*/
private long minValue = 1L;
/**
* 属性-序列最大值
*/
private long maxValue = 99999999L;
复制代码
序列组件使用
Gitee源代码仓库:
https://gitee.com/obullxl/sequence-jdbc
GitHub源代码仓库:
https://github.com/obullxl/sequence-jdbc
目前JAR包已经发布,通过Gitee进行仓库托管,也可直接使用,2步即可:
第一步:在项目源代码的根pom.xml中,设置仓库地址:
<repositories>
<repository>
<id>Gitee-obullxl</id>
<url>https://gitee.com/obullxl/maven-repository/master/repository</url>
</repository>
</repositories>
复制代码
第二步:引用JAR包,仅需要依赖本JAR包,无其他JAR包依赖:
<dependency>
<groupId>cn.ntopic</groupId>
<artifactId>sequence-jdbc</artifactId>
<version>1.0.1</version>
</dependency>
复制代码
在业务代码中调用序列组件样例:
// 1. 构建数据源
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:sqlite:/Users/obullxl/CodeSpace/sequence-jdbc/SequenceJDBC.sqlite");
dataSource.setDriverClassName("org.sqlite.JDBC");
dataSource.setPoolPreparedStatements(false);
dataSource.setMaxPoolPreparedStatementPerConnectionSize(-1);
dataSource.setTestOnBorrow(true);
dataSource.setTestOnReturn(false);
dataSource.setTestWhileIdle(true);
dataSource.setValidationQuery("SELECT '1' FROM sqlite_master LIMIT 1");
// 2. 初始化序列组件
NTSequenceImpl ntSequence = new NTSequenceImpl(dataSource);
ntSequence.setTableName(tableName);
ntSequence.createTable();
ntSequence.init();
// 3. 获取序列值
@Autowire
@Qualifier("ntSequence")
private NTSequence ntSequence;
// 获取`DEFAULT`默认序列ID
long newId1 = ntSequence.next();
long newId2 = ntSequence.next();
long newId3 = ntSequence.next();
// 获取`USER`用户ID:
long newUserId1 = ntSequence.next("USER");
long newUserId2 = ntSequence.next("USER");
long newUserId3 = ntSequence.next("USER");
// 获取`ORDER`订单ID:
long newOrderId1 = ntSequence.next("ORDER");
long newOrderId2 = ntSequence.next("ORDER");
long newOrderId3 = ntSequence.next("ORDER");
复制代码
完整的使用方法,可参数源代码仓库说明文档(README.md):
Gitee源代码仓库:
https://gitee.com/obullxl/sequence-jdbc
GitHub源代码仓库:
https://github.com/obullxl/sequence-jdbc
分布式id序列测试用例
因为代码较大,请直接查看源代码:
Gitee测试源代码:
https://gitee.com/obullxl/sequence-jdbc/blob/master/src/test/java/cn/ntopic/sequence/NTSequenceTest.java
GitHub测试源代码:
https://github.com/obullxl/sequence-jdbc/blob/master/src/test/java/cn/ntopic/sequence/NTSequenceTest.java
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
本帖子中包含更多资源
您需要
登录
才可以下载或查看,没有账号?
立即注册
x
回复
使用道具
举报
0 个回复
倒序浏览
返回列表
快速回复
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
or
立即注册
本版积分规则
发表回复
回帖并转播
回帖后跳转到最后一页
发新帖
回复
饭宝
金牌会员
这个人很懒什么都没写!
楼主热帖
53基于java的资源博客论坛系统设计与实 ...
zotero+坚果云实现多pc端及iPad同步管 ...
天涯神贴合集500篇(2023最新) ...
Android——一个简单的记账本APP ...
需求:清空三个月前的操作日志,并生成 ...
面试官:@Configuration 和 @Component ...
【分布式计算】学习笔记(期末复习) ...
PerfView专题 (第十一篇):使用 Diff ...
Python潮流周刊#5:并发一百万个任务要 ...
nginx 常用指令配置总结
标签云
存储
服务器
快速回复
返回顶部
返回列表