分布式ID生成方案(五):SpringBoot2.X集成滴滴Tinyid

简介

Tinyid是用Java开发的一款分布式id生成系统,基于数据库号段算法实现,简单来说是数据库中保存了可用的id号段,tinyid会将可用号段加载到内存中,之后生成id会直接内存中产生。

特性

  • 全局唯一的long型id
  • 趋势递增的id,即不保证下一个id一定比上一个大
  • 非连续性
  • 提供http和java client方式接入
  • 支持批量获取id,支持生成1,3,5,7,9…序列的id
  • 支持多个db的配置,无单点

可用性

  • 依赖db,当db不可用时,因为server有缓存,所以还可以使用一段时间,如果配置了多个db,则只要有1个db存活,则服务可用
  • 使用tiny-client,只要server有一台存活,则理论上可用,server全挂,因为client有缓存,也可以继续使用一段时间

适用场景:

只关心id是数字,趋势递增的系统,可以容忍id不连续,有浪费的场景

不适用场景:

类似订单id的业务(因为生成的id大部分是连续的,容易被扫库、或者测算出订单量)

接入实现

  • Http方式

1. 导入源码

git clone https://github.com/didi/tinyid.git

2. 新建数据表

CREATE TABLE `tiny_id_info` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
  `biz_type` varchar(63) NOT NULL DEFAULT '' COMMENT '业务类型,唯一',
  `begin_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '开始id,仅记录初始值,无其他含义。初始化时begin_id和max_id应相同',
  `max_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '当前最大id',
  `step` int(11) DEFAULT '0' COMMENT '步长',
  `delta` int(11) NOT NULL DEFAULT '1' COMMENT '每次id增量',
  `remainder` int(11) NOT NULL DEFAULT '0' COMMENT '余数',
  `create_time` timestamp NOT NULL DEFAULT '2010-01-01 00:00:00' COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT '2010-01-01 00:00:00' COMMENT '更新时间',
  `version` bigint(20) NOT NULL DEFAULT '0' COMMENT '版本号',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_biz_type` (`biz_type`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT 'id信息表';

CREATE TABLE `tiny_id_token` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
  `token` varchar(255) NOT NULL DEFAULT '' COMMENT 'token',
  `biz_type` varchar(63) NOT NULL DEFAULT '' COMMENT '此token可访问的业务类型标识',
  `remark` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
  `create_time` timestamp NOT NULL DEFAULT '2010-01-01 00:00:00' COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT '2010-01-01 00:00:00' COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT 'token信息表';

INSERT INTO `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-21 23:52:58', '2018-07-22 23:19:27', 1);

INSERT INTO `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-21 23:52:58', '2018-07-23 00:39:24', 3);


INSERT INTO `tiny_id_token` (`id`, `token`, `biz_type`, `remark`, `create_time`, `update_time`)
VALUES
	(1, '0f673adf80504e2eaa552f5d791b644c', 'test', '1', '2017-12-14 16:36:46', '2017-12-14 16:36:48');

INSERT INTO `tiny_id_token` (`id`, `token`, `biz_type`, `remark`, `create_time`, `update_time`)
VALUES
	(2, '0f673adf80504e2eaa552f5d791b644c', 'test_odd', '1', '2017-12-14 16:36:46', '2017-12-14 16:36:48');

3. 修改Server数据库配置

server.port=9999
server.context-path=/tinyid

batch.size.max=100000

datasource.tinyid.names=primary
datasource.tinyid.type=org.apache.tomcat.jdbc.pool.DataSource

datasource.tinyid.primary.driver-class-name=com.mysql.jdbc.Driver
datasource.tinyid.primary.url=jdbc:mysql://localhost:3306/demo?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8
datasource.tinyid.primary.username=root
datasource.tinyid.primary.password=123456

4. 启动Server测试

nextId:
curl 'http://localhost:9999/tinyid/id/nextId?bizType=test&token=0f673adf80504e2eaa552f5d791b644c'
response:{"data":[2],"code":200,"message":""}

nextId Simple:
curl 'http://localhost:9999/tinyid/id/nextIdSimple?bizType=test&token=0f673adf80504e2eaa552f5d791b644c'
response: 3

with batchSize:
curl 'http://localhost:9999/tinyid/id/nextIdSimple?bizType=test&token=0f673adf80504e2eaa552f5d791b644c&batchSize=10'
response: 4,5,6,7,8,9,10,11,12,13

Get nextId like 1,3,5,7,9...
bizType=test_odd : delta is 2 and remainder is 1
curl 'http://localhost:9999/tinyid/id/nextIdSimple?bizType=test_odd&batchSize=10&token=0f673adf80504e2eaa552f5d791b644c'
response: 3,5,7,9,11,13,15,17,19,21

使用该方式性能取决于http server的能力,网络传输速度

  • Java Client方式

新建数据表及Server数据库配置,如HTTP方式的2、3两步。

下面就将该方式集成在基于Mysql数据库生成批量ID项目中使用:

1. 将源码进行打包,在本地仓库中生成jar包
分布式ID生成方案(五):SpringBoot2.X集成滴滴Tinyid_第1张图片
直接在maven中install tinyid即可,刚开始自己从子模块入手,base生成jar之后,继续生成client、server,结果一直出错:
分布式ID生成方案(五):SpringBoot2.X集成滴滴Tinyid_第2张图片
原因是如果你有子项目引用了父项目的POM,但没有在父项目POM目录下执行安装操作,这个问题就会出现。针对子模块依赖兄弟子模块的情况,需要在父项目POM目录下至少执行一次安装。

解决办法是直接在父项目下进行install即可

另外需要注意的是在install的过程中,要保持server端服务可用,不然client会失败,连不上server错误。

2. 项目中引入tinyid-client maven依赖


    com.xiaoju.uemc.tinyid
    tinyid-client
    0.1.0-SNAPSHOT

3. 项目中增加tinyid_client配置文件

#配置server端及token
tinyid.server=localhost:9999
tinyid.token=0f673adf80504e2eaa552f5d791b644c

4. 项目中提供两个controller接口,便于查看结果

/**
 * 集成tinyid生成单个id
 * @return
 */
@GetMapping("/tinyid/simple")
public Long tinyid(){
    Long id = TinyId.nextId("test");
    return id;
}

/**
 * 集成tinyid生成批量id
 * @return
 */
@GetMapping("/tinyid/batch")
public List tinyBatchId(){
    List ids = TinyId.nextId("test", 10);
    return ids;
}

该方式,id为本地生成,号段长度(step)越长,qps越大,如果将号段设置足够大,则qps可达1000w+,推荐使用方式。

完整代码地址:SpringBoot项目集成Tinyid生成全局性ID

你可能感兴趣的:(【架构设计】)