CentOS7服务器待所有PHP更新脚本实例终止后的执行方案问询
适用方案推荐
方案1:无额外依赖的优化版数据库计数方案
解决原生计数方案异常终止导致计数不准的问题,实现逻辑如下:
- 在数据库新增
running_update_tasks表,字段包含:进程PID、启动时间戳、运行状态 - PHP更新脚本启动时插入一条状态为「运行中」的记录,再统计当前有效运行任务数量
- 通过
register_shutdown_function()注册脚本终止回调,无论脚本正常结束还是异常中断,都会将对应PID的记录标记为「已结束」 - 推送更新前校验任务数时,新增两层兜底校验:
- 调用
ps -p {PID} | grep php校验进程是否实际存活,不存在的进程对应记录直接标记为失效 - 启动时间超出脚本最大允许执行时长(可按业务需求设为5-10分钟)的记录直接判定为失效
- 调用
- 统计所有有效运行任务数为0后,即可启动推送流程,同时写入全局屏蔽标记,拒绝新的更新请求
方案2:Redis 过期键方案(适合已有Redis环境的场景)
天然解决锁永久遗留问题,实现逻辑最简单:
- 每个PHP更新脚本启动时,执行
INCR update_running_count增加运行计数,同时为该脚本生成唯一的临时键,设置过期时间为脚本最大允许执行时长 - 脚本结束时执行
DECR update_running_count扣减计数 - 推送更新前先写入
update_block标记并设置过期时间(按最长推送耗时设置,防止推送脚本挂死导致永久屏蔽),新的更新请求检测到该标记存在直接拒绝 - 轮询等待
GET update_running_count返回值为0,即可启动推送流程 - 推送完成后删除
update_block标记,恢复更新请求
方案3:修正用法的flock文件锁方案
你之前遇到的flock锁无法释放问题大概率是用法错误:PHP内置的flock()是内核维护的建议性锁,持有锁的进程无论正常退出还是异常崩溃,内核都会自动释放锁,不会出现永久遗留问题。正确实现逻辑如下:
- 无需提前创建文件,直接使用
/tmp/update.lock作为全局锁文件 - 所有PHP更新脚本启动时,先获取锁文件的共享锁(
LOCK_SH),持有锁即可正常执行更新逻辑 - 推送脚本启动时尝试获取锁文件的排他锁(
LOCK_EX),操作系统会保证排他锁必须在所有共享锁释放后才能获取成功,正好满足你等待所有正在运行的更新脚本执行完成的要求 - 推送脚本持有排他锁期间,新的更新请求获取共享锁会自动阻塞,无需额外实现请求屏蔽逻辑
- 推送完成后释放排他锁即可恢复服务
补充说明
你提到的CentOS内存互斥锁也可以实现,对应POSIX信号量,PHP有sem扩展支持,逻辑和flock类似,同样由内核保证进程异常退出后自动释放锁,但需要安装额外扩展,易用性低于上述三个方案,不做优先推荐。
内容的提问来源于stack exchange,提问作者Michael Chourdakis
相关产品推荐
相关产品推荐

