9

我最新的 web 应用程序的一部分需要写入文件作为其日志记录的一部分。我注意到的一个问题是,如果有几个并发用户,写入可以相互覆盖(而不是附加到文件)。我认为这是因为目标文件可以同时在多个地方打开。

flock(...)通常很棒,但它似乎不适用于 NFS ......这对我来说是一个大问题,因为生产服务器使用 NFS 阵列。

我见过的最接近实际解决方案的事情是尝试创建一个锁目录并等待它被创建。说这缺乏优雅是对今年,可能是十年的轻描淡写。

有更好的想法吗?

编辑:我应该补充一点,我在服务器上没有 root,并且以另一种方式进行存储在短期内并不可行,尤其是在我的最后期限内。

4

6 回答 6

15

Directory operations are NOT atomic under NFSv2 and NFSv3 (please refer to the book 'NFS Illustrated' by Brent Callaghan, ISBN 0-201-32570-5; Brent is a NFS-veteran at Sun).

NFSv2 has two atomic operations:

  • symlink
  • rename

With NFSv3 the create call is also atomic.

Knowing this, you can implement spin-locks for files and directories (in shell, not PHP):

lock current dir:

while ! ln -s . lock; do :; done

lock a file:

while ! ln -s ${f} ${f}.lock; do :; done 

unlock (assumption, the running process really acquired the lock):

unlock current dir:

mv lock deleteme && rm deleteme

unlock a file:

mv ${f}.lock ${f}.deleteme && rm ${f}.deleteme

Remove is also not atomic, therefore first the rename (which is atomic) and then the remove.

For the symlink and rename calls, both filenames have to reside on the same filesystem. My proposal: use only simple filenames and put file and lock into the same directory.

于 2008-11-09T10:27:55.883 回答
4

另一个肮脏的黑客攻击将是flock()“本地”文件,并且只有在您持有本地文件的锁定时才打开/写入 NFS 文件。

编辑:从flock()页面:

flock() 不适用于 NFS 和许多其他网络文件系统。查看您的操作系统文档以获取更多详细信息。

编辑2:

当然,总是使用数据库来同步访问(我假设您的应用程序使用数据库)。但是,如果您要进行大量日志记录,这将对性能造成很大影响。

如果只是为了记录,你真的需要一个集中的日志文件吗?您可以在本地登录(如果需要,甚至在一天结束时轮换日志时合并日志)?

于 2008-10-20T13:39:11.773 回答
3

一种方法是设置一个Memcache实例,在每个虚拟服务器之间共享。您可以flock()在启动本地文件操作时将文件名条目放入缓存中,并在完成后擦除它。

每个服务器都可以在文件操作之前访问这个池,并查看这个“锁”是否存在,例如

// Check for lock, using $filename as key
$lock = $memcache->get($filename);

if(!$lock) {
    // Set lock in memcache for $filename
    $memcache->set($filename, 1);

    // Do file operations...

    // Blow away "lock"
    $memcache->delete($filename);
}

不是最优雅的解决方案,但应该使您能够相对轻松地控制设置中所有服务器的锁。

于 2008-10-20T14:00:44.273 回答
2

You can also use dio_fcntl() to lock files on NFS volumes. It requires the dio package, which may not be part of your php installation by default.

于 2010-05-21T01:55:12.230 回答
1

Even though you cannot flock() files on NFS and I/O can be asynchroneous, directory operations on NFS are atomic. That means that at at any given time, a directory does, or does not exist.

To implement your own NFS locking feature, check or create a directory when you want to have it locked and remove it when you're done.

Unfortunately, it's probably not compatible with any other application you didn't write yourself.

于 2008-10-20T18:18:16.250 回答
0

应该只使用 memcache add 并避免竞争条件。

if ($memcache->add($filename, 1, 1))
{
   $memcache->delete($filename);
}
于 2008-10-20T15:17:37.067 回答