4.2.6 常见信号应用场景:优雅退出、重载配置、超时控制

常见信号应用场景主要集中在进程生命周期管理与可运维性保障,典型目标是“优雅退出”“重载配置”“超时控制”。本节给出原理草图、可执行示例、排错要点与练习。

原理草图(信号在进程与子任务中的流转):

文章图片

优雅退出(SIGTERM/SIGINT + 超时强杀)
- 目的:在终止前完成连接排空、状态落盘与资源释放。
- 关键命令解释:
- kill -TERM <pid>:发送SIGTERM请求进程优雅退出。
- kill -KILL <pid>:无法捕获,强制终止(最后手段)。
- ps -o pid,ppid,stat,cmd -p <pid>:查看进程状态。

示例:用脚本模拟优雅退出

# /opt/app/graceful.sh
#!/usr/bin/env bash
set -e

cleanup() {
  echo "[`date +%T`] 收到SIGTERM,开始清理..."
  # 模拟关闭连接与落盘
  sleep 2
  echo "[`date +%T`] 清理完成,退出"
  exit 0
}

trap cleanup SIGTERM SIGINT

echo "[`date +%T`] 服务启动,PID=$$"
# 模拟主循环
while true; do
  echo "[`date +%T`] 处理请求..."
  sleep 1
done

运行与验证:

chmod +x /opt/app/graceful.sh
nohup /opt/app/graceful.sh >/tmp/graceful.log 2>&1 &
echo "PID=$(pgrep -f /opt/app/graceful.sh)"
kill -TERM $(pgrep -f /opt/app/graceful.sh)
tail -n 5 /tmp/graceful.log

预期效果:日志中出现“收到SIGTERM…清理完成,退出”。
排错要点:
- 进程不退出:确认是否捕获SIGTERM(strace -p <pid> -e signal)。
- 退出太慢:检查清理逻辑耗时,结合systemd的TimeoutStopSec

重载配置(SIGHUP/SIGUSR1)
- 目的:不停机更新配置或切换日志。
- 关键命令解释:
- kill -HUP <pid>:请求进程重载配置。
- nginx -t:测试Nginx配置语法。

示例:以Nginx为例热加载

# 安装(如未安装)
# RHEL/CentOS:
# yum -y install nginx
# Debian/Ubuntu:
# apt-get -y install nginx

# 修改配置并校验
nginx -t
# 发送重载信号
kill -HUP $(cat /run/nginx.pid)

# 验证
ss -lntp | grep nginx
tail -n 20 /var/log/nginx/error.log

预期效果:端口持续监听,无进程重启;日志显示“signal process started”。
排错要点:
- 重载失败:先nginx -t,再确认pid文件路径。
- 配置未生效:检查是否有多份配置被include。

超时控制(SIGALRM 或外部watchdog)
- 目的:避免任务卡死、调用外部依赖超时。
- 关键命令解释:
- timeout 5s <cmd>:超时后发送SIGTERM(可用-k设定SIGKILL)。
- trap 'handler' ALRM:脚本内捕获定时器超时。

示例:使用timeout保护任务

# 模拟阻塞任务
sleep 100

# 通过timeout限制
timeout -k 2s 5s sleep 100
echo "返回码=$?"  # 124表示超时

示例:脚本内超时控制

# /opt/app/timeout_job.sh
#!/usr/bin/env bash
set -e
trap 'echo "超时,退出"; exit 124' ALRM
(sleep 5; kill -ALRM $$) &

echo "开始任务..."
sleep 30

排错要点:
- 任务被误杀:提高超时阈值或区分“长任务”与“卡死”。
- 超时无响应:确认是否被trap捕获,或信号被屏蔽。

常用信号与默认行为速查(命令解释)

kill -l            # 列出信号
kill -TERM <pid>   # 优雅退出
kill -HUP <pid>    # 传统重载/日志切换
kill -USR1 <pid>   # 由应用自定义
kill -KILL <pid>   # 强制终止

练习
1) 编写脚本捕获SIGTERM,模拟“停止接收新请求”后退出。
2) 修改Nginx配置,将worker_connections调小,重载并验证新值生效。
3) 使用timeout -k为一个备份脚本设定总超时与强杀时间。