我在通过 NFS 共享文件系统的系统上使用 PHP flock()(使用系统 flock)。
当我使用 EXCLUSIVE、BLOCKING 锁访问 2 台服务器上的同一个(共享)文件时,flock() 会失败。当然,只有一个进程应该能够获得(独占)锁,但在这种情况下,另一个进程应该被阻止。但我看到的是 flock() 调用立即返回并出现错误。
如果我在 1 台服务器上执行同样的事情(启动 2 个程序来获取 EXCLUSIVE、BLOCKING 锁),它就可以工作。
问题是:这应该有效吗?一般不建议通过 NFS 使用文件锁定吗?(给出的根本不起作用的信息通常是指过时的信息)。如果这应该有效,我该怎么做才能调试或解决这个问题?
测试设置
(我用过PHP 脚本,但可以使用命令行 flock 进行更简单的测试设置):
系统 1:
flock -x lock.txt sleep 10
结果:获取锁
系统 2(当系统 1 已获得锁定时):
flock -x lock.txt sleep 10
这将立即返回
flock:lock.txt:没有可用的锁
诊断
strace flock -x lock.txt sleep 10
flock(3, LOCK_EX) = -1 ENOLCK (No locks available)
添加调试信息rpcdebug -m nfs all
(在客户端)
这是失败的群集尝试的日志。
/var/log/消息
Feb 4 10:24:51 myclient kernel: NFS: initiated commit call
Feb 4 10:24:51 myclient kernel: NFS: 6791 nfs_commit_done (status 0)
Feb 4 10:24:51 myclient kernel: NFS: nfs_update_inode(0:40/916722366 fh_crc=0xa8927c2a ct=1 info=0x27e7f)
Feb 4 10:24:51 myclient kernel: NFS: commit (0:40/916722366 1358@4096) OK
Feb 4 10:24:59 myclient kernel: NFS: permission(0:41/872433655), mask=0x81, res=-10
Feb 4 10:24:59 myclient kernel: NFS call access
Feb 4 10:24:59 myclient kernel: NFS: nfs_update_inode(0:41/872433655 fh_crc=0x9e46fe1a ct=2 info=0x27e7f)
Feb 4 10:24:59 myclient kernel: NFS reply access: 0
Feb 4 10:24:59 myclient kernel: NFS: permission(0:41/872433655), mask=0x1, res=0
Feb 4 10:24:59 myclient kernel: NFS: nfs_lookup_revalidate(/lock.txt) is valid
Feb 4 10:24:59 myclient kernel: NFS: permission(0:41/915542237), mask=0x10, res=0
Feb 4 10:24:59 myclient kernel: NFS: dentry_delete(/lock.txt, 40808cc)
Feb 4 10:24:59 myclient kernel: NFS: permission(0:41/872433655), mask=0x81, res=0
Feb 4 10:24:59 myclient kernel: NFS: nfs_lookup_revalidate(/lock.txt) is valid
Feb 4 10:24:59 myclient kernel: NFS: revalidating (0:41/915542237)
Feb 4 10:24:59 myclient kernel: NFS call getattr
Feb 4 10:24:59 myclient kernel: NFS reply getattr: 0
Feb 4 10:24:59 myclient kernel: NFS: nfs_update_inode(0:41/915542237 fh_crc=0x35293470 ct=1 info=0x27e7f)
Feb 4 10:24:59 myclient kernel: NFS: nfs3_forget_cached_acls(0:41/915542237)
Feb 4 10:24:59 myclient kernel: NFS: (0:41/915542237) revalidation complete
Feb 4 10:24:59 myclient kernel: NFS: dentry_delete(/lock.txt, 40808cc)
Feb 4 10:24:59 myclient kernel: NFS: nfs_weak_revalidate: inode 872433655 is valid
Feb 4 10:24:59 myclient kernel: NFS: permission(0:41/872433655), mask=0x81, res=0
Feb 4 10:24:59 myclient kernel: NFS: revalidating (0:41/915542237)
Feb 4 10:24:59 myclient kernel: NFS call getattr
Feb 4 10:24:59 myclient kernel: NFS reply getattr: 0
Feb 4 10:24:59 myclient kernel: NFS: nfs_update_inode(0:41/915542237 fh_crc=0x35293470 ct=1 info=0x27e7f)
Feb 4 10:24:59 myclient kernel: NFS: (0:41/915542237) revalidation complete
Feb 4 10:24:59 myclient kernel: NFS: nfs_lookup_revalidate(/lock.txt) is valid
Feb 4 10:24:59 myclient kernel: NFS call access
Feb 4 10:24:59 myclient kernel: NFS: nfs_update_inode(0:41/915542237 fh_crc=0x35293470 ct=1 info=0x27e7f)
Feb 4 10:24:59 myclient kernel: NFS reply access: 0
Feb 4 10:24:59 myclient kernel: NFS: permission(0:41/915542237), mask=0x24, res=0
Feb 4 10:24:59 myclient kernel: NFS: open file(/lock.txt)
Feb 4 10:24:59 myclient kernel: NFS: llseek file(/lock.txt, 0, 1)
Feb 4 10:24:59 myclient kernel: NFS: flock(/lock.txt, t=1, fl=82)
Feb 4 10:24:59 myclient kernel: NFS: flush(/lock.txt)
Feb 4 10:24:59 myclient kernel: NFS: release(/lock.txt)
Feb 4 10:24:59 myclient kernel: NFS: dentry_delete(/lock.txt, 40808cc)
系统
红帽企业版
uname -r
3.10.0-1062.9.1.el7.x86_64
nfsstat –s
Server rpc stats:
calls badcalls badclnt badauth xdrcall
0 0 0 0 0
Client rpc stats:
calls retrans authrefrsh
588092 0 588092
Client nfs v3:
null getattr setattr lookup access readlink
0 0% 350667 59% 0 0% 1714 0% 231693 39% 5 0%
read write create mkdir symlink mknod
748 0% 2243 0% 0 0% 3 0% 0 0% 0 0%
remove rmdir rename link readdir readdirplus
0 0% 0 0% 0 0% 0 0% 0 0% 110 0%
fsstat fsinfo pathconf commit
0 0% 10 0% 5 0% 889 0%
安装选项:
rw,nosuid,noexec,noatime,nodiratime,上下文 = system_u:object_r:httpd_sys_rw_content_t:s0,vers = 3,rsize = 131072,wsize = 131072,namlen = 255,hard,proto = tcp,timeo = 600,retrans = 2,sec = sys,mountaddr = someip,mountvers = 3,mountport = 300,mountproto = udp,local_lock = none,addr = someip
我搜索过这个主题。一些搜索结果如下很老,没有得到答复或者参考 Linux 上尚不支持共享锁的旧版本的 flock。
例如在我的系统上,man 2 flock 给出以下信息:
在 Linux 内核 2.6.11 之前,flock() 不会通过 NFS 锁定文件(即锁定范围仅限于本地系统)。相反,可以使用 fcntl(2) 字节范围锁定,只要 Linux 版本足够新并且服务器支持锁定,该锁定在 NFS 上是可行的。从 Linux 2.6.12 开始,NFS 客户端通过将 flock() 锁定模拟为整个文件上的字节范围锁定来支持 flock() 锁定。这意味着 fcntl(2) 和 flock() 锁定确实会通过 NFS 相互交互。从 Linux 2.6.37 开始,内核支持兼容模式,允许将 flock() 锁定(以及 fcntl(2) 字节区域锁定)视为本地锁定;请参阅 nfs(5) 中对 local_lock 选项的讨论。
答案1
已经有很多资源可以解决这个问题。总之,flock
由于手册页中给出的原因,您无法直接在 NFS 上使用。
请参阅这些链接: