最近朋友项目发生了一件怪事,好好的进程,没有任何痕迹地退出,没有core文件,没有syslog痕迹,也不是进程主动退出,因为逻辑中exit都有日志。
现在记录一下追查过程:
1.先排除core生成条件不足的可能性
1)查看ulimit -c,
2)查看/proc/sys/kernel/core_pattern,
3)查看/etc/sysctl.conf中的
kernel.core_pattern = /var/core/core_%e_%p_%t
kernel.core_uses_pid = 0
这些设置都正常
2.排除程序自身exit
排查代码发现所有exit的地方都有日志,而现在进程退出没有任何exit相关的日志
3.查看syslog
在进程退出时间先后查看syslog没有发现任何异常
4.排除主动调用kill
查看机器的history,并没有发现有人调用过kill
从上面的结果看,应该是进程主动退出,但是并非是程序中的exit,那么大概率只有一种可能是进程收到了某种信号,然后导致进程退出。其实kill本身也是信号。那么怎么追踪呢?祭出大杀器:gdb,进程退出,最后应该会进入exit接口处理收尾工作。那就gdb在exit函数这里打断点,同时因为不可能直接在终端开着gdb,如果终端断开的话就会终止gdb监控,而本身这个异常退出就是不定时的,所以必须是后台模式启动gdb。
最关键的操作如下:
1.生成一个gdb脚本文件:monitor
b exit
c
bt
q
2.nohup gdb -p server --command=monitor &
这样后台起一个任务,监控server程序退出时的exit的调用,在程序退出的时候会生成一个result文件nohup.out
两天后sevrer有挂掉了,查看gdb结果文件看到:
Thread 2 "GameRunner" received signal SIGPIPE, Broken pipe.
[Switching to Thread 0x7efc25351700 (LWP 2086776)]
__libc_write (nbytes=223, buf=0x7efc200012a0, fd=14)
at ../sysdeps/unix/sysv/linux/write.c:26
26 ../sysdeps/unix/sysv/linux/write.c: No such file or directory.
#0 __libc_write (nbytes=223, buf=0x7efc200012a0, fd=14)
at ../sysdeps/unix/sysv/linux/write.c:26
#1 __libc_write (fd=14, buf=0x7efc200012a0, nbytes=223)
at ../sysdeps/unix/sysv/linux/write.c:24
#2 0x00007efc26aa55c5 in ?? () from /lib/x86_64-linux-gnu/libcrypto.so.1.1
#3 0x00007efc26aa072a in ?? () from /lib/x86_64-linux-gnu/libcrypto.so.1.1
#4 0x00007efc26a9f784 in ?? () from /lib/x86_64-linux-gnu/libcrypto.so.1.1
#5 0x00007efc26a9fc43 in BIO_write ()
from /lib/x86_64-linux-gnu/libcrypto.so.1.1
#6 0x00007efc26a9df01 in ?? () from /lib/x86_64-linux-gnu/libcrypto.so.1.1
#7 0x00007efc26aa0116 in BIO_ctrl ()
from /lib/x86_64-linux-gnu/libcrypto.so.1.1
#8 0x00007efc26d22f3d in ?? () from /lib/x86_64-linux-gnu/libssl.so.1.1
#9 0x00007efc26d31e8f in ?? () from /lib/x86_64-linux-gnu/libssl.so.1.1
#10 0x00007efc26d224a3 in ?? () from /lib/x86_64-linux-gnu/libssl.so.1.1
#11 0x0000562740764db0 in init_sslwebsocket_server_connection (
con=0x7efc200066a0) at yknet_sslwebsocket_pipe.cpp:76
#12 0x0000562740763d03 in yknet_ssl_pipe_handshake (pe=pe@entry=0x7efc20021540)
at yknet_pipe_base.cpp:1167
#13 0x0000562740763e2b in yknet_ssl_pipe_conn_sock_readcb (fd=14,
event=<optimized out>, arg=0x7efc20021540) at yknet_pipe_base.cpp:1209
#14 0x0000562740775fd4 in event_process_active_single_queue (
base=base@entry=0x56274325c200, activeq=0x56274325c650,
max_to_process=max_to_process@entry=2147483647, endtime=endtime@entry=0x0)
at event.c:1691
#15 0x0000562740776bcf in event_process_active (base=0x56274325c200)
at event.c:1783
#16 event_base_loop (base=0x56274325c200, flags=flags@entry=1) at event.c:2006
#17 0x0000562740763b7e in yknet_pipe_base_process_send_data (
base=b
原来是 Thread 2 "GameRunner" received signal SIGPIPE, Broken pipe,进程收到了信号SIGPIPE,该信号默认结束进程,而server代码中并没有忽略这个信号。问题最后找到了答案,就是对常见的应该屏蔽的信号没有处理,导致进程结束。最后从之前的老的代码库中抄了一段:
// ignore signals
signal(SIGINT, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
signal(SIGTTIN, SIG_IGN);
signal(SIGTERM, SIG_IGN);
问题解决!