簡介
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包
直接在maven中install tinyid即可,剛開始自己從子模塊入手,base生成jar之後,繼續生成client、server,結果一直出錯:
原因是如果你有子項目引用了父項目的POM,但沒有在父項目POM目錄下執行安裝操作,這個問題就會出現。針對子模塊依賴兄弟子模塊的情況,需要在父項目POM目錄下至少執行一次安裝。
解決辦法是直接在父項目下進行install即可。
另外需要注意的是在install的過程中,要保持server端服務可用,不然client會失敗,連不上server錯誤。
2. 項目中引入tinyid-client maven依賴
<dependency>
<groupId>com.xiaoju.uemc.tinyid</groupId>
<artifactId>tinyid-client</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>
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<Long> tinyBatchId(){
List<Long> ids = TinyId.nextId("test", 10);
return ids;
}
該方式,id爲本地生成,號段長度(step)越長,qps越大,如果將號段設置足夠大,則qps可達1000w+,推薦使用方式。
完整代碼地址:SpringBoot項目集成Tinyid生成全局性ID