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
posted on 2014-09-11 10:57 順其自然EVO 閱讀(261) 評論(0) 編輯 收藏 所屬分類: 測試學習專欄