6

シナリオは次のとおりです。サーブレットコンテナ内で実行されているマルチスレッドの Java Web アプリケーションがあります。アプリケーションは、サーブレット コンテナー内に複数回デプロイされます。異なるサーバーで複数のサーブレット コンテナーが実行されています。

おそらく、このグラフは次のことを明確にしています。

server1
+- servlet container
   +- application1
   |  +- thread1
   |  +- thread2
   +- application2
      +- thread1
      +- thread2
server2
+- servlet container
   +- application1
   |  +- thread1
   |  +- thread2
   +- application2
      +- thread1
      +- thread2

これらすべてのスレッドがアクセスできるネットワーク共有ディレクトリ内にファイルがあります。そして、彼らは頻繁にファイルにアクセスします。ほとんどの場合、ファイルはそれらのスレッドによってのみ読み取られます。でもたまに書いてある。

データの一貫性が保証されるように、これらすべてのスレッドを同期するためのフェイル セーフ ソリューションが必要です。


(適切に)機能しないソリューション

  1. java.nio.channels.FileLock
    を使用すると、FileLock クラスを使用して、異なるサーバーからスレッドを同期できます。ただし、ファイル ロックはプロセス全体で使用できるため、これは同じプロセス (サーブレット コンテナー) 内のスレッドでは機能しません。

  2. 同期
    に別のファイルを使用すると、プロセスがファイルに対して読み取りまたは書き込みを行っていることを示す別のファイルを作成できます。このソリューションはすべてのスレッドで機能しますが、いくつかの欠点があります。

    • パフォーマンス。ファイルの作成、削除、およびチェックは、かなり遅い操作です。1 つの同期ファイルを使用した低重量の実装では、ファイルの並列読み取りが妨げられます。
    • JVM がクラッシュした後も同期ファイルが残り、手動によるクリーンアップが必要になります。
    • ネットワークファイルシステム上のファイルを削除するという奇妙な問題がすでに発生しています。
  3. メッセージング
    の使用 スレッドがファイル アクセスを調整するために使用するメッセージング システムを実装できます。しかし、これはこの問題には複雑すぎるようです。繰り返しますが、パフォーマンスは低下します。

何かご意見は?

4

6 に答える 6

2

最も単純な解決策は、別のプロセス (Web サービスまたは最も単純なもの) を作成することです。このプロセスのみがファイルの読み取り/書き込みを行い、他のサービスによる読み取り/書き込み要求をリッスンします。

これはネットワーク共有を直接使用するよりも遅いように見えるかもしれませんが、必ずしもそうではありません: ネットワーク共有を使用するということは、OS に組み込まれているクライアント/サーバーを使用することを意味します (これはまさにそれを行います: に読み取り/書き込み要求を送信します)。共有を提供するサーバー)。

あなたのサービスは(一般的な「ファイルを提供する」サービスではなく)タスクに合わせて最適化されているため、さらに高速になる可能性があります。

于 2009-01-28T07:57:43.587 に答える
2

明白な解決策を除いて、可能な解決策を列挙しました。そのファイルへの依存関係を削除します

ファイルから読み取る代わりに、スレッドがそのデータを取得する別の方法はありますか? すべてのスレッドにファイルを読み込ませるのではなく、その情報へのアクセスを調整する役割を担うある種のプロセスを設定するのはどうでしょうか。

于 2009-01-27T16:56:40.537 に答える
2

A. データベースの時代のようですね :-)。共有ファイルを持つのではなく、データベースにデータを保存するのはどうですか。

B. 別の方法 - レイヤリング:

  1. 標準の同期ロックを使用して、プロセス内のスレッドをロックします。
  2. ファイルベースのロックタイプのものでプロセス間/マシンをロックします-たとえば、ロックを保持するディレクトリを作成します。

1 の中に 2 を入れ子にします。

まだクリーンアップの問題があります。

C. あるいは、読者がおそらくロックする必要がないように、新しいファイルへの書き込み/名前変更戦略のようなものはありますか?

于 2009-01-27T16:57:39.473 に答える
1

まれにファイルを書き込む必要があるだけの場合は、一時的な名前でファイルを書き込んでから、renameを使用してリーダーに「表示」するのはどうでしょうか。

ただし、これはUnixファイルシステムでのみ確実に機能します。Windowsでは、一部のプロセスでファイルが(読み取り用に)開かれている場合に対処する必要があります。この場合、名前の変更は失敗します。名前の変更が成功するまで、もう一度やり直してください。

輻輳が発生する可能性があるため、これを徹底的にテストすることをお勧めします。読み取り要求が非常に多いため、ライタータスクでファイルを長時間置き換えることができません。

その場合は、リーダーに一時ファイルを確認させ、ファイルが消えるまで次の読み取りでしばらく待ちます。

于 2009-01-28T07:59:57.763 に答える
1

アプリケーション内で一度に 1 つのアクセスを制御するためにセマフォを使用することはできますか?

API を引用するには、「セマフォは、いくつかの (物理的または論理的な) リソースにアクセスできるスレッドの数を制限するためによく使用されます」

その API はコンテナ固有のままかもしれませんが、分散セマフォの概念は、おそらくJGroupsを使用して実現できるはずです。

Google で「分散型 Java セマフォ」をざっと検索すると、上記の問題に対処できるように見えるJukeboxが見つかりました。

于 2009-01-27T17:45:52.700 に答える
1

ReadWriteLock で java.nio.channels.FileLock を使用します。

私があなたなら、File、FileChannel、およびすべての FileOutputStream をすべてのビジネス コードから非表示にします。DAO のような独自の単純なアダプター クラスに置き換えます。

例えば

abstract class MyWriter{
    private FileChannel file;
    public void writeSomething(byte[] b){
        // get VM scope write lock here
        // get file lock here
        // do write
        // release file lock
        // release readwritelock lock
    }
}
于 2009-01-27T17:00:00.593 に答える