什么是分布式ID生成器Tinyid
本篇内容介绍了“什么是分布式ID生成器Tinyid”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
Tinyid的特性
全局唯一的long型ID
趋势递增的id
提供 http 和 java-client 方式接入
支持批量获取ID
支持生成1,3,5,7,9...序列的ID
支持多个db的配置
适用场景:只关心ID是数字,趋势递增的系统,可以容忍ID不连续,可以容忍ID的浪费
不适用场景:像类似于订单ID的业务,因生成的ID大部分是连续的,容易被扫库、或者推算出订单量等信息
Tinyid原理
Tinyid是基于号段模式实现,再简单啰嗦一下号段模式的原理:就是从数据库批量的获取自增ID,每次从数据库取出一个号段范围,例如 (1,1000] 代表1000个ID,业务服务将号段在本地生成1~1000的自增ID并加载到内存.。
Tinyid会将可用号段加载到内存中,并在内存中生成ID,可用号段在首次获取ID时加载,如当前号段使用达到一定比例时,系统会异步的去加载下一个可用号段,以此保证内存中始终有可用号段,以便在发号服务宕机后一段时间内还有可用ID。
原理图大致如下图:
Tinyid原理图
Tinyid实现
Tinyid的GitHub地址 :https://github.com/didi/tinyid.git
Tinyid提供了两种调用方式,一种基于Tinyid-server提供的http方式,另一种Tinyid-client客户端方式。不管使用哪种方式调用,搭建Tinyid都必须提前建表tiny_id_info、tiny_id_token。
CREATETABLE`tiny_id_info`(`id`bigint(20)unsignedNOTNULLAUTO_INCREMENTCOMMENT'自增主键',`biz_type`varchar(63)NOTNULLDEFAULT''COMMENT'业务类型,唯一',`begin_id`bigint(20)NOTNULLDEFAULT'0'COMMENT'开始id,仅记录初始值,无其他含义。初始化时begin_id和max_id应相同',`max_id`bigint(20)NOTNULLDEFAULT'0'COMMENT'当前最大id',`step`int(11)DEFAULT'0'COMMENT'步长',`delta`int(11)NOTNULLDEFAULT'1'COMMENT'每次id增量',`remainder`int(11)NOTNULLDEFAULT'0'COMMENT'余数',`create_time`timestampNOTNULLDEFAULT'2010-01-0100:00:00'COMMENT'创建时间',`update_time`timestampNOTNULLDEFAULT'2010-01-0100:00:00'COMMENT'更新时间',`version`bigint(20)NOTNULLDEFAULT'0'COMMENT'版本号',PRIMARYKEY(`id`),UNIQUEKEY`uniq_biz_type`(`biz_type`))ENGINE=InnoDBAUTO_INCREMENT=1DEFAULTCHARSET=utf8COMMENT'id信息表';CREATETABLE`tiny_id_token`(`id`int(11)unsignedNOTNULLAUTO_INCREMENTCOMMENT'自增id',`token`varchar(255)NOTNULLDEFAULT''COMMENT'token',`biz_type`varchar(63)NOTNULLDEFAULT''COMMENT'此token可访问的业务类型标识',`remark`varchar(255)NOTNULLDEFAULT''COMMENT'备注',`create_time`timestampNOTNULLDEFAULT'2010-01-0100:00:00'COMMENT'创建时间',`update_time`timestampNOTNULLDEFAULT'2010-01-0100:00:00'COMMENT'更新时间',PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=1DEFAULTCHARSET=utf8COMMENT'token信息表';INSERTINTO`tiny_id_info`(`id`,`biz_type`,`begin_id`,`max_id`,`step`,`delta`,`remainder`,`create_time`,`update_time`,`version`)VALUES(1,'test',1,1,100000,1,0,'2018-07-2123:52:58','2018-07-2223:19:27',1);INSERTINTO`tiny_id_info`(`id`,`biz_type`,`begin_id`,`max_id`,`step`,`delta`,`remainder`,`create_time`,`update_time`,`version`)VALUES(2,'test_odd',1,1,100000,2,1,'2018-07-2123:52:58','2018-07-2300:39:24',3);INSERTINTO`tiny_id_token`(`id`,`token`,`biz_type`,`remark`,`create_time`,`update_time`)VALUES(1,'0f673adf80504e2eaa552f5d791b644c','test','1','2017-12-1416:36:46','2017-12-1416:36:48');INSERTINTO`tiny_id_token`(`id`,`token`,`biz_type`,`remark`,`create_time`,`update_time`)VALUES(2,'0f673adf80504e2eaa552f5d791b644c','test_odd','1','2017-12-1416:36:46','2017-12-1416:36:48');
tiny_id_info表是具体业务方号段信息数据表
max_id :号段的最大值
step:步长,即为号段的长度
biz_type:业务类型
号段获取对max_id字段做一次update操作,update max_id= max_id + step,更新成功则说明新号段获取成功,新的号段范围是(max_id ,max_id +step]。
tiny_id_token是一个权限表,表示当前token可以操作哪些业务的号段信息。
修改tinyid-server中 \offline\application.properties 文件配置数据库,由于tinyid支持数据库多master模式,可以配置多个数据库信息。启动 TinyIdServerApplication 测试一下。
datasource.tinyid.primary.driver-class-name=com.mysql.jdbc.Driverdatasource.tinyid.primary.url=jdbc:mysql://127.0.0.1:3306/xin-master?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8datasource.tinyid.primary.username=junkangdatasource.tinyid.primary.password=junkangdatasource.tinyid.primary.testOnBorrow=falsedatasource.tinyid.primary.maxActive=10datasource.tinyid.secondary.driver-class-name=com.mysql.jdbc.Driverdatasource.tinyid.secondary.url=jdbc:mysql://localhost:3306/db2?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8datasource.tinyid.secondary.username=rootdatasource.tinyid.secondary.password=123456datasource.tinyid.secondary.testOnBorrow=falsedatasource.tinyid.secondary.maxActive=10
1、Http方式
tinyid内部一共提供了四个http接口来获取ID和号段。
packagecom.xiaoju.uemc.tinyid.server.controller;/***@authordu_imba*/@RestController@RequestMapping("/id/")publicclassIdContronller{privatestaticfinalLoggerlogger=LoggerFactory.getLogger(IdContronller.class);@AutowiredprivateIdGeneratorFactoryServeridGeneratorFactoryServer;@AutowiredprivateSegmentIdServicesegmentIdService;@AutowiredprivateTinyIdTokenServicetinyIdTokenService;@Value("${batch.size.max}")privateIntegerbatchSizeMax;@RequestMapping("nextId")publicResponse<List<Long>>nextId(StringbizType,IntegerbatchSize,Stringtoken){Response<List<Long>>response=newResponse<>();try{IdGeneratoridGenerator=idGeneratorFactoryServer.getIdGenerator(bizType);List<Long>ids=idGenerator.nextId(newBatchSize);response.setData(ids);}catch(Exceptione){response.setCode(ErrorCode.SYS_ERR.getCode());response.setMessage(e.getMessage());logger.error("nextIderror",e);}returnresponse;}@RequestMapping("nextIdSimple")publicStringnextIdSimple(StringbizType,IntegerbatchSize,Stringtoken){Stringresponse="";try{IdGeneratoridGenerator=idGeneratorFactoryServer.getIdGenerator(bizType);if(newBatchSize==1){Longid=idGenerator.nextId();response=id+"";}else{List<Long>idList=idGenerator.nextId(newBatchSize);StringBuildersb=newStringBuilder();for(Longid:idList){sb.append(id).append(",");}response=sb.deleteCharAt(sb.length()-1).toString();}}catch(Exceptione){logger.error("nextIdSimpleerror",e);}returnresponse;}@RequestMapping("nextSegmentId")publicResponse<SegmentId>nextSegmentId(StringbizType,Stringtoken){try{SegmentIdsegmentId=segmentIdService.getNextSegmentId(bizType);response.setData(segmentId);}catch(Exceptione){response.setCode(ErrorCode.SYS_ERR.getCode());response.setMessage(e.getMessage());logger.error("nextSegmentIderror",e);}returnresponse;}@RequestMapping("nextSegmentIdSimple")publicStringnextSegmentIdSimple(StringbizType,Stringtoken){Stringresponse="";try{SegmentIdsegmentId=segmentIdService.getNextSegmentId(bizType);response=segmentId.getCurrentId()+","+segmentId.getLoadingId()+","+segmentId.getMaxId()+","+segmentId.getDelta()+","+segmentId.getRemainder();}catch(Exceptione){logger.error("nextSegmentIdSimpleerror",e);}returnresponse;}}
nextId、nextIdSimple都是获取下一个ID,nextSegmentIdSimple、getNextSegmentId是获取下一个可用号段。区别在于接口是否有返回状态。
nextId:'http://localhost:9999/tinyid/id/nextId?bizType=test&token=0f673adf80504e2eaa552f5d791b644c'response:{"data":[2],"code":200,"message":""}nextIdSimple:'http://localhost:9999/tinyid/id/nextIdSimple?bizType=test&token=0f673adf80504e2eaa552f5d791b644c'response:3
2、Tinyid-client客户端
如果不想通过http方式,Tinyid-client客户端也是一种不错的选择。
引用 tinyid-server包
<dependency><groupId>com.xiaoju.uemc.tinyid</groupId><artifactId>tinyid-client</artifactId><version>${tinyid.version}</version></dependency>
启动 tinyid-server项目打包后得到 tinyid-server-0.1.0-SNAPSHOT.jar ,设置版本 ${tinyid.version}为0.1.0-SNAPSHOT。
在我们的项目 application.properties 中配置 tinyid-server服务的请求地址 和 用户身份token
tinyid.server=127.0.0.1:9999tinyid.token=0f673adf80504e2eaa552f5d791b644c```
在Java代码调用TinyId也很简单,只需要一行代码。
//根据业务类型获取单个IDLongid=TinyId.nextId("test");//根据业务类型批量获取10个IDList<Long>ids=TinyId.nextId("test",10);
Tinyid整个项目的源码实现也是比较简单,像与数据库交互更直接用jdbcTemplate实现
@OverridepublicTinyIdInfoqueryByBizType(StringbizType){Stringsql="selectid,biz_type,begin_id,max_id,"+"step,delta,remainder,create_time,update_time,version"+"fromtiny_id_infowherebiz_type=?";List<TinyIdInfo>list=jdbcTemplate.query(sql,newObject[]{bizType},newTinyIdInfoRowMapper());if(list==null||list.isEmpty()){returnnull;}returnlist.get(0);}
“什么是分布式ID生成器Tinyid”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。