私は、地域に分散した環境で一意の 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
。