13

私は、地域に分散した環境で一意の ID を生成できるようにするソリューションを見つけようとして、ネットを閲覧してきました。

私は(特に)次のオプションを見ました:

スノーフレーク (Twitter)

  • これは素晴らしいソリューションのように思えますが、ID を作成するためだけに別のソフトウェアを管理しなければならないという複雑さが増すのは好きではありません。
  • この段階ではドキュメントが不足しているため、良い投資にはならないと思います。
  • ノードは、Zookeeper を使用して相互に通信できる必要があります (遅延/通信障害はどうですか?)

UUID

  • それを見てください:550e8400-e29b-41d4-a716-446655440000 ;
  • その 128 ビット ID;
  • いくつかの既知の衝突がありました (私が推測するバージョンによって異なります)この投稿を参照してください

MYSQL のようなリレーショナル データベースでのオートインクリメント

  • これは安全に思えますが、残念ながら、リレーショナル データベースは使用していません (スケーラビリティの設定)。
  • Flickr と同じように、MySQL サーバーをデプロイすることもできますが、これは別の障害点/ボトルネックをもたらします。また、複雑さを追加しました。

COUCHBASE のような非リレーショナル データベースでのオートインクリメント

  • データベースサーバーとして Couchbase を使用しているので、これは機能する可能性があります。
  • 異なるリージョンに複数のクラスターがある場合、遅延の問題、ネットワーク障害がある場合、これは機能しません。ある時点で、トラフィックの量に応じて ID が衝突します。

私の提案する解決策(これは私が助けを必要としているものです)

5 つの異なる地域 (アフリカ、ヨーロッパ、アジア、アメリカ、オセアニア) に 10 個の Couchbase ノードと 10 個のアプリケーション ノードで構成されるクラスターがあるとします。これは、ユーザーに最も近い場所からコンテンツが提供されるようにするため (速度を上げるため) と、災害などの場合に冗長性を確保するためです。

ここでのタスクは、レプリケーション (およびバランシング) が発生したときに衝突しない ID を生成することです。これは 3 つのステップで達成できると思います。

ステップ1

すべてのリージョンには、整数 ID (一意の識別子) が割り当てられます。

  • 1 - アフリカ;
  • 2 - アメリカ;
  • 3 - アジア;
  • 4 - ヨーロッパ;
  • 5 - オシアニア。

ステップ2

クラスターに追加されるすべてのアプリケーション ノードに ID を割り当てます。1 つのクラスターには最大 99,999 台のサーバーが存在する可能性があることを念頭に置いてください (私は疑っていますが、安全上の予防措置として)。これは次のようになります (偽の IP):

  • 00001 - 192.187.22.14
  • 00002 - 164.254.58.22
  • 00003 - 142.77.22.45
  • など。

これらはすべて同じクラスター内にあることに注意してください。つまり、リージョンごとにノード 00001 を持つことができます。

ステップ 3

データベースに挿入されたすべてのレコードに対して、インクリメントされた ID を使用して識別されます。これがどのように機能するかを示します。

Couchbase は、クラスター内で内部的に ID を作成するために使用できるインクリメント機能を提供します。冗長性を確保するために、クラスター内に 3 つのレプリカが作成されます。これらは同じ場所にあるため、クラスター全体がダウンしていない限り、これを担当するノードの 1 つが利用可能であり、そうでない場合はレプリカの数を増やすことができると想定しても安全だと思います。

すべてをまとめる

ユーザーがヨーロッパからサインアップしているとします: リクエストを処理するアプリケーション ノードは、リージョン コード (この場合は4 ) を取得し、独自の ID (たとえば00005 ) を取得し、Couchbase からインクリメントされた ID ( 1 ) を取得します (同じ集まる)。

最終的に 3 つのコンポーネントになります4, 00005,1。これから ID を作成するには、これらのコンポーネントを に結合するだけ4.00005.1です。さらに良くするために (これについてはよくわかりません)、コンポーネントを連結4000051して (足し合わせではなく)、次のようにすることができます。

コードでは、これは次のようになります。

$id = '4'.'00005'.'1';

注:違い$id = 4+00005+1;ます。

長所

  • ID は UUID よりも見栄えがします。
  • 彼らは十分にユニークに見えます。別のリージョンのノードが同じインクリメントされた ID を生成し、上記のものと同じノード ID を持っている場合でも、それらを区別するためのリージョン コードが常にあります。
  • これらは引き続き整数 (おそらく Big Unsigned 整数) として格納できます。
  • すべてがアーキテクチャの一部であり、複雑さが増すことはありません。

短所

  • ソートはありませんか(またはありますか)?
  • これは私があなたの意見を必要とするところです(ほとんど)

すべての解決策には欠陥があり、表面的に見られるものよりも多くの欠陥があることを私は知っています. このアプローチ全体で何か問題を見つけることができますか?

よろしくお願いします:-)

編集

@DaveRandom が示唆したように、4 番目のステップを追加できます。

ステップ 4

乱数を生成して ID に追加するだけで、予測可能性を防ぐことができます。事実上、次のような結果になります。

4000051357の代わりに4000051

4

2 に答える 2

1

ID について懸念している理由は 2 つあります。

  1. 複雑なネットワーク インフラストラクチャでの衝突の可能性
  2. 外観

2号からは外観。識別子に関して言えば、UUIDは確かに素晴らしい美しさではありませんが、あなたが言及したように、複雑なデータセンター(またはデータセンター)全体で真に一意の番号を導入すると、利益が減少します. たとえば、Web アプリケーションへの URL で長い番号と UUID を使用すると、アプリケーションの認識に劇的な変化があるとは思えません。理想的には、どちらも表示されず、IDAjax リクエストなどを介してのみ送信されます。きれいで覚えやすい URL が望ましいですが、Amazon で買い物をするのを止めることはありません (Amazon には絶対に恐ろしい URL があります)。:)

あなたの提案でも、識別子は UUID よりも文字数は短くなりますが、UUID よりも記憶に残るものではありません。したがって、外観については議論の余地がありそうです。

最初のポイントについて話します...はい、UUID が競合を生成することが知られているいくつかのケースがあります。これは、適切に構成され、一貫して取得されたアーキテクチャでは発生しないはずですが、どのように発生するかはわかります (ただし、個人的にはそれほど心配していません)。

したがって、代替案について話しているのであれば、私は MongoDB の単純さとObjectId、ID を生成する際の重複を回避するためのその手法のファンになりました。完全なドキュメントはこちらです。関連する簡単な部分は、いくつかの点で潜在的な設計に似ています。

ObjectId は 12 バイトの BSON タイプで、以下を使用して構築されます。

  • Unix エポックからの秒数を表す 4 バイトの値、
  • 3 バイトのマシン ID、
  • 2 バイトのプロセス ID、および
  • ランダムな値で始まる 3 バイトのカウンター。

タイムスタンプは、多くの場合、並べ替えに役立ちます。マシン ID は、一意の ID を持つアプリケーション サーバーに似ています。プロセス ID は単なる追加のエントロピーであり、最後に競合を防ぐために、タイムスタンプが ObjectId が最後に生成されたときと同じになるたびに自動インクリメントされるカウンターがあります (ObjectId を迅速に作成できるようにするため)。ObjectIdクライアントまたはデータベースで生成できます。さらに、ObjectId は UUID よりも少ないバイトしか使用しません (ただし 4 バイトのみ)。もちろん、タイムスタンプを使用して 4 バイトを削除することはできません。

明確にするために、MongoDB を使用することをお勧めしているわけではありませんが、ID 生成に使用されている手法に触発されてください。

したがって、あなたのソリューションは適切で (MongoDB の一意の ID の実装に触発されたいと思うかもしれません)、実行可能だと思います。あなたがそれをする必要があるかどうかについては、あなただけが答えられる質問だと思います。

于 2013-08-15T14:58:44.953 に答える