Java实现Linux下双守护进程

 更新时间:2014年10月28日 14:28:23   投稿:hebedich  
这篇文章主要介绍了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

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

相关文章

  • 深入理解Java设计模式之状态模式

    深入理解Java设计模式之状态模式

    这篇文章主要介绍了JAVA设计模式之职责链模式的的相关资料,文中示例代码非常详细,供大家参考和学习,感兴趣的朋友可以了解
    2021-11-11
  • Java如何加载外部Jar的类并通过反射调用类的方法

    Java如何加载外部Jar的类并通过反射调用类的方法

    这篇文章主要介绍了Java如何加载外部Jar的类并通过反射调用类的方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • logback日志输出格式设置方式

    logback日志输出格式设置方式

    这篇文章主要介绍了logback日志输出格式设置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • Struts2 漏洞分析及如何提前预防

    Struts2 漏洞分析及如何提前预防

    2016年4月26日,Struts2发布一份安全公告,CVE编号 CVE-2016-3081。这是自2012年Struts2命令执行漏洞大规模爆发之后,该服务时隔四年再次爆发大规模漏洞。该漏洞也是今年目前爆出的最严重安全漏洞。本文分析了漏洞的原理危害影响防护等内容。
    2016-05-05
  • SpringBoot请求响应方式示例详解

    SpringBoot请求响应方式示例详解

    这篇文章主要介绍了SpringBoot请求响应的相关操作,本文通过示例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-06-06
  • Java小白第一次就能看懂的网络编程

    Java小白第一次就能看懂的网络编程

    网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。本文介绍了一些网络编程基础的概念,并用Java来实现TCP和UDP的Socket的编程,来让读者更好的了解其原理
    2021-08-08
  • Java实现简单推箱子游戏

    Java实现简单推箱子游戏

    这篇文章主要为大家详细介绍了Java实现推箱子游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-06-06
  • 从基础学java--数组

    从基础学java--数组

    数组是相同类型数据的有序集合数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们数组的声明创建
    2021-09-09
  • SpringBoot自定义Starter与自动配置实现方法详解

    SpringBoot自定义Starter与自动配置实现方法详解

    在Spring Boot官网为了简化我们的开发,已经提供了非常多场景的Starter来为我们使用,即便如此,也无法全面的满足我们实际工作中的开发场景,这时我们就需要自定义实现定制化的Starter
    2023-02-02
  • 一文详解Java属性为什么不能是is开头的boolean

    一文详解Java属性为什么不能是is开头的boolean

    在Java实体类定义中,boolean类型的属性命名常引发争议,阿里巴巴Java开发手册建议避免使用is作为布尔类型属性的前缀,原因在于当实体类被序列化或反序列化时,基于JavaBean规范的框架可能会移除或忽略is,导致不一致的字段名,文中介绍的非常详细,需要的朋友可以参考下
    2024-10-10

最新评论