java实现守护服务器程序

简介:
一、简介
  现在的服务器端程序很多都是基于 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/
相关文章
|
28天前
|
Java 流计算
利用java8 的 CompletableFuture 优化 Flink 程序
本文探讨了Flink使用avatorscript脚本语言时遇到的性能瓶颈,并通过CompletableFuture优化代码,显著提升了Flink的QPS。文中详细介绍了avatorscript的使用方法,包括自定义函数、从Map中取值、使用Java工具类及AviatorScript函数等,帮助读者更好地理解和应用avatorscript。
利用java8 的 CompletableFuture 优化 Flink 程序
|
19天前
|
Java Maven 数据安全/隐私保护
如何实现Java打包程序的加密代码混淆,避免被反编译?
【10月更文挑战第15天】如何实现Java打包程序的加密代码混淆,避免被反编译?
31 2
|
21天前
|
安全 Java Linux
java程序设置开机自启
java程序设置开机自启
|
24天前
|
运维 Java Linux
【运维基础知识】Linux服务器下手写启停Java程序脚本start.sh stop.sh及详细说明
### 启动Java程序脚本 `start.sh` 此脚本用于启动一个Java程序,设置JVM字符集为GBK,最大堆内存为3000M,并将程序的日志输出到`output.log`文件中,同时在后台运行。 ### 停止Java程序脚本 `stop.sh` 此脚本用于停止指定名称的服务(如`QuoteServer`),通过查找并终止该服务的Java进程,输出操作结果以确认是否成功。
32 1
|
29天前
|
SQL 安全 网络安全
守护数字资产:服务器迁移期间的安全挑战与对策
【10月更文挑战第4天】在数字化转型的浪潮中,服务器迁移成为企业不可避免的任务。然而,迁移过程中的安全挑战不容忽视。本文从安全考量的角度,探讨了服务器迁移期间可能遇到的安全问题,并提供了相应的对策和代码示例。
43 3
|
1月前
|
分布式计算 资源调度 Hadoop
大数据-01-基础环境搭建 超详细 Hadoop Java 环境变量 3节点云服务器 2C4G XML 集群配置 HDFS Yarn MapRedece
大数据-01-基础环境搭建 超详细 Hadoop Java 环境变量 3节点云服务器 2C4G XML 集群配置 HDFS Yarn MapRedece
65 4
|
1月前
|
Java Shell Maven
Flink-11 Flink Java 3分钟上手 打包Flink 提交任务至服务器执行 JobSubmit Maven打包Ja配置 maven-shade-plugin
Flink-11 Flink Java 3分钟上手 打包Flink 提交任务至服务器执行 JobSubmit Maven打包Ja配置 maven-shade-plugin
91 4
|
26天前
|
Java Python
如何通过Java程序调用python脚本
如何通过Java程序调用python脚本
22 0
|
1月前
|
Java
java的程序记录时间
java的程序记录时间
24 0
|
4天前
|
弹性计算
阿里云2核16G服务器多少钱一年?亲测价格查询1个月和1小时收费标准
阿里云2核16G服务器提供多种ECS实例规格,内存型r8i实例1年6折优惠价为1901元,按月收费334.19元,按小时收费0.696221元。更多规格及详细报价请访问阿里云ECS页面。
37 9