分散環境で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 戦略

推薦する

デジタル自動車小売業がオムニチャネル体験を最適化

自動車小売業界では、デジタルモール、AI+小売、自動車スーパーマーケット、オムニチャネルマーケティン...

Kubernetes のマルチコンテナ Pod と Pod 内のコンテナ間通信

コンテナはマイクロサービスなどの単一の問題を解決するためによく使用されますが、実際のシナリオでは、問...

電子商取引を行う伝統産業: 飢餓マーケティングのやり方を教えてくれる 4 つのヒント

従来の電子商取引ウェブサイトでは、利益を上げるためにはマーケティング手法が非常に重要です。優れたマー...

JD.com、蘇寧、国美が熾烈な競争を繰り広げる。価格比較検索が新たな戦場に

A5ウェブマスターネットワークは8月16日、8月15日に電子商取引大手3社、JD.com、Sunin...

百度ウェブサイトの外部リンクを判断することに関する李氏の意見

4月25日、百度ウェブマスタープラットフォームの李氏は「外部リンクの判定について」と題した発表を発表...

hostmada-$6/2g メモリ/2CPU/150g ハードディスク/3T トラフィック/G ポート/2IP

hostmada.com は 年に設立されたようで、ドメイン名登録、仮想ホスティング、VPS などの...

最近は風が強くて、トリックもいっぱいです。初心者は落ち着いてください!

年末には、基本的に同じやり方で、驚くほど安い価格を提示し、OpenVZ を使って損切りなしで過剰販売...

Alipay iOS版にセキュリティ脆弱性が露呈

最近、多くのメディアが、iOS版Alipayにセキュリティ上の脆弱性があると報じました。機内モードで...

蒼井そらが下着を販売、宣伝効果はあるのか?

国境を越えた交渉は今とても人気があります。最もがっかりした越境ビジネスは何ですか? 彼女が作った映画...

ソフト記事リンクに関するリンク担当者の考え

ソフト記事外部リンクは、SEO業界では高品質の外部リンクとして認識されています。まず、このタイプの外...

純利益の「接近戦」クラウドコンピューティングが次の戦場か?

[[265739]]過去1年間、アリババとテンセントはともに経済環境の不確実性と、沈みゆく市場におけ...

ロボットによるブロックに関する百度と淘宝網間の問題の図解

2008年にタオバオがロボットプロトコルを使って百度のスパイダーをブロックしたという騒動は、その事件...

Kubernetes レプリケーション コントローラーの仕組み

[[436665]]レプリケーション コントローラーは、ポッドのライフサイクルを管理し、必要な数のポ...

ケーススタディ: クラウドに依存しない製品を迅速に構築して提供する方法

2 年前、オブジェクトおよびグラフ データベースのプロバイダーである Objectivity は、ク...

Fliphost - 128m メモリ/5g SSD/500g トラフィック/G ポート/年間 16 ドル (より低価格の SSD)

Fliphostは2周年を機にKVMベースのVPSをリリースしました。1Gと2Gのメモリは月額4ドル...