我在通过 NFS 共享文件系统的系统上使用 PHPflock()(它使用系统flock)。
当我使用 EXCLUSIVE、BLOCKING 锁访问 2 个服务器上的相同(共享)文件时,flock() 失败。当然,只有一个进程应该能够获得(独占)锁,但在这种情况下,另一个应该阻塞。但我看到的是,flock() 调用立即返回错误。
如果我在 1 台服务器上做同样的事情(启动 2 个程序以获得独占、阻塞锁),它就可以工作。
问题是:这应该工作吗?一般不建议通过 NFS 使用文件锁定吗?(给出的信息根本不起作用通常指的是过时的信息)。如果这应该工作,我可以做些什么来调试或解决这个问题?
测试设置
(我使用了PHP 脚本,但可以使用命令行来进行更简单的测试设置):
系统一:
flock -x lock.txt sleep 10
结果:获得锁
系统 2(当系统 1 获得锁时):
flock -x lock.txt sleep 10
这立即返回
羊群: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)
系统
RHEL
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,context=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 提供以下信息:
在 2.6.11 之前的 Linux 内核中,flock() 不会通过 NFS 锁定文件(即锁定的范围仅限于本地系统)。取而代之的是,可以使用 fcntl(2) 字节范围锁定,它确实可以在 NFS 上工作,前提是 Linux 的最新版本和支持锁定的服务器。从 Linux 2.6.12 开始,NFS 客户端通过将flock() 锁模拟为整个文件上的字节范围锁来支持flock() 锁。这意味着 fcntl(2) 和 flock() 锁确实通过 NFS 相互交互。从 Linux 2.6.37 开始,内核支持一种兼容模式,允许将 flock() 锁(以及 fcntl(2) 字节区域锁)视为本地锁;请参阅 nfs(5) 中关于 local_lock 选项的讨论。