flock()在nfs上不生效,因nfs缺乏原子锁同步机制;应改用本地mkdir()原子锁或redis/数据库等分布式锁方案。

flock() 在 NFS 上根本不会生效
PHP 的 flock() 依赖底层 POSIX 文件锁,而大多数 NFS 实现(尤其是 v3 及默认配置的 v4)不支持或仅模拟部分 flock 行为。实测中两个进程同时调用 flock($fp, LOCK_EX) 都返回 true,锁完全形同虚设。这不是 PHP Bug,是 NFS 协议层的限制——它没有原子性的“锁状态同步”机制。
用 mkdir() 模拟原子锁(单机可靠)
利用 Linux 下 mkdir() 的原子性(路径不存在时才创建成功),可绕过 NFS 锁缺陷。关键点:
- 锁文件必须放在本地磁盘(如
/tmp/lock-xxx),不能在 NFS 挂载点内 - 锁名需带唯一标识(如进程 PID + 时间戳),避免不同请求冲突
- 必须检查
mkdir()返回值,失败说明锁已被占,不可重试写入 - 操作完成后必须
rmdir(),且不能依赖脚本结束自动清理(异常中断会残留)
示例逻辑:if (@mkdir('/tmp/myapp-lock-' . getmypid())) { /* 执行业务 */ rmdir('/tmp/myapp-lock-' . getmypid()); }
跨机器场景必须换 Redis 或数据库
如果应用部署在多个服务器、且共享同一 NFS 存储,flock() 和 mkdir() 都无效——前者跨机器无感知,后者本地磁盘无法共享。此时只能上分布式协调:
-
Redis SETNX key value EX 30:设置带 30 秒过期的锁,value 建议用随机字符串防误删 - MySQL
SELECT ... FOR UPDATE:需 InnoDB 表 + 显式事务,锁住某条记录而非整个表 - 不要用
file_put_contents($nfs_path, $data, LOCK_EX)—— 它连本地都保不住“读-改-写”,更别说 NFS
临时验证 NFS 是否真支持 flock
别猜,直接测:
- 起两个终端,在 NFS 路径下分别运行:
php -r '$f=fopen("/nfs/shared/test.lock","c"); var_dump(flock($f,LOCK_EX|LOCK_NB)); fclose($f);' - 若两者都输出
bool(true),确认失效 - 再在本地磁盘跑同样命令,应只有一个返回
true
真正麻烦的是那些没暴露问题的环境——锁偶尔失效、只在高并发时丢数据,这种比直接报错更难排查。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











