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 生成方法を一​​気に述べたときに少し困惑しました。

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

推薦する

列車チケット購入サイトがひっそりと払い戻しを再開、ただし払い戻し時期の保証は難しい

昨日、消費者の李さんは我が新聞に、CtripのTieyou.comでオンラインチケットを購入したが、...

クラウド コンピューティングのサービス レベル契約を交渉する方法

企業にとって、クラウド プロバイダーがサービスとパフォーマンスに関するエンタープライズ レベルの約束...

ビリビリはどのようにして二次元世界に「誘拐」されたのか?

最近、ビリビリ動画配信サービス(以下、Bステーション)が公式に主催する「南京夏祭り」が批判され話題と...

ウェブサイト最適化ナビゲーション

SEO に対する考え方は人それぞれです。SEO 担当者の間でも、学習経験や接するサイトの種類、その他...

Huawei Cloud Double 11ドメイン名特別オファーがあなたを待っています

どの企業にも高品質の Web サイトが必要ですが、Web サイトを構築する際には、ドメイン名の選択の...

ハイパーコンバージェンス「ハードからソフトへ」: ハイブリッド クラウド向けに設計された Azure Stack HCI が中国に進出

[51CTO.com からのオリジナル記事] ハイパー コンバージド インフラストラクチャ (HCI...

中国インターネット広告レポート

今後数年間は、トラフィック モデルのエコ化 (複数の場所、複数の形式) とシナリオベースのトラフィッ...

美麗碩の「サイドアップ」はアリババとテンセントの生態戦争を反映している。左がアリババ、右がテンセント

[美麗碩がテンセント陣営を選んだという事実は、ショッピングガイドサイトに対するタオバオの曖昧な姿勢を...

SEO担当者が注文を受ける際に考慮すべき事項の詳細な説明

現在、ウェブサイトの最適化に取り組んでいる SEO 担当者は数多くいます。インターネット上の専門企業...

基礎知識はSEOの魂

SEO 担当者は、毎日「SEO」という 3 つの単語を見ると、少し美的疲労を感じるかもしれません。実...

42のウェブサイトが、否定的な記事を掲載して口止め料を脅迫したとして閉鎖された。

新華社によると、記者は28日、国家インターネット情報局から、詐欺や恐喝、わいせつ・ポルノ情報の流布な...

2017年上半期の中国のモバイルインターネットの概観

主な内容: 1. モバイルインターネットユーザーのインターネット習慣は基本的に形成されており、毎日の...

ブラックフライデー - 100TB サーバー - サーバー無料 [2x1] 256G SSD

uk2 グループの 100tb.com は、常に膨大なトラフィックで有名であり、その価格は通常安くは...

ftlcloud: 年末プロモーション、米国\韓国\香港\本土、無制限のトラフィック、クラウド サーバーは最低 35 元、専用サーバーは最低 450 元

ftlcloud は年末の大規模なプロモーションを開始しており、構成と価格の面でコスト効率が非常に高...