分散ID生成方式
- UUID
- データベースの自己増分
- 数値セグメントモード
- Redisの実装
- スノーフレークアルゴリズム (SnowFlake)
- 百度ウイドジェネレーター
- 美団の葉
- Didi TinyID
この記事ではIDを自動インクリメントできるLeafとTinyIDに焦点を当てます。
数値セグメントモード
このモードは分散 ID を生成する方法でもあり、[1,1000] などの数値範囲をデータベースから取得し、1 から 1000 までの自動インクリメント ID を生成し、メモリにロードするというアイデアです。構造は次のとおりです。
CREATE TABLE id_generator (
id int(10) NOT NULL,
max_id bigint(20) NOT NULL COMMENT '当前最大id',
step int(20) NOT NULL COMMENT '号段的布长',
biz_type int(20) NOT NULL COMMENT '业务类型',
version int(20) NOT NULL COMMENT '版本号',
PRIMARY KEY (`id`)
)
biz_type: さまざまなビジネス タイプ
max_id: 現在の最大 ID
step: 代表的な番号セグメントのステップ サイズversion: バージョン番号は、MVCC と同様に、楽観的ロック
として理解でき、 ID が使用されるのを待ってから、次へ進みます。データベースから取得して最大値を変更します
update id_generator set max_id = #{max_id+step}、version = version + 1 ここで、version = # {version} および biz_type = XXX
長所: Baidu Uidgenerator、 Meituan Leafなど、比較的成熟したソリューションがある
短所: データベースの実装に依存する
美団の葉
Leaf では、ID を生成する 2 つの方法、番号セグメント モード (リーフ セグメント) とスノーフレーク モード (リーフ スノーフレーク) を提供します。両方のメソッドを同時に有効にすることも、有効にするメソッドを指定することもできます。デフォルトでは、2 つのメソッドが無効になります。
gitの場所
GitHub - Meituan-Dianping/Leaf: 分散 ID 生成サービス
紹介文書
https://github.com/Meituan-Dianping/Leaf/blob/master/README_CN.md
データテーブルの作成
CREATE DATABASE leaf
CREATE TABLE `leaf_alloc` (
`biz_tag` varchar(128) NOT NULL DEFAULT '',
`max_id` bigint(20) NOT NULL DEFAULT '1',
`step` int(11) NOT NULL,
`description` varchar(256) DEFAULT NULL,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`biz_tag`)
) ENGINE=InnoDB;
insert into leaf_alloc(biz_tag, max_id, step, description) values('leaf-segment-test', 1, 2000, 'Test leaf Segment Mode Get Id')
アイテムを入手
git clone [email protected]:Meituan-Dianping/Leaf.git
mysqlドライバーをアップグレードする
接続が mysql1.8 以降の場合は、mysql ドライバーをそれぞれアップグレードする必要があります
Leaf/poe.xml以及 leaf_core/poe.xml
# Leaf/poe.xml
<mybatis-spring.version>1.2.5</mybatis-spring.version>
#leaf_core/poe.xml
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
設定変更
ナンバーセグメントモードの構成は以下のとおりです。
リーフサーバー/リソース/リーフ.プロパティ
leaf.name=com.sankuai.leaf.opensource.test
leaf.segment.enable=true
leaf.jdbc.url=jdbc:mysql://127.0.0.1:3306/leaf?useSSL=false
leaf.jdbc.username=root
leaf.jdbc.password=123456
leaf.snowflake.enable=false
#leaf.snowflake.zk.address=
#leaf.snowflake.port=
パック
cd リーフ
mvn クリーン インストール -DskipTests
走る
cd リーフサーバー
#mvn メソッド
mvn spring-boot:run
#script メソッド
shdeploy/run.sh
テスト
#segmentcurl
http://localhost:8080/api/segment/get/leaf-segment-test
#snowflakecurl
http://localhost:8080/api/snowflake/get/test
モニタリングページ
番号セグメントモード: http://ローカルホスト:8080/キャッシュ#biz_type を追加すると、10 秒後に有効になることに注意してください。
Didi TinyID
ギットハブの場所
GitHub - リクエスト/リクエスト: ID ジェネレーターの識別
紹介文書
アイテムを入手
git clone https://github.com/didi/tinyid.git
データテーブルの作成
tinyid-server/db.sql
CREATE TABLE `tiny_id_info` (
`id` bigint(20) 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');
設定変更
cd tinyid-server/src/main/resources/offline
vi application.properties
server.port=9999
server.context-path=/tinyid
batch.size.max=100000
#datasource.tinyid.names=primary
#如果希望数据库能够高可用,可以设置多个不同节点,两个节点上的数据保持一致。
#注意添加配置的时候,多个节点都要添加
datasource.tinyid.names=primary,secondary
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/db1?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8
datasource.tinyid.primary.username=root
datasource.tinyid.primary.password=123456
#datasource.tinyid.primary.testOnBorrow=false
#datasource.tinyid.primary.maxActive=10
datasource.tinyid.secondary.driver-class-name=com.mysql.jdbc.Driver
datasource.tinyid.secondary.url=jdbc:mysql://localhost:3306/db2?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8
datasource.tinyid.secondary.username=root
datasource.tinyid.secondary.password=123456
datasource.tinyid.secondary.testOnBorrow=false
datasource.tinyid.secondary.maxActive=10
パック
cd 小さなID
mvn クリーン インストール -DskipTests
#または
cd tinyid-server/
sh build.sh オフライン
走る
cd tinyid-server/
#sh build.sh オフライン
java -jar 出力/tinyid-server-xxx.jar
テスト
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
クライアントの使用
クライアントのパッケージ化
cd 小さなID
mvn クリーン インストール -DskipTests
#tinyid-client\target\ tinyid-client-0.1.0-SNAPSHOT.jarが使用できるクライアントです
クライアントプロフィール
tinyid_client.properties
tinyid_client.properties をリソースの下に置きます
tinyid.server=localhost:9999
tinyid.token=0f673adf80504e2eaa552f5d791b644c
使用
public class ClientTest {
@Test
public void testNextId() {
for (int i = 0; i < 100000; i++) {
Long id = TinyId.nextId("test_odd");
System.out.println("current id is: " + id);
}
}
}
注: プログラムを再起動するたびに、ID を使い果たしたかどうかに関係なく、ID によってステップが追加されます。プログラムが頻繁に再起動される場合は、ステップを大きく設定しすぎないでください。ただし、ステップを小さくしすぎないでください。小さくしすぎると、データベースとの対話が頻繁になりすぎます。
ソース: