1. Introducción
Muchos de los programas del lado del servidor actuales se desarrollan en base a Java. Para los programas Socket desarrollados en Java, si ocurre un problema después de que dicho lado del servidor se conecte, es necesario reiniciarlo manualmente si se cuelga en medio de la noche. , sigue siendo muy problemático.
La mayoría de las soluciones consisten en utilizar otros procesos para proteger el programa del servidor. Si el programa del servidor se bloquea, inicie el programa del servidor a través del proceso demonio.
¿Qué pasa si el proceso del demonio se bloquea? Utilice guardias duales para mejorar la estabilidad. El guardia A es responsable de monitorear el programa del servidor y el guardia B. El guardia B es responsable de monitorear el guardia A. Si hay un problema en cualquiera de los lados, el programa se puede iniciar rápidamente para mejorar la estabilidad del. programa servidor.
El entorno de ejecución de Java es diferente de los programas desarrollados en lenguajes como C. Los programas Java se ejecutan en la JVM. A diferencia del lenguaje C, que puede crear un proceso directamente, crear un proceso en Java equivale a usar java -jar xxx.jar para iniciar un programa.
El programa de inicio de Java no tiene un límite de instancia única similar a C#. Puede iniciar varios, pero no puede iniciar más de uno. No puede tener varios guardianes A para proteger el programa del servidor.
2. Explicación técnica
La explicación técnica aquí es relativamente aproximada. Consulte Baidu para obtener más detalles. Aquí solo explico las funciones.
1. comando jps.
La herramienta de comando que viene con el JDK usa jps -l para enumerar los programas Java en ejecución y mostrar el pid y el nombre del programa Java. Sólo válido para programas Java. De hecho, lo que estás viendo es la JVM en ejecución.
2. Uso de la clase java.nio.channels.FileLock. Esta es una clase en Java new IO. Puede usarla para bloquear el archivo mientras lee el archivo. El archivo está bloqueado por otros programas.
3. ProcessBuilder y Proceso
Los dos principios son similares. Ambos llaman a los comandos del sistema para que se ejecuten y luego devuelven información. Pero la codificación rígida hará que su programa Java pierda portabilidad. Puede separar los comandos en el archivo de configuración.
3. Principios de diseño
Servidor: programa de servidor
A: demonio A
B: demonio B
A.lock: bloqueo de archivos del demonio A
B.lock: Bloqueo de archivos del demonio B
-------------------------------------------------- --------------------------------
Paso 1: Primero, no considere el servidor, solo considere la protección entre A y B.
1.A determina si B está vivo y, si no, inicia B
2.B determina si A está vivo y comienza A si no.
3. Durante el proceso de ejecución, A y B se acercan para obtener el bloqueo del archivo del otro. Si lo obtienen, demuestra que la otra parte está inactiva y luego inicia la otra parte.
4. Cuando A comienza, obtenga el bloqueo del archivo A.lock. Si se obtiene, prueba que A no se inició, luego A se ejecuta, si no obtiene el bloqueo, prueba que A ya comenzó; B obtuvo el bloqueo al juzgar. Si A ya comenzó y no es necesario comenzar con A nuevamente. Si B obtiene el bloqueo al juzgar, no importa, B comenzará con A de todos modos.
5. Cuando se inicia B, el principio es el mismo que el de A.
6. Si A cuelga durante la operación, B determina que A ha colgado e inicia A. B De manera similar.
Paso 2: unirse al servidor
1.A se usa para proteger B y el servidor, y B se usa para proteger A.
2. El principio es el mismo que el del Paso 1, excepto que A tiene múltiples tareas de proteger a Serer.
3. Cuando A se esté ejecutando, utilice el proceso pid para detectar que el servidor se ha colgado y luego inicie el servidor.
4. Si tanto el servidor como A están inactivos, B iniciará A y luego A iniciará el servidor.
5. Si el servidor y B están inactivos, A inicia el servidor y B.
6. Si tanto A como B mueren, la guardia termina.
Paso 3: Utilice Apagar para finalizar la guardia; de lo contrario, se iniciará automáticamente después de finalizar el servidor.
4. Realización
1. Implementación de GuardA
Copie el código de código de la siguiente manera:
clase pública GuardiaA {
// GuardA se utiliza para mantener su propio bloqueo
Archivo privado fileGuardA;
archivo privado FileOutputStreamOutputStreamGuardA;
fileChannel privado fileChannelGuardA;
FileLock privado fileLockGuardA;
// GuardB se utiliza para detectar el bloqueo de B
Archivo privado fileGuardB;
archivo privado FileOutputStreamOutputStreamGuardB;
FileChannel privado fileChannelGuardB;
FileLock privado fileLockGuardB;
public GuardA() lanza una excepción {
fileGuardA = nuevo archivo (Configure.GUARD_A_LOCK);
si (!fileGuardA.existe()) {
fileGuardA.createNewFile();
}
// Adquiera el bloqueo del archivo y salga si no puede demostrar que se ha iniciado GuardA.
fileOutputStreamGuardA = nuevo FileOutputStream(fileGuardA);
fileChannelGuardA = fileOutputStreamGuardA.getChannel();
fileLockGuardA = fileChannelGuardA.tryLock();
si (fileLockGuardA == nulo) {
Sistema.salir(0);
}
fileGuardB = nuevo archivo (Configure.GUARD_B_LOCK);
si (!fileGuardB.existe()) {
fileGuardB.createNewFile();
}
fileOutputStreamGuardB = nuevo FileOutputStream(fileGuardB);
fileChannelGuardB = fileOutputStreamGuardB.getChannel();
}
/**
* Comprobar si B existe
*
* @return true B ya existe
*/
checkGuardB booleano público() {
intentar {
fileLockGuardB = fileChannelGuardB.tryLock();
si (fileLockGuardB == nulo) {
devolver verdadero;
} demás {
fileLockGuardB.release();
devolver falso;
}
} captura (IOException e) {
Sistema.salir(0);
// nunca tocar
devolver verdadero;
}
}
}
2. Implementación de GuardServer
Copie el código de código de la siguiente manera:
servidor de guardia de clase pública {
nombre del servidor de cadena privada;
GuardServer público (nombre del servidor de cadena) {
this.servername = nombre del servidor;
}
startServer público vacío (String cmd) lanza una excepción {
System.out.println("Iniciar servidor: " + cmd);
//comandos separados
// Cadena[] cmds = cmd.split(" ");
// Constructor ProcessBuilder = new ProcessBuilder(cmds);
//
Constructor ProcessBuilder=new ProcessBuilder(new String[]{"/bin/sh","-c",cmd});
// Ubique la salida del programa del servidor en /dev/tty
builder.redirectOutput(nuevo archivo("/dev/tty"));
builder.redirectError(nuevo archivo("/dev/tty"));
builder.start(); // lanza IOException
Hilo.sleep(10000);
}
/**
* Comprobar si el servicio existe.
*
* @return Devuelve el pid del programa java configurado
* @return pid >0 devuelve pid <=0, lo que significa que el programa Java especificado no se está ejecutando.
* **/
public int checkServer() lanza una excepción {
int pid = -1;
Proceso proceso = nulo;
Lector BufferedReader = nulo;
proceso = Runtime.getRuntime().exec("jps -l");
lector = new BufferedReader(new InputStreamReader(process.getInputStream()));
Línea de cuerda;
mientras ((línea = lector.readLine()) != nulo) {
Cadena[] cadenas = line.split("//s{1,}");
si (cadenas. longitud <2)
continuar;
if (cadenas [1]. contiene (nombre del servidor)) {
pid = Integer.parseInt(cadenas[0]);
romper;
}
}
lector.close();
proceso.destruir();
devolver pid;
}
}
3. Implementación principal de GuardA
Copie el código de código de la siguiente manera:
clase pública GuardaMAin {
public static void main (String [] args) lanza una excepción {
GuardiaA guardiaA = nueva GuardiaA();
Configurar configurar = nuevo Configurar();
Servidor GuardServer = new GuardServer(configure.getServername());
mientras (verdadero) {
// Ejecute GuardB si GuardB no se está ejecutando
si (!guardA.checkGuardB()) {
System.out.println("Iniciar GuardB....");
Runtime.getRuntime().exec(configure.getStartguardb());
}
// Comprobar la supervivencia del servidor
si (servidor.checkServer() <= 0) {
booleano isServerDown = verdadero;
// cheque de viaje
para (int i = 0; i < 3; i++) {
// Si el servicio está activo
si (servidor.checkServer() > 0) {
isServerDown = falso;
romper;
}
}
si(esServerDown)
servidor.startServer(configure.getStartserver());
}
Thread.sleep(configure.getInterval());
}
}
}
4. Implementación del cierre
Copie el código de código de la siguiente manera:
clase pública Apagar {
public static void main (String [] args) lanza una excepción {
Configurar configurar = nuevo Configurar();
System.out.println("Guardias de apagado...");
para (int i = 0; i < 3; i++) {
Proceso p = Runtime.getRuntime().exec("jps -l");
Lector BufferedReader = new BufferedReader(new InputStreamReader(p.getInputStream()));
Línea de cuerda;
mientras ((línea = lector.readLine()) != nulo) {
if (line.toLowerCase().contains("Guardia".toLowerCase())) {
Cadena[] cadenas = line.split("//s{1,}");
int pid = Integer.parseInt(cadenas[0]);
Runtime.getRuntime().exec(configure.getKillcmd() + " " + pid);
}
}
p.waitFor();
lector.close();
p.destruir();
Hilo.sleep(2000);
}
System.out.println("Los guardias están apagados");
}
}
5. GuardB es similar a GuardA
5. Descargar y usar
Carpeta del proyecto: guard_demo
Dirección de descarga: http://pan.baidu.com/s/1bn1Y6BX
Si tienes alguna pregunta o sugerencia, por favor contacta conmigo.