如何守护Java程序?


73

我有一个要在linux系统上守护的Java程序。换句话说,我要在外壳中开始运行,并在注销后继续运行。我还希望能够干净地停止该程序。

我发现这篇文章结合使用了外壳脚本和Java代码来达到目的。看起来不错,但我希望有一些简单的方法。

在Linux系统上守护Java程序的首选方法是什么?



9
尝试nohup java prog &
2012年

在UNIX上提供一种更清洁的服务管理方法cr.yp.to/daemontools.html
Velu

Answers:



32

如果您不能依靠其他地方引用的Java Service Wrapper(例如,如果您在没有SW打包版本的Ubuntu上运行),则可能要采用老式的方法:让程序在/ var / run / $ progname.pid,并在其周围编写一个标准的SysV初始化脚本(例如,以ntpd为例)。最好也使其符合LSB。

本质上,启动函数会测试程序是否已在运行(通过测试/var/run/$progname.pid是否存在,以及该文件的内容是否为正在运行的进程的PID),以及是否未运行

logfile=/var/log/$progname.log
pidfile=/var/run/$progname.pid
nohup java -Dpidfile=$pidfile $jopts $mainClass </dev/null > $logfile 2>&1

停止功能检查/var/run/$progname.pid,测试该文件是否为正在运行的进程的PID,验证该文件是否为Java VM(以免杀死从死角简单地重用PID的进程Java守护程序的实例),然后终止该进程。

调用时,我的main()方法将通过将其PID写入System.getProperty(“ pidfile”)中定义的文件开始。

但是,一个主要障碍是:在Java中,没有简单而标准的方法来获取JVM运行所在的进程的PID。

这是我想出的:

private static String getPid() {
    File proc_self = new File("/proc/self");
    if(proc_self.exists()) try {
        return proc_self.getCanonicalFile().getName();
    }
    catch(Exception e) {
        /// Continue on fall-back
    }
    File bash = new File("/bin/bash");
    if(bash.exists()) {
        ProcessBuilder pb = new ProcessBuilder("/bin/bash","-c","echo $PPID");
        try {
            Process p = pb.start();
            BufferedReader rd = new BufferedReader(new InputStreamReader(p.getInputStream()));
            return rd.readLine();
        }
        catch(IOException e) {
            return String.valueOf(Thread.currentThread().getId());
        }
    }
    // This is a cop-out to return something when we don't have BASH
    return String.valueOf(Thread.currentThread().getId());
}

9
无需Java编写PID,脚本也可以做到这一点(回显$!> /var/run/my.pid)。此外,由于通常只有root才能写入/ var / run,因此您可以使用Shell脚本以root身份运行,守护进程以另一个用户身份运行。
David Rabinowitz,2009年

除非您无法在Java中更改uid或euid,否则您必须使用sudo从shell中进行操作...如果您问我,这会有些痛苦。将/ var / run和var / log
写给

3
同样,让Java编写pid文件/锁文件的理由是要知道守护程序的初始化阶段是否成功完成(通过在该阶段的末尾编写)。
瓦汉2009年

这个答案是没有用的。您想在创建套接字后进行分叉。这只是将过程与shell分开,完全是另一回事。
LtWorf

cop-out选项不起作用-线程ID几乎可以肯定与进程ID不同。
路加和记

24

我经常发现自己在编写脚本或命令行,而这些脚本或命令行本质上是这样的:

  1. 运行不受sighups影响的程序
  2. 那完全与生成它的外壳断开连接,并且
  3. 从stderr和stdout生成一个日志文件,其内容也显示出来,但是
  4. 使我可以停止查看正在进行的日志并执行其他操作,而不会中断正在运行的进程

请享用。

nohup java com.me.MyProgram </dev/null 2>&1 | tee logfile.log &

1
您可以使用cron和@reboot功能启动它。

15

我更喜欢nohup命令。博客文章说有更好的方法,但是我认为它们还不够好。


它不是完全守护进程。如果重新启动操作系统该怎么办?这是带有daemontools的更干净的解决方案stackoverflow.com/a/35569052/1840774
Velu 2016年

1
一旦系统关闭或重新启动,这将不会启动服务!
Velu


4

那要看。如果这只是一次性的事情,我想守护它然后回家,但是通常我会等待结果,我可以这样做:

nohup java com.me.MyProgram &

在命令行中。要彻底清除它,您有很多选择。您可能具有SIGKILL的侦听器,或者侦听端口并在建立连接时关闭,并定期检查文件。不同的方法有不同的弱点。如果将其用于生产中,我会考虑得更多,并可能将一个脚本添加到/etc/init.d中以使其静音,并具有更复杂的关闭功能,例如tomcat所具有的功能。


是的,它不是完全守护进程。如果重新启动操作系统该怎么办?这是带有daemontools的更干净的解决方案stackoverflow.com/a/35569052/1840774
Velu 2016年

4

在Ubuntu上,我的首选方法是使用libslack的“ daemon”实用程序。这就是Jenkins在Ubuntu上使用的(这就是我的主意。)我已经将其用于基于Jetty的服务器应用程序,并且运行良好。

当您停止守护进程时,它将通知JVM关闭。您可以在此时通过向Runtime.addShutdownHook()注册关闭钩子来执行关闭/清理代码。


2

这个问题是关于守护一个任意程序(不是特定于Java的),因此某些答案可能适用于您的情况:


2

DaemonTools:-在UNIX https://cr.yp.to/daemontools.html上管理服务的更干净的方法

  1. 从URL https://cr.yp.to/daemontools/install.html安装守护程序工具, 按照此处提到的说明进行操作,如有任何问题,请尝试使用说明https://gist.github.com/rizkyabdilah/8516303

  2. /etc/init/svscan.conf中创建一个文件,并添加以下行。(仅cent-os-6.7必需)

 start on runlevel [12345]
 stop on runlevel [^12345]
 respawn
 exec /command/svscanboot
  1. 在/ service / vm /文件夹中创建一个名为run的新脚本,并添加以下几行。
#!/bin/bash    
echo starting VM 
exec java -jar
/root/learning-/daemon-java/vm.jar

注意:用您自己的Jar文件替换Jar。或任何Java类文件。

  1. 重新启动系统

  2. svstat / service / vm应该已经启动并正在运行!

  3. svc -d / service / vm现在应该关闭虚拟机!
  4. svc -u / service / vm现在应该启动虚拟机!

0
nohup java -jar {{your-jar.jar}} > /dev/null &

这可以解决问题。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.