5

書き込み用にログファイルを開く必要があります。問題は、多くのことが同時にこれを行う可能性があることであり、私は衝突を望んでいません。各書き込みは1行で、通常は約150バイト(常に1K未満)であり、時系列で取得する必要はありません。

私が望んでいるのは、試行することだと思いますflock()。失敗した場合は、数秒間試行を続けます。何度か試行してもロックを確立できない場合は、あきらめてください。

$fh=fopen($logfile, "a");

if (flock($fh, LOCK_EX|LOCK_NB)) {
  $locked=TRUE;
} else {
  $locked=FALSE;
  // Retry lock every 0.1 seconds for 3 seconds...
  $x=0; while($x++ < 30) {
    usleep(100000);
    if (flock($fh, LOCK_EX|LOCK_NB)) {
      $locked=TRUE;
      break;
    }
  }
}

if ($locked) {
  if (fwrite($fh, strftime("[%Y-%m-%d %T] ") . $logdata . "\n")) {
    print "Success.\n";
  } else {
    print "Fail.\n";
  }
  flock($fh, LOCK_UN)
} else {
  print "Lock failed.\n";
}

私には2つの質問があります。1つは一般的なもので、もう1つは具体的なものです。まず、同じソリューションをさまざまな方法(do...whileなど)で実装する以外に、PHPでのみ実行される、この種の問題を処理するためのより優れた一般的な戦略はありますか?次に、これをPHPで実装するためのより良い方法はありますか?(はい、私は戦略の部分に本当に興味があるので、これらを分離しました。)

私が検討した代替案の1つは、syslog()を使用することですが、PHPコードは、システムレベルの管理(つまり、/ etc / syslog.confへの追加)がオプションとして利用できないプラットフォームで実行する必要がある場合があります。

更新:randy|LOCK_NBの提案に従って、上記のコードに追加されました。

4

1 に答える 1

4

PHPでログを作成する長い経験(Linuxで!)では、(何百もの同時書き込みと同時書き込みを行っても)競合の問題を経験したことはありません。とても単純なスキップロック管理:

$fh=fopen($logfile, "a");
if (fwrite($fh, strftime("[%Y-%m-%d %T] ") . $logdata . "\n")) {
    print "Success.\n";
  } else {
    print "Fail.\n";
  }
fclose($fh);

この戦略については、ファイルロギング(ロックありまたはなし)は最善の解決策ではありません。「a」が付いたすべてのfopenは、ファイルの最後にカーソルを設定するシークシステムコールを意味するためです。ファイルを開いたままにするsyslogは、このオーバーヘッドを回避します。

もちろん、「大きな」ファイルではオーバーヘッドが(パフォーマンスにおいて)重要になります。簡単な解決策は、名前に日付(または日時)を含むログファイルを作成することです。

追加

apacheパッケージにはテスタープログラムが含まれています:ab、同時実行でクエリを実行できるようにすることで、10〜1000スレッドで実行される1000000のクエリでサーバーにストレスを与える私の論文をテストできます。

追加-コメントに続いて

いいえ、それは不可能な作業ではありません。

http://php.net/manual/en/function.fwrite.phpからメモを見つけました

ハンドルが追加モードでfopen()された場合、fwrite()はアトミックです(一部のプラットフォームでは、文字列のサイズがファイルシステムのブロックサイズを超えない限り、ファイルがローカルファイルシステム上にある限り)。つまり、fwrite()を呼び出す前にリソースをflock()する必要はありません。すべてのデータは中断することなく書き込まれます。

ブロックの大きさをバイト単位で知るには(通常は4k):

dumpe2fs / dev / sd_your_disk_partition | less -i

書き込みの「アトミック性」は、書き込みを行う他の「エージェント」をブロックすることで実現されます(「psax」で「D」ステータスのプロセスが表示される場合)が、PHPストリーム機能はこの問題を解決できます。*stream_set_blocking*を参照してください。このアプローチでは部分的な書き込みが発生する可能性があるため、レコードの整合性を検証する必要があります。

いずれにせよ、fwrite(ネットワークまたはファイル)は、 flockの使用に関係なく、ブロック/障害の影響を受けやすくなります。IMHOの群れは頭上だけを導入します。

あなたの最初の質問とあなたの目標(非常にリスク回避的な環境で企業ポリシーを実装しようとする)について、fwriteでさえ問題になる可能性がありますが、私は単純な解決策を想像することしかできません:DBを使用する

  • 複雑さのほとんどはPHPからのものであり、Cで書かれています。
  • 操作の流れの完全な制御
  • 並行性の高レベル
于 2012-07-01T19:36:18.210 に答える