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類似

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM