8

私は非常に計算量の多い科学的な仕事をしていて、時々結果を吐き出します。仕事は基本的に同じことを何度もシミュレートすることなので、異なるOSを使用する複数のコンピューターに分割されます。すべてのコンピューターがNFS/Sambaを介して同じファイルシステムを参照できるため、これらすべてのインスタンスからの出力を同じファイルに送信したいと思います。制約は次のとおりです。

  1. 安全な同時追加を許可する必要があります。別のコンピューター上の他のインスタンスが現在ファイルに追加している場合は、ブロックする必要があります。
  2. パフォーマンスはカウントされませ。各インスタンスのI/Oは、1分あたりわずか数バイトです。
  3. シンプルさは重要です。これの全体的なポイントは(純粋な好奇心を除いて)、すべてのインスタンスが異なるファイルに書き込み、これらのファイルを手動でマージするのをやめることができるようにすることです。
  4. ファイルシステムの詳細に依存してはなりません。NFSまたはSambaマウント上の不明なファイルシステムで動作する必要があります。

私が使用している言語は、重要な場合に備えてDです。私が見たところ、これを行うように見える標準ライブラリには何もありません。D固有の回答と一般的な言語に依存しない回答の両方が完全に受け入れられ、高く評価されています。

4

5 に答える 5

8

NFS では、クライアント側のキャッシュと古いデータに関する問題に直面します。以前、NFS で動作する OS に依存しないロック モジュールを作成しました。[datafile].lock ファイルを作成するという単純な考え方は、NFS ではうまく機能しません。これを回避するための基本的な考え方は、ロック ファイル [datafile].lock を作成することです。これは、存在する場合、ファイルがロックされていないことを意味し、ロックを取得したいプロセスがファイルの名前を [datafile].lock.[ホスト名].[pid]. 名前の変更は、ロックの排他性を保証するために NFS 上で十分に機能する、十分にアトミックな操作です。残りは基本的に、ロックを解除してロックファイルの名前を [datafile].lock に戻す前にプロセスが終了した場合に備えて、フェイルセーフ、ループ、エラーチェック、およびロック取得の束です。

于 2009-03-20T23:53:42.293 に答える
2

ひねりを加えたファイルのロック

他の回答が述べたように、最も簡単な方法は、データファイルと同じディレクトリにロックファイルを作成することです。

複数のPCを介して同じファイルにアクセスできるようにしたいので、私が考えることができる最善の解決策は、現在データファイルに書き込んでいるマシンの識別子を含めることです。

したがって、データファイルへの書き込み順序は次のようになります。

  1. ロックファイルが存在するかどうかを確認します

  2. ロックファイルがある場合は、その内容に私の識別子が含まれていることを確認して、私がそれを所有しているかどうかを確認します。
    その場合は、データファイルに書き込んでから、ロックファイルを削除してください。
    そうでない場合は、1秒または少しランダムな時間待ってから、サイクル全体を再試行してください。

  3. ロックファイルがない場合は、自分の識別子を使用してファイルを作成し、競合状態を回避するためにサイクル全体を再試行します(ロックファイルが本当に私のものであることを再確認してください)。

識別子とともに、タイムスタンプをロックファイルに記録し、指定されたタイムアウト値よりも古いかどうかを確認します。
タイムスタンプが古すぎる場合は、ロックファイルが古くなっていると想定し、データファイルに書き込んでいるPCの1つがクラッシュしたか、接続が失われた可能性があるため、ロックファイルを削除します。

別の解決策

データファイルの形式を制御している場合は、ファイルの先頭にある構造を予約して、ロックされているかどうかを記録することができます。
この目的のためにバイトを予約するだけの場合、たとえば、00データファイルがロックされておらず、他の値が現在書き込み中のマシンの識別子を表していると想定できます。

NFSの問題

OK、いくつか追加します。JiriKloudaは、NFSがクライアント側のキャッシュを使用しているため、実際のロックファイルが未確定の状態になることを正しく指摘しているためです。

この問題を解決するいくつかの方法:

  • noacまたはsyncオプションを使用してNFSディレクトリをマウントします。これは簡単ですが、クライアントとサーバー間のデータの一貫性を完全に保証するものではありません。そのため、問題が発生する可能性がありますが、場合によっては問題ない可能性があります。

  • O_DIRECT、、O_SYNCまたは属性を使用して、ロックファイルまたはデータファイルを開きO_DSYNCます。これにより、キャッシュが完全に無効になります。
    これによりパフォーマンスは低下しますが、一貫性が確保されます。

  • を使用してデータファイルをロックできる場合がありますflock()が、その実装は不十分であり、特定のOSが実際にNFSロックサービスを使用しているかどうかを確認する必要があります。それ以外の場合は何もしません。
    データファイルがロックされている場合、書き込みのためにデータファイルを開いている別のクライアントは失敗します。
    そうそう、SMB共有では機能しないように思われるので、それを忘れるのがおそらく最善です。

  • NFSを使用せず、代わりにSambaを使用してください。このテーマに関する優れた記事があり、NFSが使用シナリオに対する最良の答えではない理由があります。
    この記事には、ファイルをロックするためのさまざまな方法もあります。

  • Jiriのソリューションも良いものです。

基本的に、物事を単純にしたい場合は、複数のマシン間で共有される頻繁に更新されるファイルにNFSを使用しないでください。

何か違います

小さなデータベースサーバーを使用してデータを保存し、NFS / SMBロックの問題を完全に回避するか、現在の複数のデータファイルシステムを維持し、結果を連結するための小さなユーティリティを作成します。
それでも、問題に対する最も安全で簡単な解決策になる可能性があります。

于 2009-03-21T00:15:32.723 に答える
2

古典的な解決策は、ロックファイル、より正確にはロックディレクトリを使用することです。すべての一般的なOSで、ディレクトリの作成は不可分操作であるため、ルーチンは次のようになります。

  • 固定された場所に固定された名前のロックディレクトリを作成してみてください
  • 作成が失敗した場合は、1秒ほど待ってから再試行してください-成功するまで繰り返します
  • データを実際のデータファイルに書き込みます
  • ロックディレクトリを削除します

これは、CVSなどのアプリケーションで長年にわたって多くのプラットフォームで使用されてきました。唯一の問題は、書き込み中およびロックを解除する前にアプリがクラッシュするまれなケースで発生します。

于 2009-03-21T00:03:29.353 に答える
2

ファイルと他のコンピューターの間にある単純なサーバーを構築しないのはなぜですか?

その後、データ形式を変更したい場合は、サーバーを変更するだけで済み、すべてのクライアントを変更する必要はありません。

私の意見では、ネットワーク ファイル システムを使用するよりも、サーバーを構築する方がはるかに簡単です。

于 2009-03-21T02:33:44.797 に答える
1

Dはわかりませんが、ミューテックスファイルを使用してジョブを実行するとうまくいく可能性があります。役立つと思われる擬似コードを次に示します。

do {
  // Try to create a new file to use as mutex.
  // If it's already created, it will throw some kind of error.
  mutex = create_file_for_writing('lock_file');
} while (mutex == null);

// Open your log file and write results
log_file = open_file_for_reading('the_log_file');
write(log_file, data);
close_file(log_file);

close_file(mutex);
// Free mutex and allow other processes to create the same file.
delete_file(mutex); 

したがって、すべてのプロセスがミューテックスファイルを作成しようとしますが、勝ったプロセスだけが続行できます。出力を書き込んだら、ミューテックスを閉じて削除し、他のプロセスが同じことを実行できるようにします。

于 2009-03-20T23:35:27.143 に答える