zoukankan      html  css  js  c++  java
  • 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的实现

     1 public class GuardA {
     2     // GuardA用于维持自己的锁
     3     private File fileGuardA;
     4     private FileOutputStream fileOutputStreamGuardA;
     5     private FileChannel fileChannelGuardA;
     6     private FileLock fileLockGuardA;
     7     // GuardB用于检测B的锁
     8     private File fileGuardB;
     9     private FileOutputStream fileOutputStreamGuardB;
    10     private FileChannel fileChannelGuardB;
    11     private FileLock fileLockGuardB;
    12 
    13     public GuardA() throws Exception {
    14         fileGuardA = new File(Configure.GUARD_A_LOCK);
    15         if (!fileGuardA.exists()) {
    16             fileGuardA.createNewFile();
    17         }
    18         //获取文件锁,拿不到证明GuardA已启动则退出
    19         fileOutputStreamGuardA = new FileOutputStream(fileGuardA);
    20         fileChannelGuardA = fileOutputStreamGuardA.getChannel();
    21         fileLockGuardA = fileChannelGuardA.tryLock();
    22         if (fileLockGuardA == null) {
    23             System.exit(0);
    24         }
    25         
    26         fileGuardB = new File(Configure.GUARD_B_LOCK);
    27         if (!fileGuardB.exists()) {
    28             fileGuardB.createNewFile();
    29         }
    30         fileOutputStreamGuardB = new FileOutputStream(fileGuardB);
    31         fileChannelGuardB = fileOutputStreamGuardB.getChannel();
    32     }
    33 
    34     /**
    35      * 检测B是否存在
    36      * 
    37      * @return true B已经存在
    38      */
    39     public boolean checkGuardB() {
    40         try {
    41             fileLockGuardB = fileChannelGuardB.tryLock();
    42             if (fileLockGuardB == null) {
    43                 return true;
    44             } else {
    45                 fileLockGuardB.release();
    46                 return false;
    47             }
    48         } catch (IOException e) {
    49             System.exit(0);
    50             // never touch
    51             return true;
    52         }
    53     }
    54 }


    2、GuardServer的实现

     1 public class GuardServer {
     2     private String servername;
     3 
     4     public GuardServer(String servername) {
     5         this.servername = servername;
     6     }
     7 
     8     public void startServer(String cmd) throws Exception {
     9         System.out.println("Start Server : " + cmd);
    10         //将命令分开
    11 //        String[] cmds = cmd.split(" ");
    12 //        ProcessBuilder builder = new ProcessBuilder(cmds);
    13     
    14         //
    15         ProcessBuilder builder=new ProcessBuilder(new String[]{"/bin/sh","-c",cmd});
    16         //将服务器程序的输出定位到/dev/tty
    17         builder.redirectOutput(new File("/dev/tty"));
    18         builder.redirectError(new File("/dev/tty"));
    19         builder.start(); // throws IOException
    20         Thread.sleep(10000);
    21     }
    22 
    23     /**
    24      * 检测服务是否存在
    25      * 
    26      * @return 返回配置的java程序的pid
    27      * @return pid >0 返回的是 pid <=0 代表指定java程序未运行
    28      * **/
    29     public int checkServer() throws Exception {
    30         int pid = -1;
    31         Process process = null;
    32         BufferedReader reader = null;
    33         process = Runtime.getRuntime().exec("jps -l");
    34         reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
    35         String line;
    36         while ((line = reader.readLine()) != null) {
    37             String[] strings = line.split("\s{1,}");
    38             if (strings.length < 2)
    39                 continue;
    40             if (strings[1].contains(servername)) {
    41                 pid = Integer.parseInt(strings[0]);
    42                 break;
    43             }
    44         }
    45         reader.close();
    46         process.destroy();
    47         return pid;
    48     }
    49 }


    3、GuardAMain实现

     1 public class GuardAMain {
     2     public static void main(String[] args) throws Exception {
     3         GuardA guardA = new GuardA();
     4         Configure configure = new Configure();
     5         GuardServer server = new GuardServer(configure.getServername());
     6         while (true) {
     7             // 如果GuardB未运行 运行GuardB
     8             if (!guardA.checkGuardB()) {
     9                 System.out.println("Start GuardB.....");
    10                 Runtime.getRuntime().exec(configure.getStartguardb());
    11             }
    12             // 检测服务器存活
    13             if (server.checkServer() <= 0) {
    14                 boolean isServerDown = true;
    15                 // trip check
    16                 for (int i = 0; i < 3; i++) {
    17                     // 如果服务是存活着
    18                     if (server.checkServer() > 0) {
    19                         isServerDown = false;
    20                         break;
    21                     }
    22                 }
    23                 if (isServerDown)
    24                     server.startServer(configure.getStartserver());
    25             }
    26             Thread.sleep(configure.getInterval());
    27         }
    28     }
    29 }


    4、Shutdown实现

     1 public class ShutDown {
     2     public static void main(String[] args) throws Exception {
     3         Configure configure = new Configure();
     4         System.out.println("Shutdown Guards..");
     5         for (int i = 0; i < 3; i++) {
     6             Process p = Runtime.getRuntime().exec("jps -l");
     7             BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
     8             String line;
     9             while ((line = reader.readLine()) != null) {
    10                 if (line.toLowerCase().contains("Guard".toLowerCase())) {
    11                     String[] strings = line.split("\s{1,}");
    12                     int pid = Integer.parseInt(strings[0]);
    13                     Runtime.getRuntime().exec(configure.getKillcmd() + " " + pid);
    14                 }
    15             }
    16             p.waitFor();
    17             reader.close();
    18             p.destroy();
    19             Thread.sleep(2000);
    20         }
    21         System.out.println("Guards is shutdown");
    22     }
    23 }


    5、GuardB与GuardA类似

  • 相关阅读:
    JavaScript 消息框
    DOM事件
    修改输入框placeholder文字默认颜色-webkit-input-placeholder
    css—文字渐变色
    css—各浏览器下的背景色渐变
    $.ajax()方法详解
    使用meta实现页面的定时刷新或跳转
    python的连接mysql的安装
    django安装
    速查
  • 原文地址:https://www.cnblogs.com/vikde/p/3955835.html
Copyright © 2011-2022 走看看