1. Introdução
Muitos dos programas do lado do servidor de hoje são desenvolvidos com base em Java. Para programas Socket desenvolvidos em Java, se ocorrer um problema após o servidor ficar online, ele precisará ser reiniciado manualmente se ele desligar no meio da noite. , ainda é muito problemático.
A maioria das soluções consiste em usar outros processos para proteger o programa do servidor. Se o programa do servidor travar, inicie o programa do servidor por meio do processo daemon.
E se o processo daemon travar? Use guardas duplas para melhorar a estabilidade. O guarda A é responsável por monitorar o programa do servidor e o guarda B. O guarda B é responsável por monitorar o guarda A. Se houver um problema em qualquer um dos lados, o programa pode ser iniciado rapidamente para melhorar a estabilidade do. programa de servidor.
O ambiente de execução do Java é diferente dos programas desenvolvidos em linguagens como C. Os programas Java são executados na JVM. Ao contrário da linguagem C, que pode criar um processo diretamente, criar um processo em Java é equivalente a usar java -jar xxx.jar para iniciar um programa.
O programa de inicialização Java não tem um limite de instância única semelhante ao C#. Você pode iniciar vários, mas não pode iniciar mais de um. Você não pode ter vários guardiões A para proteger o programa do servidor.
2. Explicação técnica
A explicação técnica aqui é relativamente aproximada. Verifique o Baidu para obter detalhes. Eu apenas explico as funções aqui.
1. comando jps.
A ferramenta de comando que vem com o JDK usa jps -l para listar os programas Java em execução e exibir o pid e o nome do programa Java. Válido apenas para programas Java. Na verdade, o que você está visualizando é a JVM em execução.
2. Uso da classe java.nio.channels.FileLock Esta é uma classe em Java novo IO. Você pode usá-la para bloquear o arquivo durante a leitura. arquivo está bloqueado por outros programas.
3. ProcessBuilder e Processo
Os dois princípios são semelhantes. Ambos chamam comandos do sistema para executar e depois retornam informações. Mas a codificação rígida fará com que seu programa Java perca a portabilidade. Você pode separar os comandos no arquivo de configuração.
3. Princípios de design
Servidor: programa de servidor
R: Daemon A
B: Daemon B
A.lock: bloqueio de arquivo do daemon A
B.lock: Bloqueio de arquivo do daemon B
-------------------------------------------------- --------------------------------
Passo 1: Primeiro, não considere o servidor, considere apenas a proteção entre A e B.
1.A determina se B está vivo e, se não, inicia B
2.B determina se A está vivo e, caso contrário, inicia A.
3. Durante o processo de execução, A e B vão um ao outro para obter o bloqueio de arquivo um do outro. Se conseguirem, isso prova que a outra parte está inativa e, em seguida, inicia a outra parte.
4. Quando A é iniciado, obtenha o bloqueio do arquivo A.lock. Se for obtido, prova que A não foi iniciado, então A é executado; se não obtiver o bloqueio, prova que A já foi iniciado; B obteve o bloqueio ao julgar. Se A já começou e não há necessidade de iniciar A novamente. Se B obtiver o bloqueio ao fazer o julgamento, não importa, B iniciará A novamente de qualquer maneira.
5. Quando B é iniciado, o princípio é o mesmo de A.
6. Se A desligar durante a operação, B determina que A desligou e inicia A. BDa mesma forma.
Etapa 2: ingressar no servidor
1.A é usado para proteger B e Servidor, e B é usado para proteger A.
2. O princípio é o mesmo do Passo 1, exceto que A tem múltiplas tarefas de proteger Serer.
3. Quando A estiver em execução, use o processo pid para detectar que o servidor desligou e, em seguida, inicie o servidor.
4. Se o Servidor e A estiverem inativos, B iniciará A e A iniciará o Servidor.
5. Se o Servidor e B estiverem inativos, A inicia o Servidor e B
6. Se A e B morrerem, a guarda termina
Passo 3: Use Shutdown para encerrar a guarda, caso contrário ela iniciará automaticamente após encerrar o servidor.
4. Realização
1. Implementação do GuardA
Copie o código do código da seguinte forma:
classe pública GuardA {
// GuardA é usado para manter seu próprio bloqueio
Arquivo privado fileGuardA;
privado FileOutputStream fileOutputStreamGuardA;
fileChannel privado fileChannelGuardA;
privado FileLock fileLockGuardA;
// GuardB é usado para detectar o bloqueio de B
Arquivo privado fileGuardB;
privado FileOutputStream fileOutputStreamGuardB;
fileChannel privado fileChannelGuardB;
privado FileLock fileLockGuardB;
public GuardA() lança exceção {
arquivoGuardA = novo arquivo(Configure.GUARD_A_LOCK);
if (!fileGuardA.exists()) {
fileGuardA.createNewFile();
}
//Adquira o bloqueio do arquivo e saia se não puder provar que o GuardA foi iniciado.
fileOutputStreamGuardA = novo FileOutputStream(fileGuardA);
fileChannelGuardA = fileOutputStreamGuardA.getChannel();
arquivoLockGuardA = arquivoChannelGuardA.tryLock();
if (fileLockGuardA == nulo) {
Sistema.exit(0);
}
arquivoGuardB = novo arquivo (Configure.GUARD_B_LOCK);
if (!fileGuardB.exists()) {
fileGuardB.createNewFile();
}
fileOutputStreamGuardB = novo FileOutputStream(fileGuardB);
fileChannelGuardB = fileOutputStreamGuardB.getChannel();
}
/**
* Verifique se B existe
*
* @return true B já existe
*/
public boolean checkGuardB() {
tentar {
arquivoLockGuardB = arquivoChannelGuardB.tryLock();
if (fileLockGuardB == nulo) {
retornar verdadeiro;
} outro {
arquivoLockGuardB.release();
retornar falso;
}
} catch (IOException e) {
Sistema.exit(0);
// nunca toque
retornar verdadeiro;
}
}
}
2. Implementação do GuardServer
Copie o código do código da seguinte forma:
classe pública GuardServer {
private String nome do servidor;
public GuardServer(String nome do servidor) {
this.servername = nome do servidor;
}
public void startServer(String cmd) lança exceção {
System.out.println("Iniciar Servidor: " + cmd);
//comandos separados
// String[] cmds = cmd.split(" ");
// Construtor ProcessBuilder = new ProcessBuilder(cmds);
//
Construtor ProcessBuilder=new ProcessBuilder(new String[]{"/bin/sh","-c",cmd});
//Localiza a saída do programa servidor em /dev/tty
construtor.redirectOutput(novo arquivo("/dev/tty"));
construtor.redirectError(novo arquivo("/dev/tty"));
construtor.start(); // lança IOException
Thread.sleep(10000);
}
/**
* Verifique se o serviço existe
*
* @return Retorna o pid do programa java configurado
* @return pid >0 retorna pid <=0, o que significa que o programa java especificado não está em execução.
* **/
public int checkServer() lança exceção {
intpid = -1;
Processo processo = nulo;
Leitor BufferedReader = null;
processo = Runtime.getRuntime().exec("jps -l");
leitor = novo BufferedReader(new InputStreamReader(process.getInputStream()));
Linha de corda;
while ((linha = leitor.readLine()) != null) {
String[] strings = line.split("//s{1,}");
if (strings. comprimento <2)
continuar;
if (strings[1].contains(nomedoservidor)) {
pid = Integer.parseInt(strings[0]);
quebrar;
}
}
leitor.close();
process.destruir();
retornar pid;
}
}
3. Implementação GuardAMain
Copie o código do código da seguinte forma:
classe pública GuardAMain {
public static void main(String[] args) lança exceção {
GuardaA guardaA = new GuardaA();
Configurar configurar = new Configurar();
Servidor GuardServer = new GuardServer(configure.getServername());
enquanto (verdadeiro) {
//Executa o GuardB se o GuardB não estiver em execução
if (!guardA.checkGuardB()) {
System.out.println("Iniciar GuardB....");
Runtime.getRuntime().exec(configure.getStartguardb());
}
// Verifica a sobrevivência do servidor
if (servidor.checkServer() <= 0) {
booleano isServerDown = true;
//verificação de viagem
for (int i = 0; i < 3; i++) {
//Se o serviço estiver ativo
if (servidor.checkServer() > 0) {
isServerDown = falso;
quebrar;
}
}
if(isServerDown)
servidor.startServer(configure.getStartserver());
}
Thread.sleep(configure.getInterval());
}
}
}
4. Implementação de desligamento
Copie o código do código da seguinte forma:
classe pública Desligar {
public static void main(String[] args) lança exceção {
Configurar configurar = new Configurar();
System.out.println("Protetores de desligamento..");
for (int i = 0; i < 3; i++) {
Processo p = Runtime.getRuntime().exec("jps -l");
Leitor BufferedReader = new BufferedReader(new InputStreamReader(p.getInputStream()));
Linha de corda;
while ((linha = leitor.readLine()) != null) {
if (line.toLowerCase().contains("Guarda".toLowerCase())) {
String[] strings = line.split("//s{1,}");
int pid = Integer.parseInt(strings[0]);
Runtime.getRuntime().exec(configure.getKillcmd() + " " + pid);
}
}
p.waitFor();
leitor.close();
p.destruir();
Thread.sleep(2000);
}
System.out.println("Os guardas estão desligados");
}
}
5. GuardB é semelhante ao GuardA
5. Baixe e use
Pasta do projeto: guard_demo
Endereço para download: http://pan.baidu.com/s/1bn1Y6BX
Se você tiver alguma dúvida ou sugestão, entre em contato comigo