在PHP中锁定NFS文件

Oli*_*Oli 7 php concurrency

我最新的webapp的一部分需要写入相当数量的文件作为其日志记录的一部分.我注意到的一个问题是,如果有少量并发用户,则写入可以相互覆盖(而不是附加到文件).我假设这是因为目标文件可以同时在多个地方打开.

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

我在实际解决方案中看到的最接近的事情是尝试创建一个锁定目录并等待它可以创建.说这种缺乏优雅的一年,甚至十年都是轻描淡写的.

有更好的想法吗?

编辑:我应该补充一点,我在服务器上没有root,并且以其他方式进行存储在任何时候都不可行,尤其是在我的截止日期之前.

小智 16

NFSv2和NFSv3下的目录操作不是原子操作(请参阅Brent Callaghan的书籍"NFS Illustrated",ISBN 0-201-32570-5; Brent是Sun的NFS退伍军人).

NFSv2有两个原子操作:

  • 符号链接
  • 改名

使用NFSv3,create调用也是原子的.

知道这一点,你可以为文件和目录实现自旋锁(在shell中,而不是PHP):

锁定当前目录:

while ! ln -s . lock; do :; done
Run Code Online (Sandbox Code Playgroud)

锁定文件:

while ! ln -s ${f} ${f}.lock; do :; done 
Run Code Online (Sandbox Code Playgroud)

解锁(假设,运行过程确实获得了锁定):

解锁当前目录:

mv lock deleteme && rm deleteme
Run Code Online (Sandbox Code Playgroud)

解锁文件:

mv ${f}.lock ${f}.deleteme && rm ${f}.deleteme
Run Code Online (Sandbox Code Playgroud)

删除也不是原子的,因此首先重命名(这是原子的)然后删除.

对于符号链接和重命名调用,两个文件名必须驻留在同一文件系统上.我的建议:只使用简单的文件名并将文件和锁定放在同一目录中.


Gre*_*reg 4

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

编辑:从flock()页面:

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

编辑2:

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

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