我的Java应用程序有时可以被外部脚本杀死。 这可以通过SIGTERM或者SIGKILL来完成。
应用程序是一个每秒接收很多连接的服务器,在尝试提供服务时可能会被终止。
我想重新启动应用程序,所以我已经为此准备了一个脚本。
问题是,一旦应用程序被终止,新的应用程序实例就无法绑定到前一个实例使用的端口,因为“地址已经在使用”了。 前一个实例的进程已经被终止了,反正这个有问题的监听端口仍然存在,但是被分配给了bash (或者在其他机器上)。
Obviouly, 我的目标是重新启动应用程序,并让它成功绑定到以前的地址 。
我已经尝试等待200多秒,然后重新启动无济于事,无论如何我不能等待那么多。
我在运行应用程序的所有机器(这是一个Java 1.6的docker服务器)上遇到过这个问题。
任何build议表示赞赏,谢谢,
西尔维奥
编辑杀死jvm进程不是我退出我的应用程序的正常方式,这是用来在出现问题(OutOfMemoryErrors)的情况下。 我从来不需要用SIGKILL来杀死它,因为SIGTERM总是足够的,只有在SIGTERM失败的情况下,我才会使用SIGKILL,这从来没有发生过。 我正在研究一个长期的解决scheme,同时我必须通过在这里和那里应用缝线来运行我的应用程序。
编辑更清楚:这是netstat -tunap | grep行我查杀之前看过程:
tcp6 0 0 :::8898 :::* LISTEN 22709/java
这是在杀了这个过程之后
tcp6 0 0 :::8898 :::* LISTEN 23665/sh
注意PID 22709的进程被杀死了,但是端口仍然在那里(但是被sh锁住了)
更新后,我杀了我的应用程序,用netstat我可以看到一个长长的CLOSE_WAIT状态挂起的连接列表,我的IP作为目的地。 另外,我可以在状态LISTEN中看到一个sh进程监听我的端口:当我终止它时,一个睡眠进程replace它并监听同一个端口:当我终于终止了这个hibernate进程时,端口被释放,我可以成功重启我的服务器。 这可能是一个解决scheme,让我的端口释放,但我担心自动杀死进程,以释放一个端口有点冒险
由于您只能手动执行此操作,因此可能需要添加其他检查。
netstat -p
并杀死与您打开的套接字关联的pid,即使是bash或sh。
另外,你提到大部分的时候,SIGTERM都起作用。 如果是这样的话,你的应用程序应该捕获SIGTERM并跳转到一些优雅的退出代码,RST打开所有的连接,然后closures套接字。
HTH
侦听套接字closures后,服务器仍然期望来自客户端的一些数据包,并保持端口分配。 应用程序可以使用SO_REUSEADDR套接字选项来允许立即重新使用套接字地址。
这是我的Linux ip(7)手册页摘录:
除非设置了SO_REUSEADDR标志,否则绑定的TCP本地套接字地址在closures后一段时间内将不可用。 使用这个标志时要小心,因为它使得TCP不太可靠。
应用程序或应用程序服务器可能具有使用此套接字选项的configuration设置。
你真的不杀死你的Java应用程序,你实际上是杀死你的Java虚拟机(JVM)实例,这反过来运行你的Java应用程序。
这不是终止你的java进程的想法。
如果你用kill -9杀死你的jvm,那么jvm将不能自行清理,从而使操作资源处于闲置状态。 🙁
添加一些function到您的应用程序,使其优雅地退出。 如果你别无select,那么试着用-15杀死你的jvm,它可能会帮助它自己清理掉。
如果你的Java程序真的挂了jvm,那么你需要debugging器来压缩这些有害生物。
杀死一个进程并重新启动它是一个黑客攻击,但没有解决。 如果一个进程没有响应任何其他方法,你应该只使用SIGKILL。
我通常尝试
杀-15
那么只能杀死-9作为最后的手段。
为了好玩
如果您有权访问源代码,则需要使用Jacek提到的SO_REUSEADDR选项来创build套接字。 另外感兴趣的是tcp_tw_recycle和tcp_tw_reuse内核标志(在Linux上)。
真正的问题在协议devise中,您可能会也可能不能更改。 关于这个话题的有趣线索:
随着你的更新,我有另一个解释。 保持套接字打开的sh进程必须是应用程序的subprocess,在侦听套接字打开后分叉。 它并没有和父母一起死亡,而是被初始化过程所采用。
你应该尝试找出什么是shell进程(可能是你的应用程序启动的一些脚本)以及为什么没有终止。 也许这将足以解决脚本,所以它完成后终止工作就足够了? 或者,有一种方法可以使其不与父代分离(如果是同一个进程组的一部分,它应该与父代一起死掉),或者使其closures从父代inheritance的所有不需要的文件描述符。
你可以尝试:
fuser -p $pid_of_the_sh_process
看看它保持打开的其他文件。 其中之一就是shell脚本。 知道这是什么,我们可能会find解决问题的方法。