# Tolerância à falha

Tolerância à falha, na ciência da computação, é uma faculdade do software (TFS) e do hardware que permite maior suporte a falhas (bugs), e que continue(m) a operar adequadamente mesmo após falha(s) em seu(s) componente(s). Se sua qualidade de operação diminui, a queda é proporcional à severidade da falha. A tolerância a falhas é propriedade inerente em sistemas de alta disponibilidade ou aplicações críticas como às dedicadas a medicina. É diferente de software tolerante a falhas (STF), já que este é uma sub-área.
Os problemas de mascaramento de falhas e fracassos nas comunicações de rede ocorrem já de longa data. No entanto, sabemos que consistência ou atomicidade podem ser mantidas e que a recuperação (resiliency) pode ser suportada apesar das falhas. Em hardware (HW), as falhas são geralmente causadas por desgaste físico. No entanto, um software (SW) não desgasta com o tempo, ele não tem propriedades físicas, sendo totalmente conceitual. Nele, as falhas são de desenvolvimento e bugs causados por erros humanos.
Ainda, um software tolerante a falhas pode ser visto de duas formas: em sistemas uni-processados e sistemas distribuídos, sendo utilizado para detecção de erros de desenvolvimento. Ainda pode ser estático, em que programas são executados concorrencialmente, e o resultado eleito por votação, e dinâmico, em que são estabelecidos checkpoints no decorrer da execução do programa.

## Técnicas
### Mecanismo de controle de falhas

As atividades relacionadas à tolerância a falhas podem ser subdivididas em quatro fases: detecção de erro, confinamento e avaliação de danos, recuperação de erros e tratamento de falhas.

#### Detecção de erros

Principal fator para qualquer técnica de tolerância a falhas. De um modo geral, a detecção de erros é diretamente proporcional à confiabilidade do sistema. Não é prático, entretanto, equipar o mesmo com um grande número de facilidades para detecção de erros, sobretudo devido ao custo e "overheads" impostos por extensivas verificações.
O sistema não deve ter nenhum ponto comum de falhas relacionado com seu checador, sendo o ideal que este fosse projetado por uma equipe diferente de projetistas. Podemos citar três critérios que caracterizam um projeto ideal:
* deveria ser derivado tão somente das especificações do sistema;
* deveria ser capaz de fazer uma completa checagem do sistema;
* deveria ser independente do sistema.
Duas principais estratégias podem ser usadas no que se refere a checagem: last-moment check e early check. Na prática, entretanto, uma combinação destas duas estratégias deveria ser usada para se atingir uma boa cobertura de falhas. Enquanto as técnicas de detecção de erros podem variar de sistema para sistema, a maioria delas pode ser classificada de acordo com a seguinte divisão:
* Checagem por replicação;
* Checagem por temporização;
* Checagem por codificação;
* Checagem por reversão;
* Checagem por consistência;
* Checagem por diagnóstico;
* Checagem por sequência de controle.

#### Confinamento e avaliação de danos

Mesmo que o mecanismo de detecção fosse perfeito — todos os erros fossem detectados —, haveria ainda um período de tempo decorrido entre o momento em que a falha ocorreu e o momento em que o erro foi detectado (este tempo é geralmente referido como latência da falha).
Um conceito útil para organizar um sistema a fim de facilitar o confinamento dos danos é o da ação atômica. A atividade de um elemento constitui uma ação atômica se não existem interações entre aquele elemento e o resto do sistema por toda duração da atividade.

#### Recuperação de erros

Uma vez que um erro é detectado, esforços devem ser feitos a fim de trazer o sistema de volta para um estado operacional ou, em outras palavras, fazer o sistema recuperar-se dos erros.
O método de recuperação de erro usado pode ser influenciado pela técnica de detecção de erros utilizada. Em sistemas que usam as técnicas de mascaramento de falhas, a detecção e a recuperação de erros ocorrem simultaneamente. Esses sistemas não necessitam incorporar todos os passos relacionados com sistemas tolerantes a falhas mencionados anteriormente, por razões óbvias. A ação de recuperação de erro envolve o uso de algoritmos de recuperação que podem ou não requererem decisões humanas.
A primeira classe de algoritmos é dita automática, ao passo que a segunda é dita controlada manualmente. Algoritmos de recuperação automática podem ser classificados de acordo com o estado do sistema após a ação de recuperação como:
* recuperação completa;
* recuperação com degradação;
* desligamento seguro.

#### Tratamento da falha e continuação do serviço

Uma vez que os passos anteriores não asseguram que a falha que provocou o(s) erro(s) seja identificada, outro passo pode ser necessário a fim de evitar que a falha ocorra novamente. Um tipo particular de erro poderia ser o resultado de muitas fontes de falhas. Este passo é utilizado para isolar a falha ou para reconfigurar o resto do sistema em um esforço para evitar suas manifestações repetidas e, usualmente, envolve dois estágios: localização e reparo do sistema.

## Hardware

A tolerância a falhas não é uma propriedade somente de máquinas individuais; ela pode caracterizar também a maneira como as máquinas interagem entre si. Por exemplo, o protocolo TCP foi projetado para permitir a comunicação de duas vias confiável em uma rede de troca de pacotes, mesmo na presença de ligações imperfeitas sobrecarregadas. Isso é feito requerendo a expectativa de perda de pacotes, duplicação, reordenação ou corrupção, de forma que tais condições não prejudiquem a integridade dos dados.
Formatos digitais também podem ser designados para tolerar dados incorretos. O HTML foi projeto para que os navegadores ignorem entidades (etiquetas) que não entendem sem a instabilidade da apresentação do documento.

### Falha, erro e defeito

Em sistemas computacionais as palavras falha, erro e defeito possuem significados distintos.
A falha acontece no mundo físico dos sistemas computacionais ou por um erro no algoritmo. Por exemplo: caso um disco perca a sincronia dentro de um conjunto de discos com nível de RAID 5 ou 1. Outro caso seria se um servidor com fontes redundantes tivesse uma delas queimada. Em ambos os caso houve uma falha que precisa ser corrigida, mas a princípio ela não se transformou em erro ou defeito.
Vamos supor que um determinado computador tem algum problema na fonte que altere a tensão que alimenta os seus componentes eletrônicos. Até o momento descrito se tem uma falha. Mas se esta alteração de tensão fizer que alguns bits da memória tenham os seus valores trocados de 0 para 1, a falha se transformou em erro. Se o erro anterior não for tratado e o sistema travar ou alterar alguma informação de um banco de dados, por exemplo, o erro se transformou em defeito. Se o usuário foi afetado pelo problema, este não é mais erro e sim defeito.

## Abordagens a software

Um software executado por um único processo consiste em vários componentes (módulos ou sub-programas), em que cada um deles pode conter erros. A função do STF é assegurar que o sistema não fracasse devido à presença de componentes defeituosos.
Para tratar esses erros, diferentemente das falhas em HW, a duplicação do programa (SW) não é suficiente, pois ele continuará executando com a mesma falha de programação. Assim, existem duas abordagens sugeridas: recovery block approach e N-version programing.

### Abordagem Recovery Block (Bloco de recuperação)

A proposta com a finalidade de prover uma abordagem organizacional para diversos desenvolvimentos a fim de suportar STF foi desenvolvida para manipular o desenvolvimento de falhas em componentes de SW, mas também pode enfrentar erros em SW que são causados por falhas em HW. Essa é uma técnica dinâmica que objetiva mascarar a falha de alguns módulos.
O ponto de partida para a utilização de blocos de recuperação é a disponibilidade de várias versões de cada módulo, que atendam aos requisitos definidos na especificação do problema a ser solucionado.
A execução inicia pela primeira versão - rotina primária - e seu resultado é submetido ao teste de aceitação. Se aceito, as demais versões não são executadas. Caso contrário, a segunda versão - rotina alternativa 1 - é executada e submetida ao teste de aceitação.
Para recuperação de erros, o bloco de recuperação emprega o mecanismo de recuperação por retrocesso. Antes de executar a rotina primária um ponto de recuperação é estabelecido, salvando o estado naquele ponto. Se um erro é detectado pelo teste de aceitação, o processo é restaurado ao estado salvo no momento em que o ponto de recuperação foi estabelecido. Caso isto aconteça, todos os efeitos deste módulo são desfeitos e o sistema está em um estado consistente.
Após a recuperação de erros ter sido realizada, uma nova alternativa é executada e o processo continua até que o resultado de execução de alguma versão seja aceito ou que tenham esgotado todas as alternativas possíveis. Neste caso, uma exceção é levantada indicando que nenhum módulo passou pelo teste de aceitação.
A estrutura básica de um bloco de recuperação é a que segue, onde T é a condição do teste de aceitação que se espera encontrar pela execução com sucesso da rotina primária P ou pela rotina alternativa A. A cláusula erro sinaliza uma exceção caso todas as alternativas falhem.
Embora cada uma das alternativas dentro de um bloco de recuperação busque satisfazer o mesmo teste de aceitação, não há nenhuma exigência de que elas devam produzir os mesmos resultados, dessa forma, os módulos podem diferir. Por exemplo, o primeiro pode ser mais rápido e menos complexo, diminuindo a capacidade da detecção de falhas, ao passo que um segundo módulo pode ser mais minucioso na detecção de falhas, acabando por ser mais lento.
A performance nos casos em que o teste de aceitação é satisfeito no primeiro módulo é a mesma do primeiro mais o tempo para setar o ponto de recuperação e executar o teste de aceitação. Essa técnica tem como vantagens a reprodução de todo um sistema, pode ser proibitivamente cara e poderá ser desejável ter tolerância a falhas para alguns módulos principais, o que pode ser facilmente suportado com recovery block.

### Programação "N-Versões"

Consiste na geração de N-versões de uma aplicação, onde N >= 2, sendo estas aplicações originárias da mesma especificação, mas programadas com ferramentas, linguagens, métodos, equipes e testes diferentes. Essa técnica utiliza um sistema de votação das N-versões para geração do resultado final e, portanto, trabalha com um mascaramento de falhas. A programação N-versões depende de:
* Especificação inicial;
* Independência de esforço;
* Orçamento adequado.
As diferentes versões são executadas paralelamente ou seqüencialmente e os resultados das versões são transmitidos ao votador, responsável por determinar um resultado consensual para a computação de acordo com algum critério. Caso o votador não seja capaz de determinar o resultado, então uma exceção é sinalizada.
A técnica de N-versões requer a consistência de condições iniciais e entradas para todas as computações de N e um algoritmo de decisão (votador) que determina um único resultado de decisão dos resultados múltiplos que são produzidos. Nas versões de N é importante eliminar modos comuns de fracasso:
* usando linguagens diferentes para cada versão;
* usando compiladores diferentes e ambientes de apoio para cada versão;
* usando, se possível, algoritmos diferentes para cada versão;
* utilizando grupos de programadores diferentes e preferencialmente que tenham estudado e aprendido em lugares e de formas diferentes.
Os pontos falhos das diferentes versões não podem estar correlacionados, pois, neste caso, as técnicas de diversidade de projeto não oferecem um grande aumento em confiabilidade como é antecipado. O benefício atual para confiabilidade dependerá de como os fracassos de versões estão correlacionados. Mas, para o desenvolvimento de N-versões de um mesmo programa, encontra-se uma grande dificuldade - o custo de desenvolvimento - que em SW é o fator principal, pois diferentes equipes de programadores, administração de projeto, controle de configuração, versões e instalação de mudanças são fatores que aumentam o custo.
Uma vez que o votador determina um consenso, o resultado produzido é avaliado e retornado para versões errôneas. Estas versões podem retornar para corrigir o estado interno antes da próxima computação.
Na arquitetura geral de um sistema de software N-versão, no qual somente duas versões são usadas, o sistema pode detectar um único erro comparando a saída das duas versões. O método não é usualmente simples para identificar a versão errônea. Sistemas que usam esta configuração geralmente usam uma técnica onde o sistema termina assim que uma diferença seja detectada entre as duas versões. São exigidas três versões independentes para que se chegue a um consenso dos resultados através da maioria.
Característica a blocos de recuperação, a configuração de software de N-versões provê tolerância à falha transparente ao usuário. Assim, um projetista de um sistema pode incorporar tolerância a falhas somente nos módulos críticos. O mecanismo de decisão - votador - em um ambiente de software de N-versões pode ser um único ponto para defeito, então deve ser extremamente confiável.

#### Mecanismo de deadline

Baseada no mecanismo de bloco de recuperação. Este método está associado com aplicações em tempo real e é uma variação da técnica do bloco de recuperação. A estrutura do mecanismo de deadline é:

#### Mecanismo de bloco de recuperação distribuído

Utiliza os mesmos procedimentos de bloco de recuperação, não há diferenças a nível de aplicação. Utilizado para evitar erros transitórios de hardware (teste de aceitação) porque não indica a causa do erro.
Funcionamento: distribuir o bloco principal e as rotinas alternativas em diferentes nodos e executá-los simultaneamente. Se o primário falhar, envia um aviso para o nó back-up, que transmitirá o seu resultado. O estado de erro também pode ser por omissão do envio da mensagem. Se o primário obtiver êxito, ele também envia um aviso para o back-up, que não transmitirá o seu resultado.