Devemos criar programas para se matar aleatoriamente? [fechadas]

76

Resumidamente, devemos projetar a morte em nossos programas, processos e threads em um nível baixo, para o bem do sistema como um todo?

As falhas acontecem. Processos morrem. Planejamos o desastre e, ocasionalmente, nos recuperamos dele. Mas raramente projetamos e implementamos a morte imprevisível do programa. Esperamos que a disponibilidade de nossos serviços seja tão longa quanto nos preocupamos em mantê-los funcionando.

Um macroexemplo desse conceito é o Macaco do Caos da Netflix , que termina aleatoriamente instâncias do AWS em alguns cenários. Eles alegam que isso os ajudou a descobrir problemas e construir sistemas mais redundantes.

O que eu estou falando é de nível inferior. A ideia é que os processos tradicionalmente de longa duração saiam aleatoriamente. Isso deve forçar a redundância no design e, em última instância, produzir sistemas mais resilientes.

Esse conceito já tem um nome? Já está sendo usado na indústria?

EDITAR

Com base nos comentários e respostas, receio não estar claro na minha pergunta. Para maior clareza:

  • sim, eu quero dizer aleatoriamente,
  • sim, eu quero dizer em produção e
  • não, não apenas para testes.

Para explicar, gostaria de fazer uma analogia com organismos multicelulares.

Na natureza, os organismos consistem em muitas células. As células se juntam para criar redundância e acabam morrendo. Mas deve sempre haver células suficientes dos tipos certos para o organismo funcionar. Este sistema altamente redundante também facilita a cura quando ferido. As células morrem e o organismo vive.

A incorporação da morte aleatória em um programa forçaria o sistema maior a adotar estratégias de redundância para permanecer viável. Essas mesmas estratégias ajudariam o sistema a permanecer estável diante de outros tipos de falhas imprevisíveis?

E, se alguém tentou isso, como se chama? Eu gostaria de ler mais sobre isso, se já existir.

    
por jimbojw 25.06.2013 / 01:18
fonte

16 respostas

60

Não.

Devemos projetar o manuseio de caminho ruim adequado e projetar casos de teste (e outras melhorias de processo) para validar que os programas lidam bem com essas condições excepcionais. Coisas como o Chaos Monkey podem ser parte disso, mas assim que você faz "deve falhar aleatoriamente" um requisito falhas aleatórias reais tornam-se coisas que os testadores não podem arquivar como bugs.

    
por 22.06.2013 / 17:37
fonte
19

O processo de introdução de defeitos em software ou hardware para testar os mecanismos de tolerância a falhas é chamado Injeção de falhas .

Da Wikipedia:

The technique of fault injection dates back to the 1970s when it was first used to induce faults at a hardware level. This type of fault injection is called Hardware Implemented Fault Injection (HWIFI) and attempts to simulate hardware failures within a system. The first experiments in hardware fault injection involved nothing more than shorting connections on circuit boards and observing the effect on the system (bridging faults). It was used primarily as a test of the dependability of the hardware system. Later specialised hardware was developed to extend this technique, such as devices to bombard specific areas of a circuit board with heavy radiation. It was soon found that faults could be induced by software techniques and that aspects of this technique could be useful for assessing software systems. Collectively these techniques are known as Software Implemented Fault Injection (SWIFI).

    
por 22.06.2013 / 19:56
fonte
9

Sim. Não. Talvez.

A terminação periódica é uma espada de dois gumes. Você vai ser atingido com uma vantagem ou outra, e qual é o menor de dois males depende da sua situação.

Uma vantagem é a confiabilidade: se você forçar o programa a terminar de maneira aleatória (ou previsível) e de maneira ordenada, você pode estar preparado para o evento e lidar com ele. Você pode garantir que o processo será encerrado quando não estiver ocupado fazendo algo útil. Isso também garante que os bugs que se manifestam além do tempo de execução sancionado não levantem suas cabeças feias na produção, o que é uma coisa boa. O Apache HTTPD tem uma configuração que permite ajustar quantas solicitações um processo filho (ou encadeamento em versões mais recentes) exibirá antes de terminar.

A outra vantagem também é a confiabilidade: se você não permitir que o programa seja executado por muito tempo, nunca encontrará bugs que se manifestem com o tempo. Quando você finalmente se depara com um desses bugs, é muito mais provável que o programa retorne uma resposta errada ou deixe de retornar um. Pior, se você executar muitos segmentos do mesmo trabalho, um bug induzido por tempo ou contagem pode afetar um grande número de tarefas de uma só vez e resultar em uma viagem às 3 horas da manhã no escritório.

Em uma configuração em que você executa muitos dos mesmos segmentos (por exemplo, em um servidor da Web), a solução prática é adotar uma abordagem mista que resulte em uma taxa de falha aceitável. Se você executar 100 threads, a execução de uma proporção curta / longa de 99: 1 significa que apenas um exibirá bugs de longo prazo, enquanto os outros continuarão fazendo o que quer que seja, sem falhar. Compare isso com a execução de 100% de duração, em que você corre um risco muito maior de ter todos os threads com falha ao mesmo tempo.

Onde você tem um único encadeamento, provavelmente é melhor deixá-lo rodar e falhar, porque o tempo morto durante uma reinicialização pode resultar em latência indesejada quando há trabalho real a ser feito com sucesso.

Em ambos os casos, é importante que haja algo supervisionando os processos para que eles possam ser reiniciados imediatamente. Além disso, não há nenhuma lei que diga que suas decisões iniciais sobre quanto tempo um processo deve ser executado precisam ser expressas em pedra. A coleta de dados operacionais ajudará você a ajustar seu sistema para manter as falhas em um nível aceitável.

Eu recomendaria contra a finalização aleatória, porque isso dificulta a detecção de bugs relacionados ao tempo. Chaos Monkey faz isso para garantir que o software de supervisão funcione, o que é um problema ligeiramente diferente.

    
por 22.06.2013 / 19:09
fonte
9

Você realmente quer dizer aleatório? Ter seu software matando aleatoriamente soa como uma idéia terrível. Que ponto isso serviria?

Eu estou supondo que o que você realmente quer dizer é que devemos ser realistas sobre threads / processos de longa duração e aceitar que quanto mais tempo eles rodam, maior a probabilidade de eles encontrarem algum tipo de bug oculto, e entrar em um estado não funcional. Então, como uma medida puramente pragmática, o tempo de vida de processos e fios deve ser limitado.

Acredito que, no final dos anos 90, o servidor web Apache usou algo assim. Eles tinham um pool de processos de trabalho (não threads) e cada processo de trabalho seria morto após uma vida útil fixa. Isso impedia que o servidor fosse monopolizado por processos de trabalho que haviam ficado presos em algum estado patológico.

Eu não tenho trabalhado na área há algum tempo, então eu não sei se isso ainda é o caso.

    
por 22.06.2013 / 19:18
fonte
7

O problema que vejo é que, se tal programa morrer, diremos apenas "Oh, é apenas outra terminação aleatória - nada para se preocupar". Mas e se houver um problema real que precise ser consertado? Isso será ignorado.

Os programas já "aleatoriamente" falham devido a desenvolvedores que fazem mystaykes, bugs fazendo isso em sistemas de produção, falhas de hardware, etc. Quando isso ocorre, queremos saber sobre isso para que possamos consertá-lo. Projetar a morte em programas apenas aumenta a probabilidade de falha e só nos forçaria a aumentar a redundância, o que custa dinheiro.

Não vejo nada de errado em matar processos aleatoriamente em um ambiente de teste ao testar um sistema redundante (isso deve estar acontecendo mais do que é), mas não em um ambiente de produção. Será que retiramos alguns discos rígidos de um sistema de produção ao vivo a cada poucos dias ou desativamos um dos computadores em uma aeronave, pois está voando cheio de passageiros? Em um cenário de teste - tudo bem. Em um cenário de produção ao vivo - prefiro não.

    
por 23.06.2013 / 11:09
fonte
4

Adicionar código de saída aleatório ao aplicativo não deve ser necessário. Os testadores podem escrever scripts que matam aleatoriamente os processos do aplicativo.

Na rede, é necessário simular uma rede não confiável para testar uma implementação de protocolo. Isso não é incorporado ao protocolo; ele pode ser simulado no nível do driver do dispositivo ou com algum hardware externo.

Não adicione código de teste ao programa para situações que podem ser alcançadas externamente.

Se isso é destinado à produção, não posso acreditar que seja sério!

Em primeiro lugar, a menos que os processos saiam abruptamente de modo que as transações em andamento e os dados voláteis sejam perdidos, então não é uma implementação honesta do conceito. Saídas planejadas e graciosas, mesmo que aleatoriamente, não ajudam a preparar adequadamente a arquitetura para lidar com falhas reais, que não são graciosas.

Se problemas reais ou reais forem embutidos no aplicativo, eles podem resultar em danos econômicos, assim como defeitos reais, e danos econômicos intencionais são basicamente um ato criminoso quase que por definição.

Você pode se safar de cláusulas no contrato de licenciamento que isentem a responsabilidade civil de quaisquer danos decorrentes da operação do software, mas se esses danos forem intencionais, talvez você não seja capaz de renunciar a responsabilidade criminal. / p>

Nem pense em acrobacias como essa: faça com que funcione da maneira mais confiável possível e coloque em cenários de falha falsos apenas construções ou configurações especiais.

    
por 25.06.2013 / 00:10
fonte
3

Você pode querer pesquisar " recuperação proativa " e " rejuvenescimento " no contexto de sistemas distribuídos tolerantes a falhas, para lidar com falhas arbitrárias (isto é, não só travou processos, mas dados corrompidos e comportamento potencialmente malicioso também). Tem havido muita pesquisa sobre com que frequência e em que condições um processo (em um sentido abstrato, pode realmente ser uma VM ou um host) ser reiniciado. Intuitivamente, você pode entender as vantagens da abordagem como preferir lidar com um processo morto do que com um processo traidor ...

    
por 23.06.2013 / 15:21
fonte
2

Isso não é diferente de testar. Se você está projetando uma solução de failover sempre disponível (como a Netflix), então sim - você deve testá-la. Eu não sei que saídas aleatórias espalhadas por toda a base de código é uma maneira apropriada de testar isso, no entanto. A menos que você esteja realmente empenhado em testar se o seu design é resiliente para fotografar a si mesmo, parece mais apropriado testá-lo manipulando o ambiente ao redor do código e verificando se ele se comporta adequadamente. / p>

Se você não está projetando sistemas redundantes, então não - você não deve adicionar esse recurso porque adicionou algumas saídas aleatórias. Você deve apenas remover as saídas aleatórias, e então você não terá esse problema. Seu ambiente ainda pode falhar em você, ponto em que você irá defini-lo como não suportado / não corrigirá ou endurecerá seu código em relação a essa falha e adicionará um teste para ele. Faça isso com bastante frequência e você perceberá que você realmente está projetando um sistema redundante - veja o cenário # 1.

Em algum momento, você pode determinar que não tem mais certeza de quais falhas são ou não tratadas. Agora você pode começar a puxar o tapete aleatoriamente para detectar os pontos de falha.

A única coisa interessante sobre o exemplo da Netflix é que eles executam esses testes em produção. Isso faz uma certa quantidade de sentido - alguns bugs realmente são apenas coisas que são muito difíceis ou impossíveis de serem simuladas em um ambiente isolado. Eu suspeito que a Netflix passou muito tempo em ambientes de teste antes que eles estivessem confortáveis o suficiente para fazer isso em produção. E realmente tudo o que estão fazendo é tentar que ocorram falhas durante o horário comercial, o que faz um certo sentido para o mercado deles, mas não para muitos outros.

    
por 22.06.2013 / 19:38
fonte
2

O termo que você está procurando foi recentemente cunhado por Nassim Nicholas Taleb: Antifragility. Seu livro Antifragile é definitivamente recomendado. Ele quase não menciona a TI, mas os paralelos óbvios, não ditos, são muito inspiradores. Sua idéia é ampliar a escala de fragilidade < - > robusto a frágil < - > robusto < - > antifrágil. Quebras frágeis com eventos aleatórios, gerencias robustos com eventos aleatórios e ganhos anti-frágeis com eventos aleatórios.

    
por 10.07.2013 / 14:18
fonte
1

Depende. Tenho notado que os programadores tendem a generalizar excessivamente as técnicas que se aplicam ao seu domínio específico, ignorando todos os outros. Por exemplo, obter o programa liberado ao custo de consertar todos os erros pode ser bom ... a menos que você programe controlador de aeronaves, reator nuclear etc. "Não otimize - o custo do programador é maior que o custo de execução do programa" não é necessário válido para HPC como lá programa relativamente simples pode ocupar cluster por meses etc. (ou até mesmo um programa popular que é usado por grande quantidade de usuários). Portanto, mesmo que a empresa X esteja fazendo Y por uma boa razão, você não precisa seguir os próprios passos, pois sua situação pode ser diferente.

Normalmente, as rotinas de tratamento de erros são a pior parte testada do código - embora pareça simples, é difícil simular que não há memória suficiente ou que algum arquivo importante não está lá. Por essa razão, eu li textos que propunham que o kernel Unix falhasse aleatoriamente algumas chamadas do sistema. No entanto, isso tornaria mais difícil escrever programas simples (se eu precisar conectar 3 bibliotecas C ++ para executar um programa em 2 arquivos, uma vez que não quero me preocupar com o tratamento de erros). Mesmo com exceções, GC você precisa garantir que deixou o estado consistente por trás (imagine exceção no meio da adição do nó à lista vinculada).

Quanto mais serviços distribuídos você tiver, mais as falhas serão questionadas "com que frequência", "se" ou "quando". Nos data centers, a substituição de disco em RAIDs faz parte das operações de rotina do que eu conheço - não de falhas inesperadas. Se você opera em grande escala, precisa levar isso em conta, pois mesmo que a probabilidade de falha de um componente seja pequena, é provável que algo falhe.

Eu não sei exatamente o que você está fazendo, mas para saber se vale a pena você precisa pensar se o fracasso é algo que você precisa levar em conta (ignorando os custos) ou algo muito caro para analisar ( como levar os erros em conta custa tempo de desenvolvimento).

    
por 22.06.2013 / 21:24
fonte
1

O servidor IIS tem um recurso configurável que recicla automaticamente os processos de trabalho depois que eles usam uma determinada quantidade de memória ou após atender a um determinado número de solicitações ou depois de estarem ativos por um intervalo de tempo especificado. ( link ) e ( link )

Quando um CONTAINER como o IIS faz isso, faz sentido proteger o servidor contra processos invasores. No entanto, eu preferiria manter isso desativado, porque não faz sentido se você testou suficientemente seu código.

Já trabalhamos em camadas não confiáveis (hardware, rede) para que eu nunca escreva nenhum código que mate aleatoriamente seus threads ou processos intencionalmente. Matar aleatoriamente também é uma má idéia do ponto de vista econômico - ninguém usaria minha API se achasse que eu a programara para falhar aleatoriamente. Por fim, se eu consumisse uma API ou usasse um sistema com threads quebrados aleatoriamente, teria que gastar muito dinheiro para criar um mecanismo de monitoramento robusto o suficiente para que eu pudesse dormir tranquilamente à noite.

Em vez disso, se eu estivesse desenvolvendo um sistema ou uma API, eu escreveria scripts ou usaria um equipamento que faria isso apenas para testar a resiliência do sistema. E eu faria esse teste em todas as compilações para identificar construções ruins. No entanto, enquanto isso seria um teste necessário, nunca poderia ser um teste "suficiente".

    
por 10.07.2013 / 12:54
fonte
1

Existe uma literatura relacionada a essa idéia, chamada de software Crash-Only (também Recovery Oriented Computing) e você pode começar com este papel usenix da Candea & Fox de 2003. Ao invés de mortes aleatórias, o autor argumenta que você pode melhorar a confiabilidade do sistema apenas parando seus programas matando-os, então ter um único botão de parada como um botão de desligamento e um único caminho de inicialização bem exercitado para recuperação.

Embora eu não saiba ao certo o quão bem a ideia pegou, algumas das técnicas específicas permanecem úteis. Por exemplo, não confiar em seu software para ser desligado quando solicitado e, portanto, usar programas de supervisão especializados (por exemplo, supervisord etc) e também pensar cuidadosamente sobre qual estado do programa é essencial e certificar-se de que ele foi gravado nos momentos apropriados em um data store projetado para habilitar a recuperação (por exemplo, um banco de dados sql).

    
por 27.07.2013 / 21:46
fonte
1

Realmente aleatoriamente, não. Mas provavelmente é uma boa idéia que processos / threads de longa execução saiam / reiniciem em um determinado intervalo, ou depois de ter ficado ocioso por uma duração determinada (mas dependente de certos critérios) ou após a execução de um determinado tipo de tarefa. Processos de execução demorada acumulam inevitavelmente itens obsoletos, podem presumivelmente ficar presos à memória, evitando que o espaço de swap seja liberado, e tudo isso fica (ou deveria ser) limpo quando eles saem, melhorando a estabilidade geral do sistema.

    
por 28.07.2013 / 10:33
fonte
1

Depende do tipo de aplicativo que você está criando.

As falhas aleatórias são uma ótima maneira de testar e melhorar a robustez de sistemas distribuídos (em rede).

No exemplo da Netflix, quando o seu programa depende de serviços remotos que podem falhar por diversos motivos que estão fora de seu controle (o disco rígido vai mal, perda de energia, meteoro cai no data center, etc). Seu serviço ainda precisa continuar funcionando de alguma forma.

Como você faz isso? Adicionar redundância e dimensionamento é uma solução comum.

Por exemplo, se um mouse mastigar o cabo de alimentação do servidor, o serviço deverá ter alguma solução para continuar funcionando. Pode, por exemplo, manter servidores de backup redundantes que serão usados em vez disso.

No entanto, se o seu programa é um aplicativo de processo único que não funciona em uma rede, tê-lo eliminado não testará nada, já que não há como recuperá-lo.

Aqui estão alguns comentários extras sobre o conceito Chaos Monkeys link

    
por 30.07.2013 / 02:28
fonte
1

É possível que um flip aleatório aconteça devido a radiação cósmica . Esse problema foi reconhecido, e várias técnicas foram desenvolvidas para evitar que a troca de bits acontecesse.

No entanto, não é possível corrigi-lo 100%, e corrupção de memória ainda pode causar problemas, e esses problemas ainda estão acontecendo ( com probabilidade muito baixa ).

Agora responda sua pergunta. Se você precisa ou não projetar um sistema muito robusto, isso depende do que você está fazendo. Se você precisa criar uma nave espacial, é melhor torná-la super robusta e, em seguida, precisará levar em conta todos os problemas possíveis.

Se você precisa projetar um aplicativo de desktop normal, deve observar falhas aleatórias como erros em seu código.

    
por 02.08.2013 / 09:16
fonte
0

Isso não parece uma ideia absurda.

O Android OS mata e reinicia aleatoriamente aplicativos / serviços do usuário o tempo todo. Na minha experiência, isso definitivamente me ajudou a pensar mais profundamente sobre as condições de erro, bem como projetar arquiteturas mais robustas.

    
por 22.06.2013 / 21:40
fonte

Tags