Linux进程意外收到SIGTERM信号的常见场景分析与解决方案


阅读 7 次

现象描述

最近在维护一个线上服务时,发现进程突然退出,日志显示收到了SIGTERM信号并以退出码0正常终止。这让我很困惑,因为系统资源监控显示内存充足,也没有人为干预操作。

SIGTERM触发机制解析

在Linux/BusyBox环境中,SIGTERM信号的发送通常来自以下几个场景:

// 示例:查看信号处理函数
#include <signal.h>
#include <stdio.h>

void handler(int sig) {
    printf("Received signal %d\n", sig);
}

int main() {
    signal(SIGTERM, handler);
    while(1);
    return 0;
}

常见触发场景

1. 系统关机/重启流程
在init系统(如systemd/sysvinit)执行关机时,会先发送SIGTERM给所有进程

# 模拟关机信号发送
kill -TERM `pidof your_process`

2. 容器环境调度
在Kubernetes/Docker环境中,Pod终止或资源限制触发时:

# Kubernetes preStop hook示例
lifecycle:
  preStop:
    exec:
      command: ["/bin/sh", "-c", "sleep 30"]

3. 进程监控工具干预
如supervisor、monit等工具在配置超时后可能发送SIGTERM

诊断方法

通过审计日志追踪信号来源:

# 方法1:查看系统日志
journalctl -k | grep -i sigterm

# 方法2:使用strace跟踪
strace -p <PID> -e trace=signal

防御性编程建议

正确处理信号避免数据损坏:

// 改进的信号处理示例
void graceful_shutdown(int sig) {
    // 保存状态
    save_work_state();
    
    // 关闭资源
    close_db_connections();
    
    // 退出进程
    _exit(0);
}

int main() {
    struct sigaction act;
    act.sa_handler = graceful_shutdown;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    
    sigaction(SIGTERM, &act, NULL);
    // ... 主逻辑
}

容器环境特殊处理

对于Docker/K8s环境,需要正确处理preStop和terminationGracePeriodSeconds:

# Docker示例
docker run --name test --stop-signal SIGTERM your_image

# K8s部署示例
apiVersion: v1
kind: Pod
spec:
  terminationGracePeriodSeconds: 60

监控与告警配置

建议对非预期的SIGTERM建立监控:

# Prometheus告警规则示例
- alert: UnexpectedProcessTermination
  expr: increase(process_terminations_total{signal="terminated"}[5m]) > 0
  for: 1m
  labels:
    severity: warning
  annotations:
    summary: "Process terminated by SIGTERM"