Didiの分散IDジェネレータ(Tinyid)、非常に便利な

Didiの分散IDジェネレータ(Tinyid)、非常に便利な

分散IDジェネレータについて知らない人は、前回の「分散ID生成方法9選」を復習してください。

Tinyid は Didi が開発した分散 ID システムです。 Meituan(Leaf)のリーフセグメントアルゴリズムに基づいたアップグレードです。データベースのマルチマスターノードモードをサポートするだけでなく、tinyid-client クライアントアクセスも提供しており、より便利に使用できます。しかし、Meituan (Leaf) とは異なり、Tinyid は数字セグメント モードのみをサポートし、スノーフレーク モードはサポートしていません。

Tinyidの特徴

  • グローバルに一意な長いID
  • トレンド増加ID
  • httpおよびJavaクライアントアクセスを提供する
  • 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 は 2 つの呼び出しメソッドを提供します。1 つは Tinyid-server によって提供される http メソッドに基づいており、もう 1 つは Tinyid-client クライアント メソッドです。どちらの方法を使用して呼び出す場合でも、Tinyid を構築するには、事前に tiny_id_info および tiny_id_token テーブルを作成する必要があります。

  1. テーブル `tiny_id_info` を作成します (  
  2. `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自動増分主キー',  
  3. `biz_type` varchar(63) NOT NULL DEFAULT '' COMMENT 'ビジネスタイプ、一意',  
  4. `begin_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '開始ID。初期値のみを記録し、他の意味はありません。初期化時には、begin_idとmax_idは同じである必要があります。  
  5. `max_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '現在の最大ID',  
  6. `step` int(11) デフォルト '0' コメント 'ステップ長',  
  7. `delta` int(11) NOT NULL DEFAULT '1' COMMENT '各IDの増分',  
  8. `remainder` int(11) NOT NULL デフォルト '0' コメント 'remainder',  
  9. `create_time` タイムスタンプ NOT NULL デフォルト '2010-01-01 00:00:00' コメント '作成時間',  
  10. `update_time` タイムスタンプ NOT NULL デフォルト '2010-01-01 00:00:00' コメント '更新時間',  
  11. `version` bigint(20) NOT NULL DEFAULT '0' COMMENT 'バージョン番号',  
  12. 主キー (`id`)、
  13. ユニークキー `uniq_biz_type` (`biz_type`)  
  14. )エンジン= InnoDB   AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8 COMMENT 'id information table';  
  15. テーブル `tiny_id_token` を作成します (  
  16. `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自動増分ID',  
  17. `token` varchar(255) NOT NULL DEFAULT '' COMMENT 'token',  
  18. `biz_type` varchar(63) NOT NULL DEFAULT '' COMMENT 'このトークンがアクセスできるビジネスタイプ識別子',  
  19. `remark` varchar(255) NOT NULL DEFAULT '' COMMENT '備考',  
  20. `create_time` タイムスタンプ NOT NULL デフォルト '2010-01-01 00:00:00' コメント '作成時間',  
  21. `update_time` タイムスタンプ NOT NULL デフォルト '2010-01-01 00:00:00' コメント '更新時間',  
  22. 主キー (`id`)  
  23. )エンジン= InnoDB   AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8 COMMENT 'トークン情報テーブル';  
  24. `tiny_id_info` に INSERT INTO (`id`、`biz_type`、`begin_id`、`max_id`、`step`、`delta`、`remainder`、`create_time`、`update_time`、`version`)  
  25. 価値観 
  26. (1, 'テスト', 1, 1, 100000, 1, 0, '2018-07-21 23:52:58', '2018-07-22 23:19:27', 1);  
  27. `tiny_id_info` に INSERT INTO (`id`, `biz_type`, `begin_id`, `max_id`, `step`, `delta`, `remainder`, `create_time`, `update_time`, `version`)  
  28. 価値観 
  29. (2, 'test_odd', 1, 1, 100000, 2, 1, '2018-07-21 23:52:58', '2018-07-23 00:39:24', 3);  
  30. `tiny_id_token` に INSERT します (`id`、`token`、`biz_type`、`remark`、`create_time`、`update_time`)  
  31. 価値観 
  32. (1, '0f673adf80504e2eaa552f5d791b644c', 'テスト', '1', '2017-12-14 16:36:46', '2017-12-14 16:36:48');  
  33. `tiny_id_token` に INSERT します (`id`、`token`、`biz_type`、`remark`、`create_time`、`update_time`)  
  34. 価値観 
  35. (2, '0f673adf80504e2eaa552f5d791b644c', 'test_odd', '1', '2017-12-14 16:36:46', '2017-12-14 16:36:48');

tiny_id_infoテーブルは、特定のビジネスパーティ番号セグメント情報のデータテーブルです。

max_id: セグメントの最大値

ステップ: ステップの長さ、つまり数値セグメントの長さ

biz_type: ビジネスタイプ

数値セグメントの取得では、max_id フィールドに対して更新操作 (update max_id = max_id + step) が実行されます。更新が成功した場合、新しい番号セグメントが正常に取得されたことを意味します。新しい数値セグメントの範囲は (max_id, max_id +step] です。

tiny_id_token は、現在のトークンがどのサービスを操作できるかの番号セグメント情報を示す権限テーブルです。

データベースを構成するには、tinyid-server の \offline\application.properties ファイルを変更します。 tinyid はデータベースのマルチマスターモードをサポートしているため、複数のデータベース情報を設定できます。 TinyIdServerApplication を起動してテストします。

  1. datasource.tinyid.primary.driver-class-name = com .mysql.jdbc.Driver  
  2. datasource.tinyid.primary.url = jdbc :mysql://127.0.0.1:3306/xin-master? です。 autoReconnect = true & useUnicode = true & characterEncoding = UTF -8  
  3. datasource.tinyid.primary.username =ジャンカン   
  4. datasource.tinyid.primary.password =ジャンカン   
  5. datasource.tinyid.primary.testOnBorrow = false    
  6. データソース.tinyid.primary.maxActive = 10    
  7. datasource.tinyid.secondary.driver-class-name = com .mysql.jdbc.Driver  
  8. datasource.tinyid.secondary.url = jdbc :mysql://localhost:3306/db2? です。 autoReconnect = true & useUnicode = true & characterEncoding = UTF -8  
  9. datasource.tinyid.secondary.username =ルート   
  10. データソース.tinyid.セカンダリ.パスワード= 123456    
  11. datasource.tinyid.secondary.testOnBorrow = false    
  12. データソース.tinyid.secondary.maxActive = 10  

1. HTTP メソッド

Tinyid は、ID と番号セグメントを取得するための合計 4 つの http インターフェイスを提供します。

  1. パッケージ com.xiaoju.uemc.tinyid.server.controller;  
  2. /**  
  3. * @著者 du_imba  
  4. */  
  5. @レストコントローラ 
  6. @リクエストマッピング("/id/")  
  7. パブリッククラスIdController {   
  8. プライベート静的最終 Logger logger = LoggerFactory .getLogger(IdContronller.class);  
  9. オートワイヤード 
  10. プライベート IdGeneratorFactoryServer idGeneratorFactoryServer;  
  11. オートワイヤード 
  12. プライベートSegmentIdServiceセグメントIdService;  
  13. オートワイヤード 
  14. プライベート TinyIdTokenService tinyIdTokenService;  
  15. @Value("${バッチサイズ最大}")  
  16. プライベート整数batchSizeMax;  
  17. @リクエストマッピング("次のId")
  18. パブリックレスポンス<リスト<ロング> > nextId(文字列 bizType、整数 batchSize、文字列 token) {  
  19. レスポンス<リスト<ロング> >  レスポンス=新しいレスポンス< > ();  
  20. 試す {  
  21. IdGenerator idGenerator = idGeneratorFactoryServer .getIdGenerator(bizType);  
  22. リスト<長い>   ids = idGenerator .nextId(newBatchSize);  
  23. レスポンスIDを設定します。  
  24. } キャッチ (例外 e) {  
  25. 応答.setCode(ErrorCode.SYS_ERR.getCode());  
  26. レスポンス.setMessage(e.getMessage());  
  27. logger.error("nextIdエラー", e);  
  28. }  
  29. 応答を返します。
  30. }  
  31. @RequestMapping("nextIdSimple")  
  32. パブリック String nextIdSimple(String bizType、Integer batchSize、String token) {  
  33. 文字列応答= "" ;  
  34. 試す {  
  35. IdGenerator idGenerator = idGeneratorFactoryServer .getIdGenerator(bizType);  
  36. (新しいバッチサイズ== 1 ) の場合 {  
  37. ロングid = idGenerator .nextId();  
  38. レスポンス= id + "";  
  39. } それ以外 {  
  40. リスト<長い>   idList = idGenerator .nextId(新しいバッチサイズ);  
  41. StringBuilder sb =新しいStringBuilder();  
  42. (Long id : idList) の場合 {
  43. sb.append(id).append(",");  
  44. }
  45.  レスポンス= sb .deleteCharAt(sb.length() - 1).toString();  
  46. }  
  47. } キャッチ (例外 e) {  
  48. logger.error("nextIdSimpleエラー", e);
  49.   }
  50.   応答を返します。  
  51. }  
  52. @リクエストマッピング("次のセグメントID")  
  53. パブリックレスポンス< SegmentId > nextSegmentId(String bizType, String token) {  
  54. 試す {  
  55. セグメントID segmentId = segmentIdService .getNextSegmentId(bizType);  
  56. レスポンス.setData(セグメントID);  
  57. } キャッチ (例外 e) {  
  58. 応答.setCode(ErrorCode.SYS_ERR.getCode());  
  59. レスポンス.setMessage(e.getMessage());  
  60. logger.error("nextSegmentIdエラー", e);  
  61. }  
  62. 応答を返します。  
  63. }  
  64. @RequestMapping("次のセグメント ID をシンプル")  
  65. パブリック String nextSegmentIdSimple(String bizType, String token) {  
  66. 文字列応答= "" ;  
  67. 試す {  
  68. セグメントID segmentId = segmentIdService .getNextSegmentId(bizType);
  69.  レスポンス= segmentId.getCurrentId () + "," + segmentId.getLoadingId() + "," + segmentId.getMaxId()  
  70. + "," + segmentId.getDelta() + "," + segmentId.getRemainder();  
  71. } キャッチ (例外 e) {  
  72. logger.error("nextSegmentIdSimple エラー", e);  
  73. }  
  74. 応答を返します。  
  75. }  
  76. }

nextId と nextIdSimple は次の ID を取得するために使用され、 nextSegmentIdSimple と getNextSegmentId は次の利用可能なセグメントを取得するために使用されます。違いは、インターフェースに戻りステータスがあるかどうかにあります。

  1. 次のID:  
  2. 'http://localhost:9999/tinyid/id/nextId? bizType =テスト&トークン= 0f673adf80504e2eaa552f5d791b644c '  
  3. 応答:  
  4. {  
  5. 「データ」: [2],  
  6. 「コード」: 200,  
  7. "メッセージ": ""  
  8. }  
  9. nextId シンプル:  
  10. 'http://localhost:9999/tinyid/id/nextIdSimple? bizType =テスト&トークン= 0f673adf80504e2eaa552f5d791b644c '  
  11. 回答: 3

2. Tinyidクライアント

http を使用したくない場合は、Tinyid-client も良い選択肢です。

tinyid-serverパッケージを参照する

  1. <依存関係>    
  2. <グループ ID > com.xiaoju.uemc.tinyid </グループ ID >    
  3. <artifactId> tinyid -クライアント</artifactId>    
  4. <バージョン> ${tinyid.version} </バージョン>    
  5. </依存関係>  

tinyid-server プロジェクトを起動し、パッケージ化して tinyid-server-0.1.0-SNAPSHOT.jar を取得します。バージョン ${tinyid.version} を 0.1.0-SNAPSHOT に設定します。

プロジェクトの application.properties で tinyid-server サービスのリクエスト アドレスとユーザー ID トークンを設定します。

  1. tinyid.server = 127.0.0.1:9999  
  2. tinyid.token = 0f673adf80504e2eaa552f5d791b644c ````

Java コードで TinyId を呼び出すことも非常に簡単で、必要なコードは 1 行だけです。

  1. // ビジネスタイプに基づいて単一のIDを取得します 
  2. ロングid = TinyId .nextId("test");  
  3. // ビジネス タイプに基づいて 10 個の ID を一括で取得します 
  4. リスト<長い>   ids = TinyId .nextId("テスト", 10);

Tinyid プロジェクト全体のソース コードの実装も比較的シンプルです。たとえば、データベースとのやりとりはjdbcTemplateを使用してより直接的に実装されます。

  1. @オーバーライド 
  2. パブリック TinyIdInfo クエリByBizType(文字列 bizType) {  
  3. 文字列sql = "select id、biz_type、begin_id、max_id、" +  
  4. 「ステップ、デルタ、残り、作成時間、更新時間、バージョン」+  
  5. " tiny_id_info から、 biz_typeは ?";  
  6. <TinyIdInfo> のリスト リスト= jdbcTemplate .query(sql、新しいオブジェクト[]{bizType}、新しい TinyIdInfoRowMapper());  
  7. if(リスト== null || list.isEmpty()) {  
  8. null を返します。  
  9. }  
  10. リストを返します。get(0);  
  11. }

要約する

2つの方法のうち、Tinyid-client が推奨されます。この方法では、ID はローカルで生成されます。ステップ長 (ステップ) が長いほど、サポートされる qps が大きくなります。ステップを十分に大きく設定すると、qps は 1000w 以上に達する可能性があります。さらに、tinyid-client から tinyid-server へのアクセス頻度が低くなるため、サーバーへの負荷が軽減されます。

<<:  面接官は、9 つ​​の分散 ID 生成方法を一​​気に述べたときに少し困惑しました。

>>:  クラウドサーバー市場の需要は回復しているが、いつショックが起きてもおかしくない

推薦する

新しいウェブサイトの重量を素早く改善する方法

筆者は3年以上SEOに携わり、30以上のウェブサイトを担当してきました。今日は、新しいウェブサイトの...

AI とクラウド コンピューティングが出会うとき、サービスとしての AI は神でしょうか、それとも悪魔でしょうか?

最先端技術の継続的な発展とクラウドコンピューティングサービスの普及により、AI as a servi...

WeChat 5.0はすべてのセルフメディアコンテンツを席巻し、クリックスルー率は大幅に低下するだろう

WeChatの自主メディアは短期間で急増し始め、独自の自主メディアの割合はますます希薄化しました。多...

SEO のヒント: 「SEO」キーワードで上位ランクを獲得する方法

月収10万元の起業の夢を実現するミニプログラム起業支援プランSEO の仕事をしている友人の多くは、R...

彼女がアオ・ビンに尋ねました: 分散トランザクションとは何ですか?

[[337759]]この記事はWeChatの公開アカウント「三太子敖冰」から転載したもので、著者は三...

Qunar.comの声明: 3億5000万元の融資を受けたという報道は事実ではない

網易科技ニュース、4月15日。本日、「中国商務日報」は、Qunar.comがBaidu、Hillho...

JD.comのヤン・ハイミン氏:インターネットビジネスの革新的な発展がITアーキテクチャの新たな変化を引き起こす

[51CTO.comより引用] 先日、51CTOとIntelが共催する「高速ビジネス下のITアーキテ...

Kubernetes ワーカーノードの数を計画するにはどうすればよいですか?

[[278523]]概要k8s クラスターの作業ノードを計画する際に最初に検討すべき質問は、どのタイ...

SEOキャンペーンで最終的な勝利を収めるには、「4ステップ」戦略を使用します

SEO を行うのは、火薬の煙のない戦いに似ています。勝者は王様になり、敗者は盗賊になります。勝者は百...

ミニプログラムを宣伝するための最も包括的なガイドです。強くお勧めします。これを読んで宣伝しないと言わないで

月収10万元の起業の夢を実現するミニプログラム起業支援プランミニプログラムは2017年1月9日に開始...

安定したブランドドメイン名投資家になる方法について話す

少し前に、a5ウェブマスターのウェブサイトに掲載された「国内インターネット市場取引概要」というタイト...

メモリ仮想化は具体的にどのように機能するのでしょうか?

1. 一言でまとめるメモリ仮想化は、仮想マシン内のプロセスが物理マシン上のメモリにアクセスする方法の...

収入が突然途絶えたとき、これらの問題について考えたことがありますか?

数日前に端午節が大いに盛り上がりながら始まりましたが、百度は多くの古いウェブサイトにも悪戯をしました...

2022 年の DevOps: 成功と課題

2022 年になると、セキュリティと価値が DevOps の 2 つの重要な側面になります。しかし、...

情報フロー広告チャネルの分析プラン!

情報フローの最適化を行う上で最も難しいのは、チャネルの選択です。現在、市場には何百もの情報フロープラ...