Python守护进程被(内核?)终止

3

我有一个使用来自http://www.jejik.com/files/examples/daemon.py的模块的python2.7守护进程。

该进程非常耗费系统资源,占用约40 GB的RAM和9个子线程。服务器使用RHEL 6.3,有192 GB的RAM和足够的CPU运算能力。

在启动进程后,它会持续约3-7小时,但然后被某人(可能是内核)杀死。但我在dmesg或内核日志中找不到任何提示(我已手动激活),没有任何消息。当不作为守护进程启动时,我只在终端中得到“killed”消息。

以下预防措施已完成:

  • 重置/proc//oom_score_adj中的oom分数,以便oom killer在资源排序时不会选择该进程
  • 将所有可增加的rlimit增加到最大值
  • 将进程nice /优先级设置高(prio-15)

这个问题在采取这些预防措施之前就已经存在,因此它们不负责杀死进程。

我还有一个机制捕获所有异常、STDERR、STDOUT并将所有内容记录到一个旋转的日志文件中。但在进程死亡之前没有任何有趣的内容。

在进程中使用了一些模块,其中包括oracle_cx、ibm_db、suds和wsgi_utils。但它们所有的错误都会写入日志。

有人知道如何追溯杀戮的来源和原因吗?

提前感谢您的帮助。


你是否启用了coredump以查看在kill时是否会出现dump? - Mansour
没,我没有。问题是,我们使用的是128GB的固态硬盘,当进程占用了40GB的内存时,剩余空间已经不足以进行核心转储。 - Kurnia Hendrawan
1
假设您有足够大的RAM,并且假定您的进程不会暂时占用整个RAM(这会导致内核将其杀死),则可以通过tmpfs将coredump存储在RAM上。 - Mansour
可能是谁“杀死”了我的进程,为什么?的重复问题。 - Aaron Digulla
2个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
1

要查看在进程被杀死时登录的用户,使用命令last

如果此时没有用户登录,则是某个信号杀死了该进程。

由于这是Python,找出是什么导致了进程被杀死的最简单方法是为所有信号编写信号处理程序并记录它们。请参阅如何编写信号处理程序。请参阅此问题如何捕获所有信号

如果您获得了核心转储,请附加具有足够空间的外部硬盘。或者使用ulimit将核心大小限制为1GB;这可能足以查看程序在哪里崩溃。

或者,使用像gdb这样的调试器启动进程;它会确保在向进程发送"core dump"信号时获得提示。


如果你在终端看到了“killed”这个词,这并不意味着它是被SIGKILL杀死的。该消息会为任何未处理的信号打印。而且,“pretty sure”也不足以说明问题 :-) - Aaron Digulla
守护进程已经处理了SIGTERM、SIGABRT、SIGINT和SIGSTOP信号。其他信号将产生不同的消息,而不是“killed”。我现在正在尝试使用Mansour建议的ramdisk来获取核心转储。 - Kurnia Hendrawan
你能列举一些这样的监控进程吗?我确实想过,但我不知道。顺便说一句,我也使用 monit 尝试重新启动进程,但当进程死亡时它停止了监控,但这是另一个问题。 - Kurnia Hendrawan
以上有错别字:应为SIGALRM而非SIGSTOP。 - Kurnia Hendrawan
系统管理员有时会安装工具;我手头没有名字。谁监控这台机器?他们应该知道 :-) 另外:你看过 /var/log/kern.log 吗? - Aaron Digulla
显示剩余3条评论

0

我认为我找到了根本原因,可能是Python2.7中的一个bug。在捕获所有可捕获信号并忽略它们后,我可以跟踪一些更多的错误消息,并得到socket.error的提示。问题是,这种错误将首先触发SIGTERM(尝试杀死进程),然后写入STDERR。我的机制捕获所有STDOUT和STDERR的方式无法记录消息,因为主进程已被杀死。这在守护程序中是一个问题。这些是在进程终止之前日志中的最后几行。

2013-05-07 11:05:53,194 - STDERR - ERROR - Traceback (most recent call last):
2013-05-07 11:05:53,304 - STDERR - ERROR -   File "/var/lib/netcam_epd/lib/python2.7/SocketServer.py", line 582, in process_request_thread
2013-05-07 11:05:53,415 - STDERR - ERROR -     self.finish_request(request, client_address)
2013-05-07 11:05:53,489 - STDERR - ERROR -   File "/var/lib/netcam_epd/lib/python2.7/SocketServer.py", line 323, in finish_request
2013-05-07 11:05:53,587 - STDERR - ERROR -     self.RequestHandlerClass(request, client_address, self)
2013-05-07 11:05:53,684 - STDERR - ERROR -   File "/var/lib/netcam_epd/lib/python2.7/SocketServer.py", line 640, in __init__
2013-05-07 11:05:53,835 - STDERR - ERROR -     self.finish()
2013-05-07 11:05:53,887 - STDERR - ERROR -   File "/var/lib/netcam_epd/lib/python2.7/SocketServer.py", line 693, in finish
2013-05-07 11:05:54,084 - STDERR - ERROR -     self.wfile.flush()
2013-05-07 11:05:54,182 - STDERR - ERROR -   File "/var/lib/netcam_epd/lib/python2.7/socket.py", line 303, in flush
2013-05-07 11:05:54,326 - STDERR - ERROR -     self._sock.sendall(view[write_offset:write_offset+buffer_size])
2013-05-07 11:05:54,387 - STDERR - ERROR - error: [Errno 32] Broken pipe
显然,这是由于尝试向一个不可写的套接字进行写操作所造成的。我认为应该在库中处理得更好,返回适当的值,而不仅仅是抛出错误/异常,因为套接字可能在正常运行时随时关闭。 我将验证是否确实是根本原因。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,