sigterm允许php进程优雅退出,可捕获并执行清理逻辑;sigkill由内核强制终止,无法拦截,仅作兜底使用。

SIGTERM 和 SIGKILL 是 PHP 进程管理中最关键的两个终止信号,它们的本质区别不在于“谁发的”,而在于“进程能不能反应”。SIGTERM 允许 PHP 做清理、保存状态、释放资源;SIGKILL 则直接拔电源,进程连最后一行日志都来不及输出。
为什么 SIGTERM 是“优雅退出”的核心
SIGTERM(编号 15)是 Docker、systemd、Supervisor 等主流管理工具默认发送的终止信号。它可被 PHP 捕获、延迟响应、甚至临时忽略(需谨慎),为常驻进程争取完成手头任务的时间。
- PHP 中通过 pcntl_signal() 或更健壮的 pcntl_signal_dispatch() 注册处理函数,收到 SIGTERM 后可执行队列清空、数据库连接关闭、临时文件清理等逻辑
- 在 Swoole 协程环境中,使用 Swoole\Coroutine\Signal::add(SIGTERM, $callback) 实现非阻塞监听,避免中断其他协程
- 典型场景:消费者进程刚从 Redis 队列 pop 出一条消息,此时收到 SIGTERM,应暂停新任务拉取,优先处理完当前消息再退出,防止消息丢失
SIGKILL 不可替代,也不该被依赖
SIGKILL(编号 9)由内核强制执行,PHP 完全无法拦截或延缓。它不是“更狠的退出方式”,而是“兜底保命机制”——当进程卡死、信号处理函数陷入死循环、或已失去响应时的唯一手段。
- Docker 在发送 SIGTERM 后等待默认 10 秒,超时即发 SIGKILL。这个时间窗口必须由 PHP 主动管理(例如用 pcntl_alarm() 或协程 sleep 控制退出倒计时)
- 调用 kill -9 或 posix_kill($pid, SIGKILL) 会跳过所有用户层逻辑,可能导致未刷盘的日志丢失、数据库事务未提交、共享内存残留等问题
- 开发中应避免主动触发 SIGKILL;运维中应视其为异常信号,而非常规流程一环
实际部署中容易踩的坑
容器化 PHP 应用最常因信号处理不当导致上线失败或数据异常,关键点不在“会不会写 signal handler”,而在“是否与运行模型匹配”。
- 普通 CLI 脚本需配合 pcntl_signal_dispatch() 手动轮询(尤其 PHP pcntl_async_signals(true) 自动分发
- FPM 模式下,master 进程响应 SIGTERM 并优雅重启 worker,但单个 worker 内部的长任务(如大文件导出)仍需自行监听信号并中断
- 使用 Swoole 时,不能混用 pcntl_* 和 Swoole\Process::signal,前者在异步事件循环中不可靠,后者才是协程安全方案
- 守护进程需确保标准输入/输出重定向到 /dev/null,否则 signal handler 中的 echo/var_dump 可能引发警告甚至崩溃
一个最小可行的 SIGTERM 响应示例
适用于基础 CLI worker:
// 注册信号处理器
pcntl_signal(SIGTERM, function ($sig) {
echo "收到 SIGTERM,开始退出流程...\n";
// 此处停掉新任务接收,完成当前处理
exit(0);
});
<p>// 启用异步信号(PHP 7.1+)
if (function_exists('pcntl_async_signals')) {
pcntl_async_signals(true);
} else {
pcntl_signal_dispatch(); // 旧版本需手动调用
}</p><p>// 主循环(模拟工作)
while ($running) {
// 处理一条消息
if (/<em> 有新消息 </em>/) {
process_message();
}
usleep(100000); // 避免空转
}
</p>php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











