揭开服务程序“被杀”之谜

2020-06-05 09:34:45 浏览数 (1)

在日常工作中,服务程序(daemon)意外退出,一般是由以下几个原因导致的:

  1. 程序自身bug;
  2. 被OS oom killer杀掉;
  3. 操作人员误杀;
  4. 被第三方程序杀掉;

对于第一种情况,一般可以通过coredump看出。第二个种情况,也可以通过dmesg找到线索(一般是被oom killer杀掉)。但是当后两种情况出现时,往往是大家最抓瞎最手足无措的时候。

本文将介绍多种方法来帮助大家揭开服务(daemon)被杀之谜。

首先先创建一个daemon

代码语言:javascript复制
#!/bin/bash
while : ; do    sleep 1done

然后在后台运行这个daemon.sh。

第一个方法:ftrace

使用命令

echo 1 > /sys/kernel/tracing/events/signal/enable

使用命令killall daemon.sh杀掉daemon.sh。

然后查看ftrace的输出,cat /sys/kernel/tracing/trace

如红色箭头所指,可以清晰的看出killall命令,给进程daemon.sh(pid为3615)发送了SIGTERM(即sig=15)。

第二个方法:systemtap

编写systemtap脚本,来探测kill调用。

代码语言:javascript复制
probe syscall.kill{    if (pid2execname(u32_arg(1)) == @1)            printf("%s(%d) kill %s with (%s)n", execname(), pid(), pid2execname(u32_arg(1)), argstr);}

简单介绍一下脚本。

  1. 该脚本接受一个参数@1,表示要监视的服务进程名称。
  2. u32_arg(1)获得kill系统调用的第一个参数,也就是目标pid。然后调用systemtap的函数pid2execname得到该pid的进程名。
  3. 当条件为真时,表明kill要发送的目标pid就是我们要监视服务进程。 然后打印调用者的进程名称(execname)和其pid。最后使用通过systemtap的argstr,打印kill的完整参数

看一下执行效果

第三个方法:bpftrace

bpftrace是Brendan Gregg使用bpf开发的一套trace工具。对于当前问题,我们选择其中的killsnoop来trace kill调用。

重复之前的操作,可以看到killsnoop侦测到了killall发送了SIG 15也就是SIGTERM给TPID 9216,也就是我们的daemon.sh。

第四个方法:bcc

bcc与systemtap类似,是一个可以编写ebpf的工具集。除了可以直接编写ebpf程序外,它也提供了一套与bpftrace相似的现成工具,并提供了更多的选项。

对于当前的问题,也只能使用默认行为,监控所有的kill调用。但bcc的killsnoop可以trace指定pid,来追踪指定pid进程的kill调用。

第五个方法:直接编写bpftrace代码

在第三个方法中,我们直接使用bpftrace提供的现成工具,实际上我们也可以编写bpftrace来完成这个任务。

代码语言:javascript复制
#!/usr/bin/bpftrace
tracepoint:syscalls:sys_enter_kill {    if ($1 == args->pid) {        printf("process %s send signal%d to pid %dn", comm, args->sig, args->pid);    }}

在上面的代码中,我们根据kill这个系统调用,然后打印发送信号的进程名,信号值,以及目标pid。当目标pid与第一个参数,即我们要监控的process,就进行打印。

虽然会有一个告警,但我们这里可以忽略到。

其实除了上面的5种方法外,还会有其它方案来搞定这个问题,比如直接编写ebpf程序,等等。不过我认为上面5种方法,基本上已经可以覆盖绝大部分的场景了。

如果大家还有更好的方法,欢迎留言分享~~~

0 人点赞