分散環境でIDの一意性を確保する方法

分散環境でIDの一意性を確保する方法

[[408786]]

この記事はWeChatの公開アカウント「Java Geek Technology」から転載したもので、著者はYaxue Fansです。この記事を転載する場合は、Java Geek Technology の公開アカウントにお問い合わせください。

序文

まず、分散 ID が必要な理由と、分散 ID を使用して解決する問題について説明します。私たちのプロジェクトがまだモノリシック アーキテクチャだった頃は、データベースの自動増分 ID を使用して、多くのデータ識別の問題を解決できました。しかし、ビジネスが発展するにつれて、私たちのアーキテクチャは徐々に分散アーキテクチャへと進化していきます。現時点では、ビジネスのデータは複数のデータベースに保存される可能性があるため、データの自己増分 ID を使用することはできません。このとき、データを識別するには分散 ID が必要なので、分散 ID 生成サービスが必要になります。では、分散 ID サービスの要件と課題は何でしょうか?

必要とする

グローバルに一意: データを一意に識別するために使用されるため、分散 ID はグローバルに一意であり、同じビジネスのすべてのサービスで一貫している必要があります。これは基本的な要件です。

グローバル増分:増分も分かりやすいです。多くの場合、ID は人が見るためのものであるため、生成された ID が順番に増加していくことを確認する必要があります。増分しない場合は、読みやすさが大幅に低下します。

情報セキュリティ:分散IDのセキュリティも非常に重要です。前述したように、生成された ID は増分的であるため、競合他社が ID 生成の頻度を知ることができる可能性があります。これは電子商取引やその他のシナリオでは大きな問題を引き起こしますが、これは世界的な増加と矛盾することがよくあります。

高可用性: 分散 ID 生成サービスは高可用性を備えている必要があります。結局、ID を生成できなければ、その後のすべてのサービスが使用できなくなります。

一般的な分散ID実装

今日のインターネットでは、ビジネス シナリオとニーズに応じて、分散 ID を実装する方法がいくつかあります。

  1. 識別子;
  2. レディス;
  3. 変形されたデータベース自動増分 ID。
  4. Twitter スノーフレークアルゴリズム
  5. Meituan の Leaf — Snowflake アルゴリズムのバリエーション。

言語

Java を書く友人は UUID に精通している必要があります。 7dbb9f04-d15e-4c88-b74b-72a35e0d7580 は標準の UUID です。 UUID はグローバルに一意であり、前述の最初の要件を満たしていると言われていますが、明らかにグローバル増分はありません。この分散 ID は読みやすさが悪いです。ログ記録や人間の理解を必要としないシナリオにのみ使用する場合は使用できますが、ここで説明しているビジネス データの一意の識別には適していません。さらに、この順序付けられていない UUID を主キーとして使用すると、パフォーマンスに重大な影響を及ぼします。

レディス

Redis には incr コマンドがあり、アトミックな増分を保証し、ある程度のグローバル ID を生成できます。ただし、Redis の使用には 2 つの問題があります。

  1. それは美しくありません。グローバル ID が必要ですが、incr コマンドは 1 から始まる整数であるため、グローバル ID の長さが不一致になります。固有のビジネス データを識別するためにも使用できますが、日付情報が含まれていないため、シナリオによっては読みにくくなります。
  2. Redis の高可用性に依存しますが、Redis はメモリベースであるため、ID が失われないようにするには、Redis を永続化する必要がありますが、Redis の 2 つの永続化方法にはそれぞれ長所と短所があります。詳細は公式アカウントの前回の記事をご参照ください。インタビュアー: Redis ではクラッシュ後にデータが失われないようにどのように保証するのか教えてください。

データベース自動増分ID

先ほど、分散環境内の単一のデータベースでは、各 MySQL インスタンスの自動インクリメント ID が 1 から始まり、ステップ サイズが 1 ずつ増加するため、自動インクリメント ID を使用できなくなったことを説明しました。この場合、データベースごとに異なるステップ サイズを設定することを検討するのは簡単です。異なるステップ サイズを設定すると、各データベース インスタンスが重複することなく ID を生成できるようになります。シンプルなシステムをこのように使用することもできますが、いくつか問題があります。

データベースへの依存。分散環境では、データベースに過度に依存することはリスクがあり、特に 1 秒あたり数十万 QPS の電子商取引トランザクション シナリオでは、高い同時実行性をサポートできません。

異なるデータベース インスタンスのデータは直接リンクできず、データを連結するには追加のストレージが必要になるため、ビジネスの複雑さが増します。

Twitterのスノーフレークアルゴリズム

スノーフレーク アルゴリズムは、Twitter のオープン ソース分散 ID 生成アルゴリズムです。このアルゴリズムは標準的な考え方を提供します。多くの企業がこのアルゴリズムに基づいて独自の実装を行っています。最も有名なのは美団の葉です。ここでは、スノーフレーク アルゴリズムがどのように実装されるかに焦点を当てます。

ご興味がございましたら、https://tech.meituan.com/2017/04/21/mt-leaf.html の記事を参照して、Meituan の leaf の実装原理をご確認ください。

スノーフレーク アルゴリズムの考え方は、全体を部分に分割し、分散 ID の生成を各コンピューター ルームとマシンに分散させることです。 ID を表すために 64 ビットの long 型構造体が使用されます。 64 ビット構造を以下に示します。最初の符号ビットは 0 で、その後に 41 ビットのタイムスタンプが続き、次の 10 ビットはコンピュータ ルームとマシン、最後の 12 ビットはシリアル番号です。

上記の構造は、スノーフレーク アルゴリズムの基本構造です。各社は自社の事業内容に応じて適宜調整を行っていきます。 32 ビットやその他のビットを使用でき、実際の状況に応じてタイムスタンプのビット数を調整することもできます。 10 ビットの workerID は、コンピュータ ルームがある企業の場合はコンピュータ ルームとマシンで構成でき、コンピュータ ルームがない企業の場合はマシンを直接使用できます。状況に応じてシーケンスビットも適切に調整できます。

簡単な計算ができます。 41 ビットの時間は 2 ^ 41 / (365 * 24 * 3600 * 1000) = 69 年です。各マシンは 1 ミリ秒あたり 2 ^ 12 = 4096 個の ID を生成できます。

つまり、私たちのコードは 69 年間しか実行できないということですか?実はそうではありません。サービスは開始時に初期値を設定します。ここでのタイムスタンプは、マシン時間と初期値の差です。では、SnowFlake アルゴリズムの利点と欠点は何でしょうか?

  1. タイムスタンプがあるため、自己増分の要件を満たし、一定の可読性も備えています。
  2. 各サービスは独自のマシン上で一意の ID を直接生成でき、コンピュータ ルームとマシン番号を構成するだけで済みます。
  3. 用途に応じて長さを調整できます。
  4. 欠点は、マシンのクロックに依存することです。マシンのクロックに問題がある場合は、生成された ID が繰り返される可能性があり、これを制御する必要があります。

上記の原則を組み合わせることで、Java コードを通じて実装できます。コードは次のとおりです。

  1. パブリッククラスSnowFlakeUtil {
  2.  
  3. // 初期タイムスタンプ
  4. プライベート最終静的long START_TIMESTAMP = 1624796691000L;
  5. //データセンターが占有するビット数
  6. プライベート最終静的ロングDATA_CENTER_BIT = 5;
  7. //マシンIDで使用されるビット数
  8. プライベート最終静的ロングMACHINE_BIT = 5;
  9. //シリアル番号の桁数
  10. プライベート最終静的ロングSEQUENCE_BIT = 12;
  11.  
  12.  
  13. /**
  14. * 各パーツの最大値
  15. */
  16. プライベート最終静的ロング MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);
  17. プライベート最終静的ロング MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT);
  18. プライベート最終静的ロング MAX_DATA_CENTER_NUM = ~(-1L << DATA_CENTER_BIT);
  19.  
  20. /**
  21. * 各パーツの左への変位
  22. */
  23. プライベート最終静的ロング MACHINE_LEFT = SEQUENCE_BIT;
  24. プライベート最終静的ロング DATA_CENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
  25. プライベート最終静的ロング TIMESTAMP_LEFT = DATA_CENTER_LEFT + DATA_CENTER_BIT;
  26.  
  27. プライベートファイナルロングIDC;
  28. プライベート最終長いサーバーID;
  29. プライベートロングシーケンス= 0L;
  30. プライベートロングlastTimeStamp = -1L;
  31.  
  32. プライベートlong getNextMill() {
  33. ロングミル = System.currentTimeMillis();
  34. while (ミル <= lastTimeStamp) {
  35. ミル = System.currentTimeMillis();
  36. }
  37. リターンミル;
  38. }
  39.  
  40. /**
  41. * 指定されたデータセンターIDとマシンIDに基づいて指定されたシリアル番号を生成します
  42. *
  43. * @param idc データセンター ID
  44. * @param serverId マシンのロゴ ID
  45. */
  46. public SnowFlakeUtil(長いIDC、長いサーバーId) {
  47. idc > MAX_DATA_CENTER_NUM || idc < 0 の場合 {
  48. throw new IllegalArgumentException( "IDC データ センター番号が不正です!" );
  49. }
  50. if (サーバー ID > MAX_MACHINE_NUM || サーバー ID < 0) {
  51. throw new IllegalArgumentException( "serverId マシン番号が不正です!" );
  52. }
  53. this.idc = idc;
  54. this.serverId = サーバーID;
  55. }
  56.  
  57. /**
  58. * 次のIDを生成する
  59. *
  60. * @戻る 
  61. */
  62. パブリック同期された長いgenNextId() {
  63. long currTimeStamp = System.currentTimeMillis();
  64. (現在のタイムスタンプが最後のタイムスタンプより小さい場合)
  65. throw new RuntimeException( "時計が逆方向に動きました。ID の生成を拒否します" );
  66. }
  67. (カレントタイムスタンプ == ラストタイムスタンプ)の場合{
  68. //同じミリ秒で、シリアル番号が自動的に増加します
  69. シーケンス= (シーケンス+ 1) & MAX_SEQUENCE;
  70. //同じミリ秒内のシーケンスの数が最大値に達しました
  71. if (シーケンス== 0L ) {
  72. currTimeStamp = getNextMill();
  73. }
  74. }それ以外{
  75. //異なるミリ秒では、シーケンス番号は0に設定されます
  76. シーケンス= 0L;
  77. }
  78. 最後のタイムスタンプ = currTimeStamp;
  79. 戻り値(currTimeStamp - START_TIMESTAMP) << TIMESTAMP_LEFT | idc << DATA_CENTER_LEFT |サーバーID << MACHINE_LEFT |順序;
  80. }
  81.  
  82. 公共 静的void main(String[] args) {
  83. SnowFlakeUtil snowFlake = 新しい SnowFlakeUtil(4, 3);
  84. ( int i = 0; i < 100; i++)の場合{
  85. システム。出力.println(snowFlake.genNextId());
  86. }
  87. }
  88. }

参照する

知乎:9つの分散ID生成方法が一気に語られ、面接官は少々困惑した

Leaf - 美団点評分散ID生成システム

<<:  基本概念、アーキテクチャ、新バージョンへのアップグレード - Kafka 知識システム (I)

>>:  クラウド ネイティブ 2.0: 今検討すべき 3 つの DevOps 戦略

推薦する

ほとんどのリベートウェブサイトはねずみ講に関与しており、すぐに現金を返金することはできない

最近、「福州100%事件」と「温州百業連盟事件」が各界から大きな注目を集めています。 両事件とも、リ...

平安クラウドが銀行のデジタル変革を加速

【平安クラウド金融業界ソリューション】 [51CTO.com からのオリジナル記事] クラウド コン...

小紅書のオフラインの夢が打ち砕かれた後

小紅書はオフライン店舗を閉鎖した。 「金融グラフィティ」の報道によると、小紅書は最近、上海のオンライ...

エッジコンピューティングの戦い: 新たなクラウドの戦場はクラウドではない

アマゾンは、先進国のほとんどに商品を配送する世界的な電子商取引帝国を築き上げ、その過程で分散コンピュ...

エッジコンピューティングの支出は2026年までに3,170億ドルに達する

IDC は、今年最も大きな投資が見られた 3 つのユースケースとして、コンテンツ配信ネットワーク、仮...

人人動画と射殺ネットワークを閉鎖:司馬昭の野望

世界インターネット会議が開催され、有名なインターネット界の巨人たちが、FacebookやTwitte...

WeChatマーケティングプロモーションの特徴

技術が急速に変化しているこの時代では、新しい製品が古い製品に取って代わる例が多くあり、以前人気があっ...

エッジコンピューティングはクラウドコンピューティングに取って代わるでしょうか? 5G時代の最強のダークホースは現れたのか?

コンピュータは数百マイル離れていますが、遅延はわずか数ミリ秒です。オフィス アプリケーションの場合、...

spryservers: 米国建国記念日、KVM シリーズ VPS が 50% オフ、専用サーバーが 25% オフ

spryserversはHostcatに2度登場しており、主に米国フェニックスとダラスのデータセンタ...

2018年中国インターネット消費者エコシステムビッグデータレポート!

80年代以降の世代は中国のネット消費の屋台骨だが、90年代以降の世代の消費力も追い上げている。一人当...

ガートナーの予測: 世界のパブリッククラウド収益は2020年に6.3%増加する

ガートナーの予測によると、世界のパブリッククラウドサービス市場は2019年の2,427億ドルから20...

テンセントSaaSアクセラレーター第2フェーズの受賞者が発表、40社が選出、評価額は700億元を超える

共に創造し、共に前進し、長期的な価値志向を堅持し、ウィンウィンと共存を実現し、共にウィンウィンの産業...