如何在一段时间内重试PHP flock()?

时间:2012-06-26 17:18:46

标签: php locking

我需要打开一个日志文件进行写作。麻烦的是,许多事情可能同时做到这一点,我不想要冲突。每次写入都是一行,通常大约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";
}

我有两个问题,一个是普通的,一个是具体的。首先,除了以不同的方式(do...while等)实现相同的解决方案之外,是否有更好的通用策略来处理这种仅在PHP中运行的问题?其次,有没有更好的方法在PHP中实现它? (是的,我将这些分开了,因为我对战略部分非常感兴趣。)

我考虑过的一个替代方案是使用syslog(),但PHP代码可能需要在系统级管理(即向/etc/syslog.conf添加内容)可能无法使用的平台上运行一个选项。

根据{{​​3}}的建议,

更新:|LOCK_NB添加到上面的代码中。

1 个答案:

答案 0 :(得分: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 保持文件打开可以避免这种开销。

当然,开销在“大”文件中变得有意义(在性能上),一个简单的解决方案是在名称中创建日期(或日期时间)的日志文件。

ADD

apache包中包含一个测试程序: ab ,允许在并发中进行查询,你可以测试我的论文,用10到1000个线程完成的1000000查询来强调你的服务器。

ADD - 发表评论

不,这不是一项不可能完成的任务。

我从http://php.net/manual/en/function.fwrite.php

找到了注释
  

如果handle在附加模式下被fopen()编辑,则fwrite()s是原子的(除非   在某些情况下,字符串的大小超过了文件系统的块大小   平台,只要文件在本地文件系统上)。那是,   在调用fwrite()之前不需要flock()资源;所有的   数据将不间断地写入。

知道块的大小(通常为4k):

  

dumpe2fs / dev / sd_your_disk_partition | less -i

写入的“原子性”实现阻止其他“代理”写入(当您在“ps ax”中看到“D”状态的进程时),但是 PHP 流工具< / strong>可以解决这个问题,请参阅:* stream_set_blocking *。 这种方法可能会引入部分写入,因此您必须验证记录的完整性。

在任何情况下, fwrite (网络或文件)都容易受到阻止/失败,无论使用 flock 。 IMHO flock只引入了开销。

关于您的原始问题和您的目标(尝试在高度风险厌恶的环境中实施公司政策),即使是一个有问题的fwrite,我只能想象一个简单的解决方案:使用数据库

  • 大多数复杂性都是用PHP编写的,用C语言编写!
  • 完全控制操作流程
  • hi并发级别