java实现守护服务器程序

    xiaoxiao2022-07-15  147

    一、简介   现在的服务器端程序很多都是基于 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类似    五、下载与使用   项目文件夹:guard_demo   下载地址:http://pan.baidu.com/s/1bn1Y6BX 最新内容请见作者的GitHub页:http://qaseven.github.io/ 相关资源:守护进程(java)
    最新回复(0)