如何在一段时间内重试PHP flock()? [英] How do I retry a PHP flock() for a period of time?

查看:108
本文介绍了如何在一段时间内重试PHP flock()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要打开一个日志文件进行写入.麻烦的是,很多事情可能同时发生,我不想发生冲突.每次写入都将是一行,通常大约为150个字节(且始终小于1K),并且严格要求按时间顺序进行存储.

I need to open a log file for writing. Trouble is, many things may do this at the same time, and I don't want conflicts. Each write will be a single line, generally about 150 bytes (and always less than 1K), and getting things in chronological order is not strictly required.

思考我想要的是尝试flock(),如果失败,请继续尝试几秒钟.如果尝试多次后仍无法建立锁,请放弃.

I think what I want is to attempt to flock(), and if it fails, keep trying for a few seconds. If a lock can't be established after a number of tries, then give up.

$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中实现呢? (是的,我将它们分开是因为我对策略部分真的很感兴趣.)

I have two questions, one general and one specific. First, aside from implementing the same solution in different ways (do...while, etc), is there a better general strategy for handling this kind of problem, that runs solely in PHP? Second, is there a better way of implementing this in PHP? (Yes, I separated these because I'm really interested in the strategy part.)

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

One alternative I've considered is to use syslog(), but the PHP code may need to run on platforms where system-level administration (i.e. adding things to /etc/syslog.conf) may not be available as an option.

更新:根据 randy 的建议,在上面的代码中添加了|LOCK_NB.

UPDATE: added |LOCK_NB to the code above, per randy's suggestion.

推荐答案

以我在PHP中制作日志的长期经验(在Linux下!),我从未遇到过冲突问题(即使有数百个同时进行和并发写入的情况).如此简单的跳过锁管理:

In my long experience in PHP making logs (under linux!) I've never experienced problems of conflicts (even with hundreds of simultaneus and concurrent writes). So simple skip lock maagement:

$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 保持文件打开以避免这种开销.

About this strategy the file logging (with or without lock) is not the best solution, because every fopen with the "a" imply a seek syscall to set the cursor at the end of the file. syslog keeping the file open avoid this overhead.

当然,对于大"文件,开销会变得很重要(在性能上),一个简单的解决方案是创建名称为日期(或日期时间)的日志文件.

Of course the overhead become significative (in performance) with "big" files, an easy solution is create log file with date (or date-time) in the name.

添加

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

apache package include a tester program: ab, allowing doing query in concurrency, you can test my thesis stressing your server with 1000000 of query done by 10to1000 threads.

添加-在评论之后

不,这不是不可能的任务.

No, it'not an impossible task.

我从 http://php中找到了便笺. net/manual/en/function.fwrite.php

I found a note from http://php.net/manual/en/function.fwrite.php

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

If handle was fopen()ed in append mode, fwrite()s are atomic (unless the size of string exceeds the filesystem's block size, on some platforms, and as long as the file is on a local filesystem). That is, there is no need to flock() a resource before calling fwrite(); all of the data will be written without interruption.

了解一个字节的块有多大(通常为4k):

to know how big is a block in bytes (usual 4k):

dumpe2fs/dev/sd_your_disk_partition | less -i

dumpe2fs /dev/sd_your_disk_partition |less -i

实现写入的原子性"是为了阻止其他代理"进行写入(当您在"ps ax"中看到处于"D"状态的进程)时,但是 PHP 流设施可以解决此问题,请参阅:* stream_set_blocking *. 这种方法可能会引入部分写入,因此您将必须验证记录的完整性.

The "atomicity" of write is realized blocking other "agents" to write (when you see process in "D" status in "ps ax"), BUT PHP stream facility can solve this problem, see: *stream_set_blocking*. This approach can introduce partial writes, so you will have to validate the integrity of your records.

无论如何, fwrite (网络或文件)很容易被阻止/失败,无论使用 flock 如何.恕我直言,羊群只会带来开销.

In any case a fwrite (network or file) is susceptible to block/failure regardless of use of flock. IMHO flock introduce only overhead.

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

About your original questions AND your goal (trying to implement corporate policy in a highly risk-averse environment), where even a fwrite can be problematic, I can only imagine a simple solution: use a DB

  • 最复杂的部分不是PHP,而是用C编写的!
  • 完全控制操作流程
  • 并发级别

这篇关于如何在一段时间内重试PHP flock()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆