1. Introduction
De nombreux programmes côté serveur actuels sont développés sur la base de Java. Pour les programmes Socket développés en Java, si un problème survient après la mise en ligne d'un tel serveur, il doit être redémarré manuellement s'il raccroche au milieu de la nuit. , c'est toujours très gênant.
La plupart des solutions consistent à utiliser d'autres processus pour protéger le programme serveur. Si le programme serveur se bloque, démarrez-le via le processus démon.
Que se passe-t-il si le processus démon se bloque ? Utilisez deux gardes pour améliorer la stabilité. Le garde A est responsable de la surveillance du programme serveur et le garde B. Le garde B est responsable de la surveillance du garde A. S'il y a un problème de chaque côté, le programme peut être rapidement démarré pour améliorer la stabilité du programme serveur.
L'environnement d'exécution de Java est différent des programmes développés dans des langages tels que les programmes C. Java exécutés sur la JVM. Contrairement au langage C, qui peut créer directement un processus, créer un processus en Java équivaut à utiliser java -jar xxx.jar pour démarrer un programme.
Le programme de démarrage Java n'a pas de limite d'instance unique similaire à C#. Vous pouvez en démarrer plusieurs, mais vous ne pouvez pas en démarrer plusieurs. Vous ne pouvez pas avoir plusieurs tuteurs A pour protéger le programme serveur.
2. Explication technique
L'explication technique ici est relativement approximative. Veuillez consulter Baidu pour plus de détails. J'explique uniquement les fonctions ici.
1. commande jps.
L'outil de commande fourni avec le JDK utilise jps -l pour répertorier les programmes Java en cours d'exécution et afficher le pid et le nom du programme Java. Valable uniquement pour les programmes Java. En fait, ce que vous visualisez est la JVM en cours d'exécution.
2. Utilisation de la classe java.nio.channels.FileLock Il s'agit d'une classe dans le nouveau IO Java. Vous pouvez l'utiliser pour verrouiller le fichier lors de la lecture du fichier. Lorsque vous déterminez si le fichier est verrouillé, vous pouvez déterminer si le fichier est verrouillé. le fichier est verrouillé par d’autres programmes utilisés.
3. ProcessBuilder et processus
Les deux principes sont similaires. Ils appellent tous deux des commandes système à exécuter puis renvoient des informations. Mais le codage en dur entraînera une perte de portabilité de votre programme Java. Vous pouvez séparer les commandes dans le fichier de configuration.
3. Principes de conception
Serveur : programme serveur
A : Démon A
B : Démon B
A.lock : verrouillage des fichiers du démon A
B.lock : verrouillage des fichiers du démon B
-------------------------------------------------- --------------------------------
Étape 1 : Tout d’abord, ne considérez pas le serveur, considérez uniquement la protection entre A et B.
1.A détermine si B est vivant, et sinon, démarre B
2.B détermine si A est vivant et démarre A sinon.
3. Pendant le processus en cours, A et B se rencontrent pour obtenir le verrouillage des fichiers de l'autre. S'ils l'obtiennent, cela prouve que l'autre partie est en panne, puis démarre l'autre partie.
4. Lorsque A démarre, obtenez le verrou du fichier A.lock. S'il est obtenu, cela prouve que A n'est pas démarré, alors A s'exécute s'il n'obtient pas le verrou, cela prouve que A a déjà démarré, ou B a obtenu le verrou lors du jugement. Si A a déjà commencé et qu'il n'est pas nécessaire de recommencer A. Si B obtient le verrou lors du jugement, cela n'a pas d'importance, B recommencera A de toute façon.
5. Lorsque B démarre, le principe est le même que A.
6. Si A raccroche pendant le fonctionnement, B détermine que A a raccroché et démarre A. De même.
Étape 2 : Rejoindre le serveur
1.A est utilisé pour protéger B et le serveur, et B est utilisé pour protéger A.
2. Le principe est le même que celui de l’étape 1, sauf que A a plusieurs tâches de garde des Sérères.
3. Lorsque A est en cours d'exécution, utilisez le processus pid pour détecter que le serveur a raccroché, puis démarrez le serveur.
4. Si le serveur et A sont en panne, B démarrera A, puis A démarrera le serveur.
5. Si le serveur et B sont en panne, A démarre le serveur et B
6. Si A et B meurent tous les deux, la garde se termine
Étape 3 : Utilisez Shutdown pour mettre fin à la garde, sinon elle démarrera automatiquement après avoir arrêté le serveur.
4. Réalisation
1. Mise en œuvre de GuardA
Copiez le code comme suit :
classe publique GuardA {
// GuardA est utilisé pour maintenir son propre verrou
Fichier privé fileGuardA ;
privé FileOutputStream fileOutputStreamGuardA ;
FileChannel privé fileChannelGuardA ;
FileLock privé fileLockGuardA ;
// GuardB est utilisé pour détecter le verrou de B
fichier privé fileGuardB ;
privé FileOutputStream fileOutputStreamGuardB ;
FileChannel privé fileChannelGuardB ;
FileLock privé fileLockGuardB ;
public GuardA() lève une exception {
fileGuardA = nouveau fichier (Configure.GUARD_A_LOCK);
si (!fileGuardA.exists()) {
fileGuardA.createNewFile();
}
// Acquérir le verrou de fichier et quitter s'il ne peut pas prouver que GuardA a été démarré.
fileOutputStreamGuardA = nouveau FileOutputStream(fileGuardA);
fileChannelGuardA = fileOutputStreamGuardA.getChannel();
fileLockGuardA = fileChannelGuardA.tryLock();
si (fileLockGuardA == null) {
Système.exit(0);
}
fileGuardB = nouveau fichier (Configure.GUARD_B_LOCK);
si (!fileGuardB.exists()) {
fileGuardB.createNewFile();
}
fileOutputStreamGuardB = nouveau FileOutputStream(fileGuardB);
fileChannelGuardB = fileOutputStreamGuardB.getChannel();
}
/**
* Vérifiez si B existe
*
* @return true B existe déjà
*/
public booléen checkGuardB() {
essayer {
fileLockGuardB = fileChannelGuardB.tryLock();
si (fileLockGuardB == null) {
renvoie vrai ;
} autre {
fileLockGuardB.release();
renvoie faux ;
}
} catch (IOException e) {
Système.exit(0);
// ne touche jamais
renvoie vrai ;
}
}
}
2. Implémentation de GuardServer
Copiez le code comme suit :
classe publique GuardServer {
nom du serveur de chaîne privé ;
public GuardServer (String nom du serveur) {
this.servername = nom du serveur ;
}
public void startServer (String cmd) lève une exception {
System.out.println("Démarrer le serveur : " + cmd);
//commandes séparées
// String[] cmds = cmd.split(" ");
// Générateur ProcessBuilder = new ProcessBuilder(cmds);
//
ProcessBuilder builder=new ProcessBuilder(new String[]{"/bin/sh","-c",cmd});
// Localisez la sortie du programme serveur dans /dev/tty
builder.redirectOutput(new File("/dev/tty"));
builder.redirectError(new File("/dev/tty"));
builder.start(); // lance une exception IOException
Thread.sleep(10000);
}
/**
* Vérifiez si le service existe
*
* @return Renvoie le pid du programme Java configuré
* @return pid >0 renvoie pid <=0, ce qui signifie que le programme Java spécifié n'est pas en cours d'exécution.
* **/
public int checkServer() lève une exception {
int pid = -1 ;
Processus de traitement = nul ;
Lecteur BufferedReader = null ;
processus = Runtime.getRuntime().exec("jps -l");
lecteur = new BufferedReader(new InputStreamReader(process.getInputStream()));
Ligne de ficelle ;
while ((line = reader.readLine()) != null) {
String[] strings = line.split("//s{1,}");
if (chaînes. longueur < 2)
continuer;
if (strings[1].contains(servername)) {
pid = Integer.parseInt(strings[0]);
casser;
}
}
lecteur.close();
processus.destroy();
retourner le pid ;
}
}
3. GuardAMise en œuvre principale
Copiez le code comme suit :
classe publique GuardAMain {
public static void main (String[] args) lève une exception {
GuardA guardA = new GuardA();
Configurer configure = new Configure();
Serveur GuardServer = new GuardServer(configure.getServername());
tandis que (vrai) {
// Exécutez GuardB si GuardB n'est pas en cours d'exécution
si (!guardA.checkGuardB()) {
System.out.println("Démarrer GuardB....");
Runtime.getRuntime().exec(configure.getStartguardb());
}
// Vérifier la survie du serveur
si (server.checkServer() <= 0) {
booléen isServerDown = true ;
// contrôle de voyage
pour (int je = 0; je < 3; i++) {
// Si le service est actif
si (server.checkServer() > 0) {
isServerDown = faux ;
casser;
}
}
si (isServerDown)
server.startServer(configure.getStartserver());
}
Thread.sleep(configure.getInterval());
}
}
}
4. Mise en œuvre de l'arrêt
Copiez le code comme suit :
Arrêt de classe publique {
public static void main (String[] args) lève une exception {
Configurer configure = new Configure();
System.out.println("Garde d'arrêt..");
pour (int je = 0; je < 3; i++) {
Processus p = Runtime.getRuntime().exec("jps -l");
Lecteur BufferedReader = new BufferedReader(new InputStreamReader(p.getInputStream()));
Ligne de ficelle ;
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();
lecteur.close();
p.destroy();
Thread.sleep(2000);
}
System.out.println("Les gardes sont arrêtés");
}
}
5. GuardB est similaire à GuardA
5. Téléchargez et utilisez
Dossier du projet : guard_demo
Adresse de téléchargement : http://pan.baidu.com/s/1bn1Y6BX
Si vous avez des questions ou des suggestions, veuillez me contacter