3

不可解な要件が 1 つあります。

基本的に、これらの基準で一意の ID を作成する必要があります

  • 9 桁の番号、その日固有の番号 (つまり、番号が次の日に再び表示されても問題ありません)
  • リアルタイムで生成されます。Java のみ (データベースからシーケンス番号が生成されないことを意味します - 実際にはデータベースへのアクセスはまったくありません)
  • 番号は requestID を入力するために生成され、1 日あたり約 1.000.000 の ID が生成されます。
  • UUID または UID は使用しないでください (9 桁以上)

これが私の考慮事項です:

  • シーケンス番号を使用するのは良さそうですが、JVM を再起動すると、requestId が再生成される可能性があります。
  • time HHmmssSSS (Hour Minute Second Milliseconds) を使用すると、次の 2 つの問題があります。

を。システム時間は、サーバー管理者によって変更される場合があります。
b. 2 つのリクエストが同じミリ秒で要求されると、問題が発生する可能性があります。

何か案が?

4

4 に答える 4

5

データベースからのシーケンス番号生成なし

私はそのようなばかげた要件が嫌いです。H2HSQLDBなどの組み込みデータベースをごまかして使用し、シーケンスを通じて識別子を生成すると言います。

編集:この「チート」を提案する理由について少し詳しく説明します。「データベースなし」の要件についての私の理解は、この要件を処理するためにデータベースソフトウェアをインストールする必要がないか、既存のデータベーススキーマを変更できないということです。組み込みデータベースを使用することは、新しい jar ファイルをプロジェクトに追加することと同じです。なぜあなたはこれをすべきではないのですか?リレーショナル データベースが既にこの問題を解決しているのに、なぜ自分で何かを実装するのでしょうか?

于 2012-07-24T08:09:56.300 に答える
2

1,000,000 個の ID を処理するのに 9 桁が必要なので、3 桁で遊ぶことができます (ID の 0 ~ 999999 には残りの 6 桁が必要です)。

マルチサーバーのセットアップがあると仮定します。各サーバーに 3 桁のサーバー ID を割り当てると、サーバー間の重複を気にすることなく、各サーバー内で一意の ID 値を割り当てることができます。JVMの再起動を生き残るためには、最近割り当てられた値をディスクにエコーする必要があります(ローカルディスク、memcacheなど、保存したい場所に)。

各リクエストでファイルなどの I/O のオーバーヘッドが発生しないようにするには、ID をブロックに割り当て、ブロックのエンドポイントをストレージにエコー バックします。

したがって、最終的には次のようになります。

  • 各サーバーに ID を付与する
  • その日の最後に割り当てられた値を格納するストレージをサーバーに用意します (たとえば、ファイル)。
  • ID アロケータをブロック単位で動作させる (一度に 10 個の ID、100 個など)
  • ブロックを割り当てるには:
    • ファイルを読み取り、ブロックサイズを増やした数値を書き戻します
  • ブロックの ID を使用する
  • ID は、サーバー #12 によって割り当てられた 28 番目の ID の場合、たとえば 12000000027 になります。
  • 日が変わると (真夜中など)、現在のブロックを破棄し、新しい日に新しいブロックを割り当てます

疑似コードで:

class IDAllocator {
    Storage storage;
    int     nextId;
    int     idCount;
    int     blockSize;
    long    lastIdTime;

    /**
     * Creates an IDAllocator with the given server ID, backing storage,
     * and block size.
     *
     * @param   serverId        the ID of the server (e.g., 12)
     * @param   s               the backing storage to use
     * @param   size            the block size to use
     * @throws  SomeException   if something goes wrong
     */
    IDAllocator(int serverId, Storage s, int size)
    throws SomeException {

        // Remember our info
        this.serverId = serverId * 1000000; // Add a million to make life easy
        this.storage = s;
        this.nextId = 0;
        this.idCount = 0;
        this.blockSize = bs;
        this.lastIdTime = this.getDayMilliseconds();

        // Get the first block. If you like and depending on
        // what container this code is running in, you could
        // spin this out to a separate thread.
        this.getBlock();
    }

    public synchronized int getNextId()
    throws SomeException {
        int id;

        // If we're out of IDs, or if the day has changed, get a new block
        if (idCount == 0 || this.lastIdTime < this.getDayMilliseconds()) {
            this.getBlock();
        }

        // Alloc from the block    
        id = this.nextId;
        --this.idCount;
        ++this.nextId;

        // If you wanted (and depending on what container this
        // code is running in), you could proactively retrieve
        // the next block here if you were getting low...

        // Return the ID
        return id + this.serverId;
    }

    protected long getDayMilliseconds() {
        return System.currentTimeMillis() % 86400000;
    }

    protected void getBlock()
    throws SomeException {
        int id;

        synchronized (this) {
            synchronized (this.storage.syncRoot()) {
                id = this.storage.readIntFromStorage();
                this.storage.writeIntToStroage(id + blocksize);
            }

            this.nextId = id;
            this.idCount = blocksize;
        }
    }
}

...しかし、繰り返しになりますが、これは疑似コードであり、ID が必要なときに ID を待っている I/O をブロックしないように、プロアクティブなものをそこに投入したい場合があります。

上記は、ある種のアプリケーション全体のシングルトンが既にあり、IDAllocatorインスタンスがその単一インスタンスの単なるデータ メンバーであると仮定して書かれています。getInstanceそうでない場合は、従来の方法を使用して、コンストラクターへの引数として受け取るのではなく、環境から構成を読み取ることにより、代わりに上記を簡単にシングルトンにすることができます。

于 2012-07-24T08:18:06.230 に答える
1

サーバー 1 では 1 から 999.999.999 までカウントし、サーバー 2 では -999.999.999 か​​ら -1 までカウントします。

負荷分散により、バランスは約 50:50 になると思います。したがって、各サーバーで同じ ID 範囲を取得します。さらに、最後に生成された ID をファイルシステムに保存します。パフォーマンス上の問題により、1000 ごとに値を保存するだけです (または 10000、それは実際には問題ではありません)。アプリケーションを再起動した後、最後に生成された値を読み取り、1000 を追加します。これでうまくいくと思います。

于 2012-07-24T10:25:35.970 に答える
0

ApacheのRandomStringUtilsStringrandom (int count、boolean letter、boolean numbers)を試すか、またはRANDOM.ORGを利用するJavaTRNGクライアントライブラリを試して使用することができます。

このライブラリは、Java Security APIと統合されたSecureRandomサービスを提供し、random.orgおよびrandom.irb.hr(大気ノイズまたはフォトニック放出を介してランダム性を生成する真の乱数ジェネレーター)にアクセスします。

そのうちの1つを手に入れてタイムスタンプと組み合わせると、自分が求めているものを手に入れることができると思います。

于 2012-07-24T08:13:15.670 に答える