1. はじめに
現在のサーバー側プログラムの多くは Java をベースに開発されており、Java で開発された Socket プログラムでは、サーバー側がオンラインになった後に問題が発生した場合、夜中にハングアップした場合は手動で再起動する必要があります。 、それでも非常に面倒です。
ほとんどの解決策は、他のプロセスを使用してサーバー プログラムを保護することです。サーバー プログラムがハングした場合は、デーモン プロセスを通じてサーバー プログラムを起動します。
デーモンプロセスがハングしたらどうなるでしょうか?安定性を向上させるには、デュアル ガードを使用します。ガード A はサーバー プログラムとガード B を監視します。ガード B はガード A を監視します。どちらかの側に問題がある場合、プログラムをすぐに開始して、サーバー プログラムの安定性を向上させることができます。サーバープログラム。
Javaの実行環境はCなどの言語で開発されたプログラムとは異なります。JavaプログラムはJVM上で動作します。プロセスを直接作成できる C 言語とは異なり、Java でのプロセスの作成は、java -jar xxx.jar を使用してプログラムを開始するのと同じです。
Java 起動プログラムには、C# のような単一インスタンスの制限はありません。複数起動することはできますが、複数のガーディアン A を使用してサーバー プログラムを保護することはできません。
2. 技術的な説明
ここでの技術的な説明は比較的大雑把です。詳細については、ここでは機能のみを説明します。
1.jpsコマンド。
JDK に付属のコマンド ツールでは、jps -l を使用して、実行中の Java プログラムを一覧表示し、Java プログラムの PID と名前を表示します。 Java プログラムに対してのみ有効です。実際に表示されているのは、実行中の JVM です。
2. java.nio.channels.FileLock クラスの使用 これは、ファイルの読み取り中にファイルをロックするために使用できるクラスです。ファイルは他のプログラムの使用によってロックされています。
3. ProcessBuilder とプロセス
2 つの原則は似ています。どちらもシステム コマンドを呼び出して実行し、情報を返します。ただし、ハードコーディングすると Java プログラムの移植性が失われます。コマンドを構成ファイルに分割することができます。
3. 設計原則
サーバー: サーバープログラム
A:デーモンA
B: デーモン B
A.lock: デーモン A のファイル ロック
B.lock: デーモン B のファイルロック
-------------------------------------------------- --------------------------------
ステップ 1: まず、サーバーについては考慮せず、A と B の間の保護のみを考慮します。
1.A は B が生存しているかどうかを判断し、生存していない場合は B を開始します。
2.B は A が生存しているかどうかを判断し、生存していない場合は A を開始します。
3. プロセスの実行中、A と B は相互にファイル ロックを取得します。取得すると、相手がダウンしていることが証明され、相手が起動します。
4. A が開始するとき、A.lock ファイルのロックを取得します。取得されている場合は、A が開始されていないことが証明され、ロックを取得していない場合は、A がすでに開始されていることが証明されます。 B が判定時にロックを取得しており、A を再度開始する必要がない場合、判定時に B がロックを取得しても、B は再び A を開始します。
5. B を開始する場合、原理は A と同じです。
6. 運用中に A が電話を切った場合、B は A が電話を切ったものと判断し、A を起動します。 B同様に。
ステップ 2: サーバーに参加する
1.A は B とサーバーを保護するために使用され、B は A を保護するために使用されます。
2. 原則はステップ 1 と同じですが、A が Serer を保護する複数のタスクを持っている点が異なります。
3. A の実行中に、プロセス PID を使用してサーバーがハングアップしたことを検出し、サーバーを起動します。
4. サーバーと A の両方がダウンしている場合は、B が A を起動し、次に A がサーバーを起動します。
5. サーバーと B がダウンしている場合、A はサーバーを起動し、B
6. AとBの両方が死亡した場合、ガードは終了します
ステップ 3: シャットダウンを使用してガードを終了します。そうでない場合は、サーバーの終了後にガードが自動的に開始されます。
4. 実現
1. GuardAの実装
次のようにコードをコピーします。
パブリック クラス GuardA {
// GuardA は独自のロックを維持するために使用されます
プライベートファイル fileGuardA;
プライベート FileOutputStream fileOutputStreamGuardA;
プライベート FileChannel fileChannelGuardA;
プライベート ファイルロック fileLockGuardA;
// GuardB は B のロックを検出するために使用されます
プライベートファイル fileGuardB;
プライベート FileOutputStream fileOutputStreamGuardB;
プライベート FileChannel fileChannelGuardB;
プライベートファイルロックファイルロックガードB;
public GuardA() は例外をスローします {
fileGuardA = 新しいファイル(Configure.GUARD_A_LOCK);
if (!fileGuardA.exists()) {
fileGuardA.createNewFile();
}
// ファイル ロックを取得し、GuardA が開始されたことを証明できない場合は終了します。
fileOutputStreamGuardA = 新しい FileOutputStream(fileGuardA);
fileChannelGuardA = fileOutputStreamGuardA.getChannel();
fileLockGuardA = fileChannelGuardA.tryLock();
if (fileLockGuardA == null) {
System.exit(0);
}
fileGuardB = 新しいファイル(Configure.GUARD_B_LOCK);
if (!fileGuardB.exists()) {
fileGuardB.createNewFile();
}
fileOutputStreamGuardB = 新しい FileOutputStream(fileGuardB);
fileChannelGuardB = fileOutputStreamGuardB.getChannel();
}
/**
* B が存在するかどうかを確認します
*
* @return true Bはすでに存在します
*/
public boolean checkGuardB() {
試す {
fileLockGuardB = fileChannelGuardB.tryLock();
if (fileLockGuardB == null) {
true を返します。
} それ以外 {
fileLockGuardB.release();
false を返します。
}
} キャッチ (IOException e) {
System.exit(0);
// 決して触らないでください
true を返します。
}
}
}
2. GuardServerの実装
次のようにコードをコピーします。
パブリック クラス GuardServer {
プライベート文字列サーバー名。
public GuardServer(String サーバー名) {
this.servername = サーバー名;
}
public void startServer(String cmd) が例外をスローする {
System.out.println("サーバーの起動 : " + cmd);
// 個別のコマンド
// String[] cmds = cmd.split(" ");
// ProcessBuilder ビルダー = 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(); // IOException をスローします
Thread.sleep(10000);
}
/**
※サービスが存在するか確認してください
*
* @return 設定された Java プログラムの PID を返します。
* @return pid >0 は pid <=0 を返します。これは、指定された Java プログラムが実行されていないことを意味します。
* **/
public int checkServer() は例外をスローします {
int pid = -1;
プロセス process = null;
BufferedReader リーダー = null;
プロセス = Runtime.getRuntime().exec("jps -l");
Reader = new BufferedReader(newInputStreamReader(process.getInputStream()));
文字列行;
while ((line = Reader.readLine()) != null) {
String[] strings = line.split("//s{1,}");
if (文字列。長さ < 2)
続く;
if (strings[1].contains(サーバー名)) {
pid = Integer.parseInt(strings[0]);
壊す;
}
}
Reader.close();
process.destroy();
PID を返します。
}
}
3. GuardAMain の実装
次のようにコードをコピーします。
パブリック クラス GuardAMain {
public static void main(String[] args) throws Exception {
GuardA ガード A = 新しい GuardA();
構成configure = new Configure();
GuardServer サーバー = 新しい GuardServer(configure.getServername());
while (true) {
// GuardB が実行されていない場合は GuardB を実行します
if (!guardA.checkGuardB()) {
System.out.println("Start GuardB....");
Runtime.getRuntime().exec(configure.getStartguardb());
}
// サーバーの生存確認
if (server.checkServer() <= 0) {
ブール値 isServerDown = true;
// トリップチェック
for (int i = 0; i < 3; i++) {
// サービスが生きている場合
if (server.checkServer() > 0) {
isServerDown = false;
壊す;
}
}
if(isServerDown)
server.startServer(configure.getStartserver());
}
Thread.sleep(configure.getInterval());
}
}
}
4. シャットダウンの実装
次のようにコードをコピーします。
パブリック クラス シャットダウン {
public static void main(String[] args) throws Exception {
構成configure = new Configure();
System.out.println("シャットダウン ガード..");
for (int i = 0; i < 3; i++) {
プロセス p = Runtime.getRuntime().exec("jps -l");
BufferedReader リーダー = new BufferedReader(new InputStreamReader(p.getInputStream()));
文字列行;
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 はシャットダウンされています");
}
}
5. GuardB は GuardA に似ています
5. ダウンロードして使用する
プロジェクトフォルダー:guard_demo
ダウンロードアドレス: http://pan.baidu.com/s/1bn1Y6BX
ご質問やご提案がございましたら、ご連絡ください