Java實現Linux下雙守護進程_java

來源:互聯網
上載者:User

一、簡介

  現在的伺服器端程式很多都是基於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

如果有什麼疑問或者建議,請聯絡我

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.