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

gho*_*oti 5 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";
}
Run Code Online (Sandbox Code Playgroud)

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

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

更新:|LOCK_NB按照兰迪的建议添加到上面的代码中.

Iva*_*oni 3

根据我在 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);
Run Code Online (Sandbox Code Playgroud)

关于此策略,文件日志记录(带锁或不带锁)不是最佳解决方案,因为每个带有“ a ”的 fopen 都意味着一个搜索系统调用来将光标设置在文件末尾。syslog保持文件打开可以避免这种开销。

当然,对于“大”文件,开销变得很大(在性能方面),一个简单的解决方案是创建名称中包含日期(或日期时间)的日志文件。

添加

apache 包包含一个测试程序:ab,允许并发执行查询,您可以测试我的论文,通过 10to1000 个线程完成 1000000 个查询来强调您的服务器。

添加 - 跟随评论

不,这不是一个不可能的任务。

我从http://php.net/manual/en/function.fwrite.php找到了一条注释

如果句柄是在附加模式下 fopen()ed,则 fwrite() 是原子的(除非在某些平台上字符串的大小超过文件系统的块大小,并且只要文件位于本地文件系统上)。也就是说,在调用fwrite()之前不需要flock()资源;所有数据都将不间断地写入。

要知道一个块有多大(以字节为单位)(通常为 4k):

dumpe2fs /dev/sd_your_disk_partition |less -i

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

在任何情况下,无论是否使用集群,fwrite(网络或文件)都容易受到阻塞/失败。恕我直言,羊群仅介绍开销。

关于你最初的问题和你的目标(试图在高度规避风险的环境中实施公司政策),即使是 fwrite 也可能有问题,我只能想象一个简单的解决方案:使用 DB

  • 大部分复杂性都来自于 PHP 并用 C 编写!
  • 完全控制操作流程
  • 高并发水平