温馨提示×

centos僵尸进程如何备份

小樊
38
2025-11-22 02:52:26
栏目: 智能运维

CentOS僵尸进程的备份与取证

一、核心原则

  • 僵尸进程(Z/defunct)是子进程已退出但父进程未调用 wait/waitpid 回收的状态,进程实体几乎不占用CPU/内存,仅保留进程描述符备份“状态”本身没有意义,应优先保存用于定位与复现的取证信息,并尽快修复父进程回收逻辑或重启父进程以让init/systemd收养并回收僵尸。若仅为取证,可先备份进程信息与相关资源占用情况,再处理僵尸。

二、取证与备份清单

  • 进程清单与状态
    • 快速列举僵尸及其父进程:
      • ps -eo pid,ppid,stat,cmd | awk ‘$3 ~ /Z/ {print}’
      • top/htop 中关注 zombie 计数不为 0 的情况。
  • 进程树与父子关系
    • pstree -p | grep -A5 -B5 Z
    • 记录僵尸的 PID/PPID,便于后续处理父进程。
  • 命令行与资源快照
    • 备份进程命令行与关键指标:
      • pgrep -f <关键字> | xargs ps -o pid,ppid,stat,cmd,%cpu,%mem --no-headers > zombie_snap.txt
  • 打开文件与网络连接
    • 对可疑父进程或同属服务的进程记录资源占用:
      • lsof -p > proc__files.txt
  • 运行环境上下文
    • 若服务由 systemd 托管,记录单元与最近的日志:
      • systemctl status -l
      • journalctl -u -b --since “2025-11-22 00:00:00” > svc_.log
  • 打包归档
    • 将以上文件统一打包,便于留存与传输:
      • tar czvf zombie_forensics_$(date +%F).tar.gz *.txt *.log

三、安全处置与修复

  • 优先修复父进程回收
    • 修改应用/服务代码,在父进程中正确处理 SIGCHLD,并循环调用 waitpid(WNOHANG) 回收子进程;这是根治之道。
  • 无法立即修复时的过渡
    • 重启或重载父进程/服务,使其由 systemd 收养并回收僵尸:
      • systemctl restart 或 kill -HUP <父进程PID>
    • 若父进程异常或无回收逻辑且无法重启,作为权衡可终止父进程(可能导致业务短时中断):
      • kill -9 <父进程PID>
    • 不建议仅对僵尸本身发送信号(如 kill -9 <僵尸PID>),这通常无效,因为僵尸已死,需让其父进程回收或重启父进程。
  • 预防建议
    • 上线前对多进程/守护进程进行回收逻辑信号处理自检;生产环境建立监控告警(僵尸数、子进程泄漏)与定期巡检

四、一键取证脚本示例

  • 作用:收集僵尸进程、父子关系、命令行、打开文件、systemd单元状态与日志,并打包归档。
  • 用法:以 root 或具备相应权限的用户执行,按需修改备份目录与保留天数。
#!/usr/bin/env bash
set -Eeuo pipefail

OUTDIR="/var/log/zombie_forensics/$(date +%F_%H-%M-%S)"
mkdir -p "$OUTDIR"

# 1) 僵尸进程清单
ps -eo pid,ppid,stat,cmd | awk '$3 ~ /Z/ {printf "PID=%s PPID=%s CMD=%s\n", $1, $2, substr($0, index($0,$4))}' \
  > "$OUTDIR/zombies.txt"

# 2) 进程树片段(含父进程上下文)
if command -v pstree >/dev/null 2>&1; then
  pstree -p | grep -A5 -B5 Z > "$OUTDIR/pstree_Z.txt" || true
fi

# 3) 命令行与资源快照(针对僵尸及其父进程)
for pid in $(awk '$3 ~ /Z/ {print $1}' "$OUTDIR/zombies.txt"); do
  ps -o pid,ppid,stat,cmd,%cpu,%mem --no-headers -p "$pid" >> "$OUTDIR/zombie_cmd.txt" 2>/dev/null || true
  ppid=$(ps -o ppid= -p "$pid" 2>/dev/null || echo "UNKNOWN")
  echo "=== Parent PID: $ppid ===" >> "$OUTDIR/parent_info.txt"
  ps -o pid,ppid,stat,cmd,%cpu,%mem --no-headers -p "$ppid" >> "$OUTDIR/parent_info.txt" 2>/dev/null || true
done

# 4) 打开文件与网络连接(针对父进程)
for ppid in $(awk '$3 ~ /Z/ {print $2}' "$OUTDIR/zombies.txt" | sort -u); do
  lsof -p "$ppid" > "$OUTDIR/parent_${ppid}_files.txt" 2>/dev/null || true
done

# 5) systemd 单元状态与日志(若可用)
if command -v systemctl >/dev/null 2>&1; then
  for svc in $(systemctl list-units --type=service --state=running --no-pager | awk '{print $1}'); do
    if systemctl is-active --quiet "$svc"; then
      systemctl status "$svc" -l > "$OUTDIR/svc_${svc}.status" 2>/dev/null || true
      journalctl -u "$svc" -b --since "$(date -d '1 hour ago' +%F_%H:%M:%S)" \
        > "$OUTDIR/svc_${svc}.journal" 2>/dev/null || true
    fi
  done
fi

# 6) 打包归档
tar czvf "$OUTDIR.tar.gz" -C "$(dirname "$OUTDIR")" "$(basename "$OUTDIR")"
echo "Zombie forensics saved to: $OUTDIR.tar.gz"

提示:

  • 上述脚本仅做取证与备份,不会主动终止进程;完成取证后,请按“安全处置与修复”处理父进程或重启相关服务。
  • 若需长期留存,建议配置 logrotate 或定期清理旧归档,避免磁盘占满。

0