Java实现Linux下双守护进程

一、简介

  现在的服务器端程序很多都是基于Java开发,针对于Java开发的Socket程序,这样的服务器端上线后出现问题需要手动重启,万一大半夜的挂了,还是特别麻烦的。
  大多数的解决方法是使用其他进程来守护服务器程序,如果服务器程序挂了,通过守护进程来启动服务器程序。
  万一守护进程挂了呢?使用双守护来提高稳定性,守护A负责监控服务器程序与守护B,守护B负责监控守护A,任何一方出现问题,都能快速的启动程序,提高服务器程序的稳定性。

  Java的运行环境不同于C等语言开发的程序,Java程序跑在JVM上面。不同于C语言可以直接创建进程,Java创建一个进程等同于使用java -jar xxx.jar启动一个程序。
  Java启动程序并没有C#类似的单实例限制,你可以启动多个,但是你不能启动多个,不能让多个守护A去守护服务器程序,万一启动了多个服务器程序怎么办?

二、技术讲解

这里的技术讲解比较粗略,具体请百度一下,这里只讲解作用。
1、jps命令。
  JDK自带的命令工具,使用jps -l可以列出正在运行的Java程序,显示Java程序的pid与Name。只对Java程序有效,其实查看的是运行的JVM
2、java.nio.channels.FileLock类的使用
  这个是Java new IO中的类,使用他可以维持在读取文件的给文件加上锁,判断文件时候有锁可以判断该文件是否被其他的程序使用
3、ProcessBuilder与Process
  这两个原理差不多,都是调用系统的命令运行,然后返回信息。但是硬编码会导致你的Java程序失去可移植性,可以将命令独立到配置文件中。

三、设计原理

Server:服务器程序
A:守护进程A
B:守护进程B
A.lock:守护进程A的文件锁
B.lock:守护进程B的文件锁
----------------------------------------------------------------------------------
Step 1:首先不考虑Server,只考虑A与B之间的守护
1.A判断B是否存活,没有就启动B
2.B判断A是否存活,没有就启动A
3.在运行过程中A与B互相去拿对方的文件锁,如果拿到了,证明对面挂了,则启动对方。
4.A启动的时候,获取A.lock文件的锁,如果拿到了证明没有A启动,则A运行;如果没有拿到锁,证明A已经启动了,或者是B判断的时候拿到了锁,如果是A已经启动了,不需要再次启动A,如果是B判断的时候拿到了锁,没关紧  要,反正B会再次启动A。
5.B启动的时候原理与A一致。
6.运行中如果A挂了,B判断到A已经挂了,则启动A。B同理。

Step 2:加入Server
1.A用于守护B和Server,B用于守护A。
2.原理与Step 1 一致,只是A多个一个守护Serer的任务。
3.当A运行的时候,使用进程pid检测到Server已经挂了,就启动Server
4.如果Server与A都挂了,B会启动A,然后A启动Server
5.如果Server与B挂了,A启动Server与B
6.如果A与B都挂了,守护结束

Step 3:使用Shutdown结束守护,不然结束Server后会自动启动

四、实现
1、GuardA的实现

代码如下:

public class GuardA {
     // GuardA用于维持自己的锁
     private File fileGuardA;
     private FileOutputStream fileOutputStreamGuardA;
     private FileChannel fileChannelGuardA;
     private FileLock fileLockGuardA;
     // GuardB用于检测B的锁
     private File fileGuardB;
     private FileOutputStream fileOutputStreamGuardB;
     private FileChannel fileChannelGuardB;
     private FileLock fileLockGuardB;
 
     public GuardA() throws Exception {
         fileGuardA = new File(Configure.GUARD_A_LOCK);
         if (!fileGuardA.exists()) {
             fileGuardA.createNewFile();
         }
         //获取文件锁,拿不到证明GuardA已启动则退出
         fileOutputStreamGuardA = new FileOutputStream(fileGuardA);
         fileChannelGuardA = fileOutputStreamGuardA.getChannel();
         fileLockGuardA = fileChannelGuardA.tryLock();
         if (fileLockGuardA == null) {
             System.exit(0);
         }
        
         fileGuardB = new File(Configure.GUARD_B_LOCK);
         if (!fileGuardB.exists()) {
             fileGuardB.createNewFile();
         }
         fileOutputStreamGuardB = new FileOutputStream(fileGuardB);
         fileChannelGuardB = fileOutputStreamGuardB.getChannel();
     }
 
     /**
      * 检测B是否存在
      *
      * @return true B已经存在
      */
     public boolean checkGuardB() {
         try {
             fileLockGuardB = fileChannelGuardB.tryLock();
             if (fileLockGuardB == null) {
                 return true;
             } else {
                 fileLockGuardB.release();
                 return false;
             }
         } catch (IOException e) {
             System.exit(0);
             // never touch
             return true;
         }
     }
 }

2、GuardServer的实现

代码如下:

public class GuardServer {
     private String servername;
 
     public GuardServer(String servername) {
         this.servername = servername;
     }
 
     public void startServer(String cmd) throws Exception {
         System.out.println("Start Server : " + cmd);
         //将命令分开
 //        String[] cmds = cmd.split(" ");
 //        ProcessBuilder builder = new ProcessBuilder(cmds);
    
         //
         ProcessBuilder builder=new ProcessBuilder(new String[]{"/bin/sh","-c",cmd});
         //将服务器程序的输出定位到/dev/tty
         builder.redirectOutput(new File("/dev/tty"));
         builder.redirectError(new File("/dev/tty"));
         builder.start(); // throws IOException
         Thread.sleep(10000);
     }
 
     /**
      * 检测服务是否存在
      *
      * @return 返回配置的java程序的pid
      * @return pid >0 返回的是 pid <=0 代表指定java程序未运行
      * **/
     public int checkServer() throws Exception {
         int pid = -1;
         Process process = null;
         BufferedReader reader = null;
         process = Runtime.getRuntime().exec("jps -l");
         reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
         String line;
         while ((line = reader.readLine()) != null) {
             String[] strings = line.split("\\s{1,}");
             if (strings.length < 2)
                 continue;
             if (strings[1].contains(servername)) {
                 pid = Integer.parseInt(strings[0]);
                 break;
             }
         }
         reader.close();
         process.destroy();
         return pid;
     }
 }

3、GuardAMain实现

代码如下:

public class GuardAMain {
     public static void main(String[] args) throws Exception {
         GuardA guardA = new GuardA();
         Configure configure = new Configure();
         GuardServer server = new GuardServer(configure.getServername());
         while (true) {
             // 如果GuardB未运行 运行GuardB
             if (!guardA.checkGuardB()) {
                 System.out.println("Start GuardB.....");
                 Runtime.getRuntime().exec(configure.getStartguardb());
             }
             // 检测服务器存活
             if (server.checkServer() <= 0) {
                 boolean isServerDown = true;
                 // trip check
                 for (int i = 0; i < 3; i++) {
                     // 如果服务是存活着
                     if (server.checkServer() > 0) {
                         isServerDown = false;
                         break;
                     }
                 }
                 if (isServerDown)
                     server.startServer(configure.getStartserver());
             }
             Thread.sleep(configure.getInterval());
         }
     }
 }

4、Shutdown实现

代码如下:

public class ShutDown {
     public static void main(String[] args) throws Exception {
         Configure configure = new Configure();
         System.out.println("Shutdown Guards..");
         for (int i = 0; i < 3; i++) {
             Process p = Runtime.getRuntime().exec("jps -l");
             BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
             String line;
             while ((line = reader.readLine()) != null) {
                 if (line.toLowerCase().contains("Guard".toLowerCase())) {
                     String[] strings = line.split("\\s{1,}");
                     int pid = Integer.parseInt(strings[0]);
                     Runtime.getRuntime().exec(configure.getKillcmd() + " " + pid);
                 }
             }
             p.waitFor();
             reader.close();
             p.destroy();
             Thread.sleep(2000);
         }
         System.out.println("Guards is shutdown");
     }
 }

5、GuardB与GuardA类似

五、下载与使用

项目文件夹:guard_demo

下载地址:http://pan.baidu.com/s/1bn1Y6BX

如果有什么疑问或者建议,请联系我

(0)

相关推荐

  • linux 创建守护进程的相关知识

    创建子进程,父进程退出 这是编写守护进程的第一步.由于守护进程是脱离控制终端的,因此,完成第一步后就会在Shell终端里造成一程序已经运行完毕的假象.之后的所有工作都在子进程中完成,而用户在Shell终端里则可以执行其他命令,从而在形式上做到了与控制终端的脱离. 在Linux中父进程先于子进程退出会造成子进程成为孤儿进程,而每当系统发现一个孤儿进程是,就会自动由1号进程(init)收养它,这样,原先的子进程就会变成init进程的子进程. 在子进程中创建新会话 这个步骤是创建守护进程中最重要的一步

  • Python实现Linux下守护进程的编写方法

    本文实例讲述了Python实现Linux下守护进程的编写方法,分享给大家供大家参考,相信对于大家的Python程序设计会起到一定的帮助作用.具体方法如下: 1. 调用fork()以便父进程可以退出,这样就将控制权归还给运行你程序的命令行或shell程序.需要这一步以便保证新进程不是一个进程组头领进程(process group leader).下一步,'setsid()',会因为你是进程组头领进程而失败.进程调用fork函数时,操作系统会新建一个子进程,它本质上与父进程完全相同.子进程从父进程继

  • linux shell实现守护进程脚本

    嵌入式初学者,第一次上传代码.昨天做了一个udhcpd与udhcpc的守护,目前只会用shell模仿编写,还有什么方法可以做守护呢? #! /bin/sh #进程名字可修改 PRO_NAME=udhcpc WLAN=ra0 while true ; do # 用ps获取$PRO_NAME进程数量 NUM=`ps aux | grep ${PRO_NAME} | grep -v grep |wc -l` # echo $NUM # 少于1,重启进程 if [ "${NUM}" -lt &

  • php守护进程 加linux命令nohup实现任务每秒执行一次

    Unix中 nohup 命令功能就是不挂断地运行命令,同时 nohup 把程序的所有输出到放到当前目录 nohup.out 文件中,如果文件不可写,则放到 <用户主目录>/nohup.out 文件中.那么有了这个命令以后我们php就写成shell 脚本使用循环来让我们脚本一直运行下去,不管我们终端窗口是否关闭都能够让我们php 脚本一直运行下去. 马上动手写个 PHP 小程序,功能为每30秒记录时间,写入到文件 复制代码 代码如下: # vi for_ever.php #! /usr/loca

  • 详解Linux中的守护进程

    一.什么是守护进程 Linux系统启动时会启动很多系统服务进程,这些系统服 务进程没有控制终端,不能直接和用户交互.其它进程都是在用户登录或运行程序时创建,在运⾏结束或⽤户注销时终止,但系统服务进程不受用户登录注销的影响,它们⼀直在运行着.这种进程叫守护进程. 守护进程也被称为精灵进程,是运行在后台的一种特殊进程,它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件. 查看方式 ps axj命令:查看系统中的进程. 参数a表示不仅列当前⽤户的进程,也列出所有其他用户的进程: 参数x表

  • linux下的守护进程

    Linux下的常驻进程的作用不可忽略,但这里面的问题也不能忽略,怎么启动进程,怎么结束进程,怎么在进程挂掉之后重启进程都要设计的合理.下面看一个shell控制的php常驻进程的例子. 不废话,直接捞干货,上代码,通过代码来讲解更容易理解: 复制代码 代码如下: #!/bin/sh #filename test.sh #绝对定位该文件的位置,不随执行目录而变化 cd $(cd "$(dirname "$0")";pwd) readonly path=$(pwd)/ f

  • linux 守护进程详解及建立守护进程

    linux 守护进程详解及建立守护进程 守护进程是一种后台运行并且独立于所有终端控制之外的进程. 守护进程的启动 要启动一个守护进程,可以采取一下几种方式: 在系统期间通过系统的初始化脚本启动守护进程.这些脚本通常在目录etc/rc.d下,通过它们所启动的守护进程具有超级用户的权限.系统的一些基本服务通常都是通过这种方式启动的. 很多网络服务程序都是由inetd守护程序启动的.它监听各种网络请求,如telnet.ftp等,在请求到达时启动相应的服务器程序(telnet server,ftp se

  • 使用Python编写Linux系统守护进程实例

    守护进程(daemon)是指在UNIX或其他多任务操作系统中在后台执行的电脑程序,并不会接受电脑用户的直接操控.此类程序会被以进程的形式初始化.通常,守护进程没有任何存在的父进程(即PPID=1),且在UNIX系统进程层级中直接位于init之下.守护进程程序通常通过如下方法使自己成为守护进程:对一个子进程调用fork,然后使其父进程立即终止,使得这个子进程能在init下运行.–维基百科 守护进程区别于普通用户登陆系统后运行的进程,它是直接由系统初始化,和系统用户没有关系,而用户开启的进程依存与用

  • Linux守护进程的启动方法

    "守护进程"(daemon)就是一直在后台运行的进程(daemon). 一.问题的由来 Web应用写好后,下一件事就是启动,让它一直在后台运行. 这并不容易.举例来说,下面是一个最简单的Node应用server.js,只有6行. var http = require('http'); http.createServer(function(req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('He

  • C语言编写Linux守护进程实例

    守护进程(Daemon)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.守护进程是一种很有用的进 程.Linux的大多数服务器就是用守护进程实现的.比如,Internet服务器inetd,Web服务器httpd等.同时,守护进程完成许多系统任 务.比如,作业规划进程crond,打印进程lpd等. 守护进程的编程本身并不复杂,复杂的是各种版本的Unix的实现机制不尽相同,造成不同Unix环境下守护进程的编程规则并不一致.这需要读者注意,照搬 某些书上的

随机推荐