アプリケーションでは、データベースの主キーとしてグローバルに一意のIDが必要になることがよくあります。グローバルに一意の ID を生成するにはどうすればよいですか?
まず第一に、グローバルに一意な ID が整数であるか文字列であるかを判断する必要があります。文字列の場合、既存の UUID は要件を完全に満たしているため、追加の作業は必要ありません。欠点は、文字列が ID として多くのスペースを占有し、インデックス作成の効率が整数よりも低いことです。
整数を ID として使用する場合は、範囲が狭すぎるため、最初に 32 ビット int 型を除外し、64 ビットの long 型を使用する必要があります。
整数を ID として使用する場合、自己増加する、グローバルに一意で重複しない ID を生成するにはどうすればよいですか?
オプション 1: 1 から始まるデータベースの自己増加 ID を使用すると、基本的に連続的な増加を実現できます。 Oracle では SEQUENCE
、MySQL では主キーに AUTO_INCREMENT
が使用でき、グローバルな一意性は保証できませんが、テーブルごとに一意であり、基本的にはニーズを満たします。
データベースの自己増加 ID の欠点は、データを挿入する前に ID を取得できないことです。データの挿入後、取得された ID は一意ですが、トランザクションが送信されるまでは、その ID は有効とは見なされません。一部の双方向参照データを挿入して更新する必要があり、面倒です。
2 番目の方法は、集中 ID ジェネレーター (Redis または ZooKeeper など) を使用するか、データベース テーブルを使用して最後に割り当てられた ID を記録することです。
この方法の最大の欠点は、複雑すぎて、サードパーティのサービスに大きく依存する必要があり、コード構成が煩雑であることです。一般に、ソリューションが複雑になればなるほど、信頼性が低くなり、テストは困難になります。
3 番目の方法は、Twitter の Snowflake アルゴリズムに似ており、各マシンに一意の識別子を割り当て、次にタイムスタンプ ID をインクリメントして、グローバルに一意の ID を実現します。この方法の利点は、ID 生成アルゴリズムが完全にステートレス マシンであり、ネットワーク呼び出しがなく、効率的で信頼性が高いことです。欠点は、一意の識別子が繰り返されると ID の競合が発生することです。
Snowflake アルゴリズムは、41 ビット ミリ秒のタイムスタンプ、10 ビットのマシン ID、および 12 ビットのシリアル番号を使用します。理論的には、最大 1024 台のマシンをサポートして 1 秒あたり 4096000 個のシリアル番号を生成できますが、これは Twitter の規模には十分です。 。
しかし、ほとんどの一般的なアプリケーションでは、1 秒あたり 400 万を超える ID は必要なく、マシンの数も 1024 に達しません。したがって、これを改善して、より短い ID 生成方法を使用できます:
53bitID は、32 ビットの第 2 レベルのタイムスタンプ、16 ビット、および 5 ビットのマシン識別で構成され、32 台のマシンを蓄積し、毎秒 65,000 個のシリアル番号を生成できます。コア コード:
private static synchronized long nextId(long epochSecond) { if (epochSecond < lastEpoch) { // warning: clock is turn back: logger.warn("clock is back: " + epochSecond + " from previous:" + lastEpoch); epochSecond = lastEpoch; } if (lastEpoch != epochSecond) { lastEpoch = epochSecond; reset(); } offset++; long next = offset & MAX_NEXT; if (next == 0) { logger.warn("maximum id reached in 1 second in epoch: " + epochSecond); return nextId(epochSecond + 1); } return generateId(epochSecond, next, SHARD_ID);}
タイムスタンプ 固定値の減算、このソリューションは 2106 までサポートされます。
1 秒あたり 65,000 のシリアル番号では不十分な場合はどうすればよいでしょうか?それは問題ではありません。タイムスタンプをインクリメントし続けて、次の 1 秒間 65,000 のシーケンス番号を「借用」することができます。
同時に、時刻ダイヤルバックの問題も解決されます。
マシン ID は単純なホスト名スキームを使用します。ホスト名が host-1
と一致する限り、host-2
は設定を行わずにマシン ID を自動的に抽出できます。 。
最後に、なぜ 64 ビット整数ではなく最大 53 ビット整数を使用するのでしょうか?これは、ほとんどのアプリケーションが Web アプリケーションであることを考慮すると、JavaScript を扱う場合、JavaScript でサポートされる整数の最大値は 53 桁であり、これを超えると JavaScript の精度が失われます。したがって、53 ビットの整数は JavaScript で直接読み取ることができますが、53 ビットを超える場合は、JavaScript で正しく処理できるように文字列に変換する必要があり、API インターフェイスがさらに複雑になります。これが、Sina Weibo の API インターフェイスが id
と idstr
の両方を返す理由でもあります。
推奨チュートリアル: "PHP" "Laravel チュートリアル"
以上がLaravel分散ユニークIDジェネレータの使用法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。