Seljuk : Um Ambiente para Suporte ao Desenvolvimento e à

Transcrição

Seljuk : Um Ambiente para Suporte ao Desenvolvimento e à
Seljuk1: Um Ambiente para Suporte ao Desenvolvimento e à
Execução de Aplicações Distribuídas Robustas
Francisco Vilar Brasileiro
[email protected]
Universidade Federal da Paraíba - UFPb/Campus II
Centro de Ciências e Tecnologia - CCT
Departamento de Sistemas e Computação - DSC
Laboratório de Sistemas Distribuídos - LSD
Av. Aprígio Veloso, 882
58109-970, Campina Grande, Paraíba
http://www.dsc.ufpb.br/~lsd
RESUMO
Construir aplicações distribuídas que satisfaçam requisitos de confiança no
funcionamento é uma tarefa difícil. A utilização de ferramentas apropriadas e a escolha
da semântica de falha mais restritiva possível para os componentes que formam a infraestrutura de execução da aplicação, são abordagens usualmente seguidas para reduzir
esta complexidade. Neste trabalho apresentamos a arquitetura Seljuk, que utiliza estas
duas abordagens para especificar um ambiente operacional onde aplicações distribuídas
robustas possam ser mais facilmente implementadas e executadas. O artigo apresenta
também o ambiente operacional Seljuk-Amoeba, que é uma implementação do Seljuk
sobre o sistema operacional distribuído Amoeba.
ABSTRACT
Building dependable distributed applications is not an easy task. Designers of such
systems have used two approaches to reduce design complexity: i) the use of appropriate
developing tools; and ii) the choice of the most restrictive possible failure semantics for
the components that form the underlying execution layer. In this paper we present the
Seljuk architecture, which uses these two approaches to specify an operating
environment that facilitates the construction and execution of dependable distributed
applications. The paper also presents an implementation of the architecture based on the
Amoeba distributed operating system, named Seljuk-Amoeba.
1.
INTRODUÇÃO
O nível de desenvolvimento tecnológico alcançado pelas áreas de microprocessadores e
comunicação tem permitido que sistemas distribuídos, compostos por uma coleção de
unidades de processamento conectadas por uma rede de comunicação de alta velocidade,
provejam uma relação custo/desempenho melhor do que aquela oferecida por sistemas
centralizados tradicionais. Em alguns casos, um sistema distribuído pode até suplantar o
desempenho de um mainframe, tornando-se a única solução factível para aplicações que
requerem um altíssimo nível de desempenho. Além disso, algumas aplicações que apresentam
características inerentemente distribuídas (ex. controle de processos industriais,
processamento de transações remotas, trabalho cooperativo, etc.), só podem ser
desenvolvidas, de forma eficaz, dentro do contexto de um sistema distribuído. Finalmente, um
sistema distribuído, desde que projetado com o cuidado necessário, pode potencialmente
1
Durante os séculos X e XI os seljúquios desenvolveram um exército altamente efetivo, responsável,
entre outras conquistas, pela subjulgação da armada Bizantina. Além disso, os seljúquios estabeleceram
um Estado altamente coeso e bem administrado.
oferecer um nível de confiança no funcionamento 2 muito maior do que aquele oferecido por
um sistema centralizado. Estas características são as principais responsáveis pelo acelerado
crescimento no número e na diversidade dos sistemas distribuídos desenvolvidos.
Entretanto, para que uma determinada aplicação distribuída atinja um alto nível de
confiança no funcionamento, falhas isoladas de componentes do sistema no qual ela executa
devem causar o menor impacto possível (ou, idealmente, não causar nenhum impacto) na
operação da aplicação como um todo. Desta forma, a habilidade de tratar e tolerar
efetivamente as faltas 3 que possam vir a ocorrer, é uma característica primordial em um
sistema distribuído.
Quando a implementação dos mecanismos para tolerância a
aplicação, a complexidade desta cresce. De fato, um dos principais
implementação de aplicações distribuídas robustas (aquelas que
consideráveis de confiança no funcionamento) reside justamente na
pela necessidade de se tratar e tolerar faltas [Cris91].
faltas está a cargo da
problemas no projeto e
apresentam requisitos
dificuldade introduzida
A literatura mostra que os projetistas de aplicações distribuídas robustas têm buscado
reduzir a complexidade da construção de tais sistemas, principalmente, através da utilização
de duas abordagens complementares, quais sejam: i) a utilização de ferramentas de apoio
apropriadas para a construção destes sistemas (ex. bibliotecas com funções para tolerância a
faltas [HK93], toolkits de programação [BJ87, SDP91], construções especiais de linguagens
de programação [Maes87], serviços especializados do sistema operacional [Ng90,
MRTRS90], etc.); e ii) a escolha da semântica de falha mais restritiva possível para os
componentes da infra-estrutura de execução [Cris91].
Neste trabalho, descrevemos a arquitetura do ambiente operacional Seljuk, cujo
objetivo principal é facilitar o desenvolvimento e a execução de aplicações distribuídas
robustas. Para tal, o ambiente oferece dois níveis de serviços: i) serviços de alto nível que
implementam ou auxiliam a implementação dos principais mecanismos para tolerância a
faltas requeridos por aplicações distribuídas robustas; e ii) serviços de um nível mais baixo,
que permitem restringir a semântica de falha dos componentes que formam a infra-estrutura
sobre a qual a aplicação irá executar.
Uma das características mais importantes do Seljuk é a sua flexibilidade, que
possibilita a coexistência de aplicações distribuídas com diferentes requisitos de confiança no
funcionamento, num mesmo sistema distribuído, mas pagando apenas por aqueles serviços
para tolerância a faltas por elas requisitados. Além disso, o ambiente também permite que os
requisitos de confiança no funcionamento das aplicações e a semântica de falha dos
componentes que formam a infra-estrutura de execução, sejam definidos no momento da
ativação das mesmas. Isso possibilita, entre outras coisas, o balanceamento entre as medidas
de desempenho e de confiança no funcionamento que se deseja alcançar para as aplicações,
em tempo de ativação, e sem a necessidade de qualquer mudança no código executável
destas.
O restante deste artigo é estruturado da seguinte forma. Na Seção 2 serão discutidas as
abordagens usuais utilizadas na construção de aplicações distribuídas robustas. A Seção 3
apresenta o modelo utilizado para descrever a arquitetura e os pressupostos assumidos. A
arquitetura Seljuk é detalhada na Seção 4, onde serão estudados os serviços que devem ser
providos pelo ambiente. A Seção 5 é dedicada à apresentação do Seljuk-Amoeba, uma
instanciação da arquitetura, baseada no micro-núcleo distribuído Amoeba [MRTRS90].
Encerra o artigo a Seção 6 que traz as nossas conclusões e direções futuras do trabalho.
2
[LV91] propõe uma terminologia em Português que mapeia aquela sugerida por Laprie em seu
conhecido artigo [Lapr89]. No artigo de Lemos e Veríssimo, o termo confiança no funcionamento é
usado para traduzir o termo dependability.
3
Ainda seguindo a terminologia proposta em [LV91], usaremos os termos falta, erro e falha como
respectivas traduções dos termos fault, error e failure.
2.
CONSTRUINDO APLICAÇÕES DISTRIBUÍDAS ROBUSTAS
Como mencionado anteriormente, a complexidade da construção de uma aplicação
distribuída robusta pode ser reduzida através da utilização de ferramentas apropriadas e da
escolha da semântica de falha mais restritiva possível para a infra-estrutura de execução da
aplicação. Nesta seção discutiremos como estas estratégias têm sido usadas em sistemas
apresentados na literatura.
2.1.
Ferramentas para Construção de Aplicações Distribuídas Robustas
Os primeiros sistemas tolerantes a faltas construídos eram soluções ad-hoc para
problemas específicos (ex. [HSL78, W*78, Lala86]). Com o crescimento do número de
aplicações com requisitos de confiança no funcionamento, surge a necessidade de se produzir
ferramentas que possibilitem que estes sistemas possam ser construídos com o reaproveitamento do esforço desprendido na construção de outros sistemas com características
similares. A seguir discutimos algumas ferramentas apresentadas na literatura que têm sido
usadas para tal fim.
Bibliotecas de Funções para Tolerância a Faltas
Uma forma de se promover re-usabilidade de software é através da utilização de
bibliotecas de funções. Com pouco esforço de programação, é possível utilizar mecanismos
para tolerância a faltas que já tenham sido usados (e, principalmente, testados) em outras
aplicações. Um exemplo desta tecnologia é discutido em [HK93]. Naquele artigo, os autores
apresentam vários exemplos de utilização das funções da biblioteca libft, para construir
aplicações tolerantes a faltas.
A biblioteca contém funções para especificar e realizar checkpoint de dados críticos da
aplicação, recuperar a informação de checkpoints, atualizar diário de eventos (logs), localizar
e reconectar servidores, realizar tratamento de situações excepcionais [Cris91], além de
prover suporte para programação diversificada [Aviz85] e uso de blocos de recuperação
[Rand75]. Por exemplo, a função critical() pode ser usada para especificar dados
críticos da aplicação que devem fazer parte de um checkpoint que, por sua vez, pode ser salvo
através da ativação da função checkpoint().
Construções Especiais de Linguagens de Programação
A consolidação do paradigma de orientação a objetos para o desenvolvimento de
sistemas de software fez emergir um outro tipo de ferramenta - os toolkits de programação. A
idéia aqui é usar os mecanismos de herança das linguagens de programação orientadas a
objetos, para disponibilizar classes de objetos que implementam mecanismos para tolerância a
faltas. Estes mecanismos podem então ser usados pela aplicação, através da utilização de subclasses derivadas daquelas classes providas pelo toolkit.
O sistema Arjuna [SDP91] é um exemplo deste tipo de ferramenta. O modelo
computacional do Arjuna baseia-se na utilização do conceito de transações atômicas
aninhadas, que controlam as operações realizadas sobre objetos persistentes, para a
construção de aplicações distribuídas robustas. A complexidade do tratamento da distribuição,
da consistência, e da persistência dos objetos que implementam a aplicação é escondida do
programador pela infra-estrutura provida pelo Arjuna.
Além da reutilização de componentes inerente ao modelo de orientação a objetos,
recentemente o conceito de reflexão computacional [Maes87] também tem sido explorado
para auxiliar a construção de aplicações distribuídas robustas. De uma forma simplificada, a
idéia é dividir o sistema em uma parte funcional (objetos da aplicação) e outra de controle e
gerência (meta-objetos). Em [LC95] esta técnica é utilizada para prover tolerância a faltas de
software.
Serviços Especializados de Sistemas Operacionais Distribuídos
A necessidade de desenvolver aplicações distribuídas que tolerem faltas que possam
afetar a infra-estrutura de execução destas aplicações tem influenciado o projeto dos sistemas
operacionais modernos, notadamente dos sistemas operacionais distribuídos. A maior parte
destes sistemas implementa serviços de comunicação com variável grau de confiabilidade (ex.
[CZ83, MRTRS90, Rozi92]). Outros vão além e oferecem serviços de processamento
confiável [Ng90].
No sistema ROSE [Ng90] um serviço de detecção de falhas é provido pelo núcleo do
sistema. Um processo pode usar este serviço para detectar a falha de um outro processo,
possivelmente executando em um outro processador do sistema distribuído. Além deste
serviço, o sistema também oferece um serviço de replicação de espaço de endereçamento, que
permite a replicação de dados em processadores diferentes. Com base nestes dois serviços, o
sistema possibilita a execução de processos usando tanto replicação ativa como passiva
[Powe92].
2.2.
Impondo Restrições à Semântica de Falhas dos Componentes
A complexidade dos mecanismos para tolerância a faltas reflete as considerações feitas
sobre a semântica de falha dos componentes do sistema, necessários para a execução destes
mecanismos [Cris91], ou seja, as considerações feitas sobre que tipo de falha os componentes
poderão apresentar. Quanto mais restritiva a semântica de falha de tais componentes, mais
simples será a implementação dos mecanismos. Levando-se esta consideração ao extremo, se
os componentes nunca falham (semântica de falha mais restritiva possível), não há
necessidade de adicionar à aplicação qualquer mecanismo para tolerância a faltas.
Uma abordagem tomada pelos projetistas de um considerável número de sistemas
distribuídos apresentados na literatura (ex. [Bart81, KM85, BJ87, Ng90, MRTRS90, SDP91,
Powe92]), é desenvolver os sistemas assumindo que os processadores e canais de
comunicação que compõem a infra-estrutura sobre a qual estes serão construídos, possuem
uma semântica de falha controlada (fail-controlled [Lapr89]), ou seja, apresentam uma
semântica de falha bem definida e previsível.
Muitos sistemas tolerantes a faltas descritos na literatura, foram construídos assumindo
que eles executam em unidades de processamento - doravante denominadas de nodos - que
falham de forma segura (fail-safe nodes) [Lapr89], ou seja, o nodo quando falha, pára, ao
invés de realizar uma transição não especificada. Dois tipos de nodos representativos desta
classe de nodos com semântica de falha segura são os nodos com semântica de falha estável
(fail-stop ou fail-stable nodes) [Schn84, Bras95] e os nodos com semântica de falha silenciosa
(fail-silent nodes) [Bern88, WB91, SESTT92, RS93, BESST96]. Outros sistemas assumem
que os nodos nunca falham, desta forma eles devem executar em nodos que possam garantir
este comportamento por toda a duração da execução da aplicação (tempo de missão). Nodos
que mascaram falhas (failure-masking nodes) [HSL78, W*78, S*78, Lala86, Theu86,
SESTT92, Powe92, STBES93, BES95b] formam uma outra classe de nodos, que são capazes
de oferecer um serviço correto, com uma probabilidade arbitrariamente alta.
Quando a infra-estrutura disponível não pode prover, com probabilidade
suficientemente alta, a semântica de falha assumida, faz-se necessário construir nodos, que,
de fato, apresentem a semântica de falha requerida.
2.2.1. Construindo Nodos com Semântica de Falha Controlada
Nodos com semântica de falha controlada podem ser construídos através do
agrupamento de processadores convencionais redundantes, que falham de maneira
independente, e de forma arbitrária (falhas Bizantinas). A computação é replicada e executada
simultaneamente em cada um dos processadores formando o nodo. Os resultados da
computação de cada um dos processadores são validados por um mecanismo apropriado (ex.
comparação, votação majoritária, etc.), que garante a semântica de falha do nodo.
A maioria dos nodos com semântica de falha controlada apresentados na literatura são
implementados em hardware [HSL78, Lala86, Bern88, WB91]. Os processadores formando o
nodo são sincronizados a cada ciclo de relógio, e a cada ciclo os resultados das operações de
cada um dos processadores são validados por um circuito que implementa a semântica de
falha do nodo. A principal vantagem desta abordagem é a reduzida perda de desempenho
introduzida pelos circuitos especiais. Entretanto, existem alguns problemas: primeiro, os
processadores precisam ser construídos de tal maneira que eles tenham um comportamento
determinista em cada ciclo de relógio; segundo, a introdução de circuitos especiais aumenta a
complexidade do projeto, o que, em última instância, pode reduzir a confiabilidade do nodo
como um todo; terceiro, é difícil incorporar avanços tecnológicos, sem que seja necessário um
considerável esforço de (re)projeto do nodo; quarto, este tipo de abordagem não tolera faltas
de projeto nos processadores; finalmente, o fato de se ter os mecanismos para tolerância a
faltas fisicamente incorporados ao nodo, implica na forçosa distribuição do custo associado a
estes mecanismos por todas as aplicações executando no nodo, inclusive por aquelas que não
necessitam de serviços para tolerância a faltas [Bras95].
Em contraposição à abordagem baseada em hardware, foi proposta uma abordagem
baseada em software [W*78], que tenta resolver a maior parte dos problemas citados acima.
Nesta abordagem, os protocolos necessários para sincronizar os processadores redundantes do
nodo e validar o resultado das operações realizadas por estes processadores, garantindo então
a semântica de falha do nodo, são implementados em software. Esta abordagem é muito mais
flexível do que a anterior, permitindo inclusive a utilização de diferentes tipos de
processadores (design diversity) em um mesmo nodo, o que possibilita o tratamento de faltas
de projeto na construção dos processadores. Além disso, a atualização tecnológica destes
nodos é trivial, pois os protocolos implementados em software precisam apenas ser
recompilados para a nova plataforma. Por outro lado, o principal problema da abordagem de
software é a possibilidade de uma queda acentuada no desempenho do sistema.
[Bras95] apresenta uma forma eficiente de construir diversos tipos de nodos com
semântica de falha controlada, implementados em software, e identifica classes de aplicações
para as quais a redução de desempenho do sistema, devido aos mecanismos para tolerância a
faltas, é bastante reduzida.
3.
MODELO E PRESSUPOSTOS
3.1.
Componentes da Arquitetura
Uma arquitetura pode ser descrita em função dos seus componentes e das relações de
dependência entre estes componentes [Cris91]. Um componente implementa um conjunto de
operações que podem ser ativadas através de requisições explícitas por parte dos usuários do
componente ou simplesmente através da passagem do tempo. Os componentes de um sistema
podem ser implementados em hardware ou em software.
O conjunto de operações implementadas pelo componente especifica o serviço por ele
oferecido. Por exemplo, o serviço oferecido por um interpretador Java [Flan96] consiste do
processamento de todas as operações definidas pelo byte-code da linguagem. Por sua vez,
para fornecer o seu serviço, o interpretador Java utiliza os serviços oferecidos por outros
componentes do sistema (ex. os serviços de alocação de memória e escalonamento de
processos de um sistema operacional, o serviço de processamento de um processador, etc.).
Podemos definir uma relação de dependência entre os componentes de um sistema, da
seguinte forma: um componente A depende de um outro componente B, quando a corretude
do comportamento de A depende da corretude do comportamento de B. Por exemplo,
componentes implementados em software dependem dos serviços de processamento
oferecidos pelo sistema operacional (criação e escalonamento de processos, gerência de
memória, etc.). Estes, por sua vez, dependem do serviço de processamento oferecido por um
processador.
Dentro do contexto do nosso trabalho, uma aplicação distribuída é implementada por
uma coleção de componentes (tipicamente processos) que se comunicam exclusivamente
através da troca de mensagens. Os componentes da aplicação dependem dos serviços
oferecidos pelos outros componentes do ambiente operacional para proverem o serviço da
aplicação.
Os componentes das aplicações podem apresentar comportamento determinístico ou
não. Quando o comportamento apresentado por um determinado componente é não
determinístico, nem todos os serviços oferecidos pelo ambiente operacional poderão ser
usados. Adiante discutiremos detalhadamente quais as restrições que se aplicam a
componentes com este tipo de comportamento, e como os componentes da aplicação podem
ser construídos para, mesmo apresentando comportamento não determinístico, poderem fazer
uso de todos os serviços oferecidos pelo Seljuk.
3.2.
Faltas e Semântica de Falhas
O comportamento de um componente após a ativação de uma de suas operações pode
ser observado através das mudanças internas de seu estado e dos resultados emitidos por ele.
A especificação do componente define, para todas as possíveis ativações do componente,
quais as mudanças do seu estado interno e quais os resultados que ele deve emitir. O
comportamento de um componente é correto quando está de acordo com a sua especificação.
Faltas no sistema podem fazer com que um componente execute uma transição
diferente daquela definida pela sua especificação e desta forma falhe. As faltas que podem
ocorrer em um sistema podem ser divididas em dois grandes grupos: i) faltas físicas, ou seja,
aquelas geradas por fenômenos físicos internos ao sistema; e ii) faltas humanas, as quais
englobam faltas de projeto - quer seja de hardware ou de software - cometidas durante a fase
de construção do sistema, e faltas de interação, que são violações dos procedimentos de
operação e manutenção do sistema [SS92]. Dentro do escopo deste trabalho, o nosso interesse
será principalmente na tolerância a faltas físicas e faltas de projeto de hardware e de software.
Para que se possa tolerar os efeitos causados por uma falta em um componente é
importante conhecer os possíveis comportamentos faltosos que o componente pode exibir, ou
seja, qual é a sua semântica de falha. Considere um cliente c que envia uma requisição de
serviço rs para um servidor s, através de um canal de comunicação cc, e que o atraso máximo
na transmissão de rs de c para s através de cc é a. Se o projetista assume uma semântica de
falha por omissão para cc, ou seja a probabilidade de cc atrasar ou corromper uma mensagem
é desprezível, então pode-se usar um mecanismo simples baseado em time-outs para detectar
a falha no envio de rs por c ou na resposta a rs por s. Para tolerar faltas em cc, basta que c reenvie rs, sempre que a resposta a rs não for recebida dentro de um período de 2a unidades de
tempo após o envio de rs por c. Note que se a semântica de falha de cc fosse outra,
mecanismos diferentes teriam que ser utilizados para tolerar possíveis faltas [Cris91].
O que se percebe da discussão acima é que a semântica de falha de um componente
deve ser escolhida pelo projetista do sistema, a quem cabe julgar o que se constitui uma
probabilidade de ocorrência desprezível para um dado comportamento. Em outras palavras, o
projetista é responsável pela identificação de quando é justificável assumir que a
probabilidade de um determinado comportamento ocorrer é tão pequena que pode-se
desprezar a sua ocorrência.
Portanto, a semântica de falha de um componente depende não somente das
características do componente propriamente, mas também, entre outros fatores, do tempo de
missão e dos requisitos de confiança no funcionamento exigidos pela aplicação que o usa.
Tomando processadores como exemplo, embora se tenha conhecimento que processadores
convencionais possam falhar de uma maneira arbitrária [Lala86, HLD88], a probabilidade
deste tipo de falha ocorrer é tão pequena, que é possível assumir uma semântica de falha
controlada para estes processadores, e ainda assim, atender aos requisitos de confiabilidade de
um grande número de aplicações. Existe, entretanto, um número crescente de aplicações,
cujos requisitos de confiabilidade são suficientemente altos a ponto de, para estas aplicações,
não ser possível assumir que processadores convencionais apresentam semântica de falha
controlada.
No Seljuk a semântica de falha dos componentes de hardware (processadores e canais
de comunicação) e de software é escolhida no momento da ativação da aplicação, dentro de
um leque de opções que contemplam desde a semântica de falha arbitrária (menos restritiva
possível) até a semântica de falha silenciosa (mais restritiva possível). Quando a semântica de
falha escolhida para os componentes de software é mais restritiva do que aquela escolhida
para os componentes de hardware, o ambiente operacional, desde que haja recursos
suficientes, se encarrega de implementar a semântica de falha requerida para os componentes
de software, através da replicação e gerência dos componentes de hardware disponíveis.
Quando os recursos são insuficientes para atender ao serviço de processamento ou
comunicação com a semântica de falha requerida pelo componente requisitante, o serviço é
negado.
4.
A ARQUITETURA DO AMBIENTE OPERACIONAL S ELJUK
A execução de uma aplicação distribuída robusta no ambiente operacional Seljuk
utiliza basicamente três serviços distintos: i) o serviço de processamento, que é responsável
pela execução das instruções dos componentes da aplicação em nodos (possivelmente
replicados); ii) o serviço de comunicação, que provê os mecanismos necessários para que dois
ou mais componentes possam trocar mensagens de forma confiável; e iii) o serviço de
gerência da redundância, que implementa os protocolos que garantem os requisitos de
confiança no funcionamento requisitados pela aplicação.
Os componentes do Seljuk podem ser acomodados em 4 camadas distintas, conforme
ilustrado na Figura 1 abaixo.
Aplicações
Middleware
Sistema Operacional Distribuído
Processadores e Canais de Comunicação
Figura 1: estrutura em camadas do ambiente operacional Seljuk
As três camadas superiores da estrutura apresentada na Figura 1 são formadas por
componentes implementados em software. Já a camada inferior é formada por componentes
implementados em hardware; destes, destacaremos com maior ênfase os processadores e os
canais de comunicação.
Os componentes que formam as duas camadas inferiores são responsáveis pela
implementação dos serviços de processamento e de comunicação. A camada intermediária
denominada de middleware, por sua vez, utiliza os serviços oferecidos pelas camadas
inferiores para implementar os serviços de gerência da redundância necessários para
implementar os mecanismos para tolerância a faltas usados pelos componentes das
aplicações. Por fim, na camada superior ficam os componentes que implementam o serviço da
aplicação.
A estrutura apresentada acima explicita as relações de dependência entre os principais
componentes da arquitetura. Vê-se que além dos serviços normalmente oferecidos por um
ambiente operacional tradicional, o ambiente operacional Seljuk oferece serviços de
processamento e comunicação confiáveis, e sobre estes, serviços especializados para
tolerância a faltas. Como será visto mais adiante, estes serviços são oferecidos de forma
flexível e com ônus apenas para aquelas aplicações que se utilizam deles.
Sistemas operacionais distribuídos baseados em micro-núcleos parecem ser o tipo de
tecnologia capaz de implementar tais serviços. O princípio básico da tecnologia de micro-
núcleos é minimizar o tamanho da parte do sistema operacional que executa em modo
supervisor (o micro-núcleo propriamente dito) com o objetivo de aumentar a flexibilidade do
sistema. Toda a funcionalidade do sistema operacional que não é provida pelo micro-núcleo
fica a cargo de processos servidores que executam em modo usuário. Desta forma, os serviços
providos por estes servidores podem ser modificados/adaptados/configurados muito mais
facilmente, atendendo às diferentes exigências das aplicações. Esta é essencialmente uma
forma de dividir, de uma maneira elegante, mecanismos de políticas. Uma quantidade mínima
de mecanismos básicos é implementada pelo micro-núcleo que executa em modo supervisor,
enquanto que a política de gerência dos recursos do sistema é implementada pelos servidores
executando em modo usuário.
Na realidade, dado a importância que a comunicação entre processos tem nestes
sistemas, a maioria dos micro-núcleos distribuídos descritos na literatura [CZ83, MRTRS90,
Rozi92], oferece um serviço de comunicação com algum grau de confiabilidade. No entanto,
serviços de processamento confiáveis são praticamente inexistentes. Nossa abordagem, além
de introduzir estes serviços, agrega novos serviços para tolerância a faltas àqueles
tradicionalmente fornecidos por micro-núcleos distribuídos, de forma a possibilitar a
concepção de plataformas de desenvolvimento que ofereçam os serviços mencionados acima.
4.1.
Serviço de Processamento Confiável
Os micro-núcleos distribuídos existentes praticamente não possuem serviços de
processamento confiável, ou seja, o processamento nestes sistemas é, no máximo, tão
confiável quanto os nodos nos quais ele é executado.
Os protocolos desenvolvidos em [Bras95] podem ser usados para implementar a
execução replicada de processos, e assim prover um serviço de processamento confiável para
os componentes das aplicações que requisitarem tal serviço. Em [Bras95], os protocolos são
implementados por uma coleção de funções pertencentes a uma biblioteca, que são ligadas ao
código da aplicação. A aplicação deve então ser executada no número de processadores
necessários para garantir o grau de confiança no funcionamento requerido. Grande parte da
gerência dos mecanismos para tolerância a faltas está a cargo do programador, o que, além de
ser trabalhoso, é susceptível à introdução de faltas de projeto. A arquitetura Seljuk elimina
estes problemas introduzindo no micro-núcleo de um sistema operacional distribuído os
mecanismos que tornam o serviço de processamento confiável transparente para as
aplicações.
O processamento confiável no Seljuk é obtido através de replicação ativa dos
componentes da aplicação em processadores independentes; cada processador do nodo
replicado executa uma coleção de threads do núcleo que gerem a redundância do nodo
(detalhes são apresentados em [Bras95] e [GB97]). Entre as operações executadas por estas
threads podemos destacar a ordenação das mensagens que são entregues às réplicas dos
componentes da aplicação, que garante que todas as réplicas corretas processem as mesmas
mensagens na mesma ordem, e a validação das mensagens produzidas pelas réplicas, que em
última instância vai definir a semântica de falha do nodo.
A ordenação das mensagens entregues às réplicas por si só não garante o correto
funcionamento da replicação ativa. O potencial comportamento não determinístico das
réplicas pode levar à divergência de estados entre as várias réplicas de um determinado
componente. É preciso, portanto, evitar, ou pelo menos controlar, possíveis comportamentos
não determinísticos das réplicas. O comportamento não determinístico de uma réplica pode
ser conseqüência de duas situações: i) não determinismo de componentes do sistema
operacional (ex. tratamento de eventos assíncronos); e ii) processamento não deterministico
da aplicação (ex. cálculo feito a partir dos dados lidos de um sensor).
O comportamento não determinístico do sistema operacional pode ser decorrente de
uma chamada síncrona ao sistema que tem um comportamento não determinístico (ex. uma
chamada do tipo gettimeofday() que retorna a hora do sistema no momento da sua
ativação) e portanto pode retornar valores diferentes para as várias réplicas de um
componente; ou de um evento assíncrono (ex. fim de um time-out, recepção de um sinal, etc.)
que pode ser tratado em diferentes pontos da execução das réplicas e em conseqüência
produzir diferentes resultados.
Estes problemas são resolvidos no Seljuk da seguinte forma. Todas as chamadas
síncronas ao sistema que tenham comportamento não determinístico devem ser modificadas,
de forma que antes de retornar o valor calculado à aplicação, primeiro o valor calculado é
enviado às outras réplicas do componente através de mensagens; estas mensagens serão
ordenadas normalmente pelo mecanismo de ordenação que implementa o nodo replicado, e
desta forma apenas um dos valores calculados será utilizado por todas as réplicas (aquele
calculado pela réplica que conseguiu ordenar seu valor em primeiro lugar); os outros valores
calculados serão descartados como duplicatas de uma mensagem já recebida pelo nodo. Note
que um mecanismo similar pode ser usado pelas componentes das aplicações que tenham um
comportamento não determinístico, permitindo que estes possam ser replicados ativamente, e
portanto possam utilizar todos os serviços oferecidos pelo Seljuk, sem quaisquer restrições.
No caso dos eventos assíncronos, basta transformar estes eventos em mensagens
especiais, e enviar estas mensagens para as outras réplicas do nodo. Os handlers destes
eventos são implementados na forma de threads que bloqueiam a espera de uma mensagem
sinalizando o evento correspondente. Novamente, o mecanismo de ordenação do nodo garante
que os mesmos eventos serão tratados no mesmo ponto de execução por todas as réplicas. Um
seqüenciador de eventos é usado para possibilitar o descarte de eventos duplicados, já
tratados.
4.2.
Serviço de Comunicação Confiável
Do ponto de vista da comunicação, existem basicamente três tipos de falhas possíveis:
perda ou atraso de mensagens; duplicação de mensagens; e corrupção do conteúdo das
mensagens. Muitos sistemas oferecem um serviço de comunicação sujeito a todos os tipos de
falhas citados acima. Nestes sistemas, aplicações com requisitos de confiança no
funcionamento devem implementar protocolos que garantam que estas falhas sejam toleradas.
Outros sistemas oferecem serviços de comunicação um pouco mais confiáveis, com detecção
de duplicatas e de mensagens corrompidas, sobre o qual outros serviços de comunicação mais
sofisticados podem ser mais facilmente implementados. Entre estes serviços mais sofisticados
destacam-se as chamadas de procedimento remotos (RPC) [BN84] e os serviços de
comunicação em grupo [BJ87].
Um outro fator que aumenta a complexidade dos serviços de comunicação diz respeito
à ordem na qual as mensagens recebidas por um nodo são entregues às aplicações executando
naquele nodo. O serviço de ordenação mais simples de ser implementado é aquele que garante
ordenação fifo (first-in-first-out) das mensagens trocadas por um par de processos. Outros
serviços de comunicação que atendem requisitos de ordenação de mensagens mais
sofisticados incluem os serviços de disseminação com preservação de causalidade (causal and
total order multicast) [BJ87] e os serviços de disseminação atômica (atomic broadcast)
[BES95a, BE95].
A arquitetura Seljuk prevê a disponibilização de todos os serviços discutidos acima. A
oferta de uma grande quantidade de serviços de comunicação, com variado grau de
confiabilidade, proporciona uma maior flexibilidade para o desenvolvedor, deixando a cargo
deste escolher o serviço mais apropriado, levando em consideração fatores como o
desempenho e a redução da complexidade de desenvolvimento alcançados, quando um
determinado serviço é utilizado.
4.3.
Serviços para Tolerância a Faltas
Existe um considerável número de protocolos desenvolvidos com o intuito de
possibilitar a implementação de serviços para tolerância a faltas. A principal diferença entre
estes protocolos reside nas considerações feitas sobre a semântica de falha de nodos e canais
de comunicação, e no grau de confiabilidade que se deseja alcançar.
Tolerância a faltas a nível de processamento é normalmente alcançada através da
replicação do processamento em um número N de nodos, onde N é uma função do número f
de falhas que se quer tolerar e da semântica de falha dos nodos. Há basicamente dois tipos de
replicação: ativa e passiva [Powe92].
Na replicação ativa, os processos que implementam a aplicação distribuída são
executados simultaneamente em todos os N nodos. Se os nodos possuem semântica de falha
segura, é necessário apenas que N seja maior que f, para que f faltas sejam toleradas; por outro
lado, se os nodos possuem semântica de falha arbitrária, então N deve ser pelo menos maior
que 2f (assumindo que os nodos são capazes de assinar mensagens). No primeiro caso, o
resultado da computação será o primeiro resultado produzido por qualquer uma das réplicas;
já no segundo caso, faz-se necessário submeter os resultados produzidos pelas réplicas a uma
votação majoritária, que mascare os resultados produzidos por replicas executando em nodos
que falharem. Para que a replicação ativa funcione é fundamental que as réplicas executem a
mesma seqüência de comandos, evitando assim divergência nos seus estados internos. Para
tal, as réplicas devem executar um algoritmo determinista, e devem receber a mesma
seqüência de mensagens de entrada.
Na replicação passiva, apenas uma réplica dos processos, a primária, executa. As outras
réplicas, as secundárias, simplesmente mantêm informações sobre o progresso da réplica
primária. De tempos em tempos a réplica primária envia informações (checkpoints) às
réplicas secundárias, informando sobre o seu progresso. Se a réplica primária falha, e portanto
deixa de enviar um checkpoint, uma nova réplica primária é escolhida entre as réplicas
secundárias e o processamento é continuado com base nas informações recebidas no último
checkpoint. Replicação passiva só é possível se os nodos apresentam semântica de falha
segura e, neste caso, para se tolerar f faltas, é suficiente que N seja maior que f. Como só uma
réplica executa em cada instante, não há necessidade dos algoritmos dos processos que
implementam a aplicação serem deterministas.
Outros serviços importantes são o diagnóstico e a recuperação de nodos que falham. O
diagnóstico destes nodos é feito dentro do contexto de um grupo de nodos que se relacionam
de alguma forma (ex. implementam um serviço de forma conjunta). Um serviço de
diagnóstico completo deve permitir que todos os nodos que falharam no grupo sejam
diagnosticados e que todos os nodos corretos do grupo concordem sobre quais nodos
falharam. Quando a semântica de falha dos nodos é segura, este diagnóstico pode ser
alcançado de maneira razoavelmente simples. Por outro lado, se os nodos podem falhar de
forma arbitrária, não se conhece nenhum protocolo que possa garantir um diagnóstico
completo. Nestes casos, entretanto, é possível se implementar um serviço de diagnóstico
parcial [SR87]. Nodos cuja falha tenha sido diagnosticada devem ser isolados ou substituídos
por nodos corretos.
A exclusão dos nodos que falham durante o tempo de missão de uma aplicação vai,
paulatinamente, degradando os serviços para tolerância a faltas usados pela aplicação.
Quando o tempo de missão da aplicação não pode ser predeterminado ou é muito longo, fazse necessário reconfigurar o sistema de tempos em tempos, introduzindo outros nodos que
possam assumir a carga de processamento dos nodos que falharam e, desta forma renovar o
nível de tolerância a faltas dos serviços. Os nodos adicionados podem ser nodos suplentes ou
os próprios nodos que falharam, desde que seja possível recuperá-los e colocá-los novamente
em operação.
No Seljuk, os serviços apresentados acima, são colocados à disposição das aplicações
na forma de chamadas ao sistema, de processos servidores, e de forma transparente como os
serviço de processamento discutido anteriormente (na próxima seção daremos mais detalhes
sobre a forma como estes serviços são oferecidos em uma plataforma específica).
5.
SELJUK-AMOEBA
Dentre os micro-núcleos apresentados na literatura, o Amoeba [MRTRS90], destaca-se
pela sua penetração na comunidade científica e pela grande quantidade de informação
disponível. Por estes motivos, o Amoeba foi escolhido como sistema hospedeiro para a nossa
primeira implementação de um ambiente operacional Seljuk, o qual chamamos de SeljukAmoeba. Os detalhes da especificação deste ambiente são relatados em [VB97], [GB97],
[CB97] e [FB97]; aqui nos limitaremos a apresentar um resumo dos serviços oferecidos pelo
ambiente.
5.1.
Serviços de Processamento no Seljuk-Amoeba
O serviço de processamento confiável do Seljuk-Amoeba é oferecido por um servidor
chamado de FT Run Server. Para usar o serviço, primeiro um processo faz uma RPC com o
FT Run Server. Um dos parâmetros contidos nesta chamada é a semântica de falha do nodo.
Ao disparar a aplicação, pode-se escolher qual a semântica de falha assumida para o nodo
onde ela executará; as semânticas de falha possíveis são a semântica de falha silenciosa e a
semântica de falha mascarada. O fator de replicação também é passado pelo processo. Este
fator é um valor numérico que informa ao FT Run Server quantos processadores
independentes formarão o nodo. Um outro parâmetro fornecido pelo processo, é uma lista
contendo quais os processadores que não se deseja utilizar na execução daquela aplicação
(este parâmetro pode ser utilizado, por exemplo, se o projetista da aplicação achar que o
processador de uma determinada arquitetura não é confiável, e não desejar submeter nenhuma
tarefa a este; pode acontecer também, do processo disparar duas aplicações e necessitar que
estas executem em conjuntos de processadores distintos, por exemplo, para implementar uma
replicação de mais alto nível [VB97]). Dois outros parâmetros passados na RPC são um
objeto contendo o código a ser executado e a semântica de falha que deve ser assumida para
os processadores do sistemas. Finalmente, um último parâmetro a ser passado na RPC é uma
variável que sinaliza se a aplicação será executada com diversidade de projeto ou não. Com
isto, pode-se conseguir tolerância a faltas de projeto de software, já que cada réplica disparada
pelo processo executará uma implementação diferente da mesma aplicação. Detalhes sobre as
ações que são executados pelo Seljuk-Amoeba quando um processo utiliza o serviço do FT
Run Server podem ser vistos em [GB97].
No Amoeba pode-se ter processadores heterogêneos. Por este motivo, é possível obterse tolerância a faltas a nível de projeto de hardware quando o mesmo processo é replicado em
vários processadores de arquiteturas diferentes. Para permitir também tolerância a faltas de
projeto de software, a organização dos binários no Amoeba foi adaptada da maneira mostrada
na Figura 2 abaixo.
/bin
pd.i80386
versão1
sort
dir
i80386
pd.VAX
versão2
versão3
Figura 2: Sistema de arquivos do Seljuk-Amoeba
Em sua versão original, o Amoeba só trata de executáveis para arquiteturas diferentes.
O Seljuk-Amoeba manipula também várias versões de um mesmo programa para várias
arquiteturas. A Figura 2 mostra um exemplo da organização atual do diretório onde se
encontram os executáveis no Seljuk-Amoeba (/bin). Nesta figura, o /bin contém dois
comandos: dir e sort. O comando dir está disponível apenas para a arquitetura VAX; o
comando sort por sua vez, encontra-se disponível na arquitetura 80386 além de conter outras
n implementações dele disponíveis para a mesma arquitetura. Esta diversidade de
implementações do mesmo programa, permite que o projetista opte pela execução da
aplicação em nodos replicados, de forma que cada réplica do nodo execute uma versão
diferente do programa. Note que com a diversidade de arquiteturas de processadores e com a
disponibilidade de n versões para cada uma destas arquiteturas, aumenta-se o grau de
tolerância a faltas para esta aplicação.
5.2.
Serviços de Comunicação no Seljuk-Amoeba
O sistema de comunicação do Amoeba é implementado no núcleo em duas camadas. A
camada inferior implementa o Fast Local Internet Protocol (FLIP), que é um protocolo que
opera em modo datagrama, não orientado à conexão. Comunicação confiável é fornecida pelo
Amoeba pelos dois serviços da camada superior - comunicação em grupo e RPC (Remote
Procedure Call), que utilizam o serviço não confiável fornecido pelo FLIP para enviar
mensagens.
Portanto, o Amoeba já oferece primitivas para comunicação um-a-um confiável, além
de primitivas para comunicação em grupo que provêem entrega atômica de mensagens a
todos os membros do grupo, mesmo na presença de falhas dos canais de comunicação e,
opcionalmente, dos processadores. Ou seja, a comunicação em grupo do Amoeba garante
entrega confiável e ordenada de mensagens a todos os membros corretos do grupo.
Alguns serviços do Seljuk-Amoeba, entretanto, necessitam de serviços de comunicação
em grupo que não são atendidos pelo Amoeba, fazendo-se necessário incrementar o conjunto
de primitivas oferecidas. As primitivas a serem acrescentadas pelo Seljuk-Amoeba deverão
ser flexíveis, permitindo que se possa balancear desempenho contra requisitos de tolerância a
faltas. Três novas primitivas que podem ser ativadas por um processo que não faz parte de um
grupo são necessárias: CreateRepGroup(), que permite a criação de um grupo de réplicas;
JoinRepGroup() que permite que novos membros sejam adicionados a um grupo criado por
CreateRepGroup(); e ResetRepGroup(), que permite a inicialização do processo de
recuperação do grupo.
5.3.
Serviços para Tolerância a Faltas no Seljuk-Amoeba
O serviço de replicação de processamento no Seljuk-Amoeba é oferecido por um
servidor de replicação - o RepServer - implementado na camada middleware da arquitetura
Seljuk. A fim de criar um componente de software replicado, a seguinte invocação é feita ao
RepServer, através de uma RPC:
Replicate(file, rep-degree, failure-semantics)
Esta chamada solicita ao RepServer a criação de um processo replicado para executar o
código contido em file. O grau de replicação (isto é, o número de réplicas a serem criadas) é
determinado por rep-degree e a semântica de falha real considerada para os processadores do
sistema é definida em failure-semantics.
Se a semântica de falha definida para os processadores é menos restritiva do que a
semântica de falha silenciosa (que é a exigida por esta implementação do RepServer), ao
receber tal pedido, o RepServer deve requisitar ao FT Run Server, também via RPC, a criação
de rep-degree nodos com semântica de falha silenciosa.
Além da primitiva para criação de um grupo de réplicas, o Seljuk-Amoeba
disponibiliza uma biblioteca de funções que podem ser usadas para facilitar a implementação
de aplicações replicadas de forma passiva. Essas funções executam tarefas relacionadas com a
eleição de réplicas primárias, manutenção de checkpoints e controle de logs de mensagens
recebidas e enviadas pelas réplicas [VB97].
Finalmente, os mecanismos de detecção e reconfiguração do sistema são definidos pela
aplicação no momento da sua ativação e são executados de forma transparente pelo ambiente
operacional, utilizando as primitivas adicionais de manipulação de grupos
(CreateRepGroup(); JoinRepGroup() e ResetRepGroup()).
6.
CONCLUSÕES E TRABALHOS FUTUROS
Construir aplicações distribuídas capazes de tolerar a ocorrência de faltas é uma tarefa
difícil. Acreditamos que a plataforma de desenvolvimento proposta neste projeto possibilitará
uma sensível redução na complexidade de desenvolvimento destas aplicações. Este
sentimento se baseia nas seguintes considerações:
i) as aplicações poderão escolher a semântica de falha dos nodos onde executarão sem a
preocupação de implementar qualquer mecanismo que garanta esta semântica - isso
será feito de forma transparente pela plataforma. Além disso, já que esta escolha é feita
em tempo de ativação, este serviço também oferece uma maior flexibilidade para as
aplicações, que podem a qualquer momento mudar as considerações feitas sobre a
semântica de falha dos nodos, e/ou dos processadores do sistema, sem que seja
necessário qualquer modificação no código executável da aplicação; e
ii) a plataforma oferece um número de serviços para tolerância a faltas que poderão ser
usados de várias formas no desenvolvimento de novas aplicações, facilitando a
implementação destas.
Poucos sistemas tolerantes a faltas descritos na literatura têm a habilidade de tolerar
faltas arbitrárias de seus componentes. Os que existem são normalmente voltados à solução
de problemas bastante específicos. A maioria dos sistemas tolerantes a faltas assume uma
semântica de falha bastante restritiva para os seus componentes (principalmente unidades de
processamento). A plataforma descrita neste artigo implementa nodos com diversas
semânticas de falha controlada. Tais nodos são implementados a partir dos processadores
disponíveis no sistema, cuja semântica de falha é especificada por cada aplicação, quando esta
é ativada. Portanto, a plataforma é capaz de tolerar falhas arbitrárias nos processadores.
Todos os serviços para tolerância a faltas oferecidos pela plataforma, são
implementados inteiramente em software, sem a necessidade de qualquer componente de
hardware especial. Esta característica possibilita a utilização de diversidade de projeto, tanto
no hardware, quanto no software, para tolerância a faltas de projeto do hardware e do
software.
Finalmente, embora diversos protocolos tenham sido desenvolvidos para possibilitar a
construção de uma variedade de mecanismos para tolerância a faltas em sistemas distribuídos,
a maneira de integrar estes mecanismos no sentido de garantir o provimento dos requisitos de
confiança no funcionamento de aplicações distribuídas ainda não é clara. A flexibilidade
oferecida pela plataforma de desenvolvimento Seljuk será útil na avaliação dos custos desta
integração.
Atualmente estamos iniciando a implementação do ambiente Seljuk-Amoeba. No
futuro pretendemos desenvolver várias aplicações distribuídas com diferentes requisitos de
confiabilidade, para podermos avaliar melhor o potencial, bem como as limitações, do
ambiente.
Agradecimentos
O autor agradece o apoio financeiro do CNPq (processo 300.646/96-8).
Referências
[Aviz85]
A. Avizienis, “The N-Version Approach to Fault Tolerant Software,” IEEE Transaction
on Software Engineering, Vol. 11, N. 12, pp. 1491-1501, December 1985.
[Bart81]
J.F. Bartlett, “A NonStop Kernel,” ACM 8th Symposium on Operating Systems
Principles, Pacific Grove, USA, Vol. 15, No. 5, pp. 22-29, December 1981.
[Bern88]
P.A. Bernstein, “Sequoia: A Fault-Tolerant Tightly Coupled Multiprocessor for
Transaction Processing,” IEEE Computer, Vol. 21, No. 2, pp. 37-45, February 1988.
[BJ87]
K.P. Birman and T.A. Joseph, “Reliable Communication in the Presence of Failures,”
ACM Transactions on Computer Systems, Vol. 5, No. 1, pp. 47-76, February 1987.
[BN84]
A.D. Birrell and B.J. Nelson, “Implementing Remote Procedure Calls,” ACM
Transactions on Computer Systems, Vol. 2, N. 1, pp. 39-59, February 84.
[Bras95]
F.V. Brasileiro, “A Software Approach to the Construction of Fail-Controlled Nodes for
Distributed Systems,” Anais do VI Simpósio de Computadores Tolerantes a Falhas,
Canela, Brasil, pp. 385-404, agosto de 1995.
[BES95a]
F.V. Brasileiro, P.D. Ezhilchelvan, and N.A. Speirs, “Authenticated Agreement
Protocols without Explicit Clock Synchronisation,” Proceedings of the European
Research Seminar on Advances in Distributed Systems, France, pp. 151-157, April 1995.
[BES95b]
F.V. Brasileiro, P.D. Ezhilchelvan, and N.A. Speirs, “TMR Processing without Explicit
Clock Synchronisation,” Proceedings of the 14th Symposium on Reliable Distributed
Systems, Germany, pp. 186-195, September 1995.
[BE95]
F.V. Brasileiro e P.D. Ezhilchelvan, “Atomic Broadcast Using Time-outs instead of
Synchronised Time,” Anais do VI Simpósio de Computadores Tolerantes a Falhas,
Canela, Brasil, pp. 223-238, agosto de 1995.
[BESST96] F.V. Brasileiro, P.D. Ezhilchelvan, S.K. Shrivastava, N.A. Speirs, and S. Tao, “Efficient
Protocols for Fail-Silent Nodes in Distributed Systems,” IEEE Transactions on
Computers, Vol. 45, N. 11, pp. 1226-1238, November 1996.
[CB97]
V.S. Catão e F.V. Brasileiro, “Serviço de Comunicação Síncrona para Nodos
Replicados,” Anais do VII Simpósio de Computadores Tolerantes a Falhas, Campina
Grande, Brasil, julho de 1997.
[CZ83]
D.R. Cheriton and W. Zwaenpoel, “The Distributed V Kernel and its Performance for
Diskless Workstations,” Operating Systems Review, Vol. 17, N. 5, pp. 129-140, May
1983.
[Cris91]
F. Cristian, “Understanding Fault-Tolerant Distributed Systems,” Communications of the
ACM, Vol. 34, N. 2, pp. 56-78, February 1991.
[FB97]
R.M. Faria e F.V. Brasileiro, “Serviço de Assinatura Digital para Nodos Replicados,”
submetido ao VII Simpósio de Computadores Tolerantes a Falhas, fevereiro de 1997.
[Flan96]
D. Flanagan, Java in a Nutshell, O’Reilley&Associates, Inc., USA, 1996, ISBN 1-56592183-6.
[GB97]
E.L. Gallindo e F.V. Brasileiro, “Processamento Confiável no Ambiente Operacional
Seljuk-Amoeba,” Anais do VII Simpósio de Computadores Tolerantes a Falhas,
Campina Grande, Brasil, julho de 1997.
[HLD88]
R.E. Harper, J.H. Lala, and J.J. Deyst, “Fault Tolerant Processor Architecture
Overview,” Digest of Papers, FTCS-18, Tokyo, Japan, pp. 252-257, June 1988.
[HSL78]
A.L. Hopkins, T.B. Smith, and J.H. Lala, “FTMP - A Highly Reliable Fault-Tolerant
Multiprocessor for Aircraft,” Proceedings of the IEEE, Vol. 66, No. 10, pp. 1221-1239,
October 1978.
[HK93]
Y. Huang and C. Kintala, “Software Implemented Fault Tolerance: Technologies and
Experience,” Digest of Papers, FTCS-23, Toulose, France, pp. 2-9, 1993.
[KM85]
H. Kopetz, and W. Merker., “The Architecture of MARS,” Digest of Papers, FTCS-15,
Ann Arbor, USA, pp. 274-279, June 1985.
[Lala86]
J.H. Lala, “A Byzantine Resilient Fault Tolerant Computer for Nuclear Power Plant
Applications,” Digest of papers, FTCS-16, Vienna, Austria, pp. 338-343, July 1986.
[Lapr89]
J-C. Laprie, “Dependability: a Unifying Concept for Reliable Computing and Fault
Tolerance,” in Dependability of Resilient Computers, T. Anderson (Ed.), BSP
Professional Books, 1989, ISBN 0-632-02054-7.
[LV91]
R. de Lemos e Paulo Veríssimo, “Confiança no Funcionamento - Proposta para uma
Terminologia em Português,” comunicação pessoal, dezembro de 1991.
[LC95]
M.L.B. Lisbôa e G.G.H. Cavalheiro, “Reflexão Computacional sobre Técnicas de
Tolerância a Falhas em Software,” Anais do VI Simpósio de Computadores Tolerantes a
Falhas, Canela, RS, pp. 405-416, agôsto de 1995.
[Maes87]
P. Maes, “Concepts and Experiments in Computational Reflexion,” Proceedings of
OOPLAS’87, ACM SIGPLAN Notices, Vol. 22, N. 12, pp. 147-155, October 1987.
[MRTRS90] S.J. Mullender, G. van Rossum, A.S. Tanembaum, R. van Renesse, and H. van Staveren,
“Amoeba: A Distributed Operating System for the 1990's,” IEEE Computer, Vol. 23, No.
5, pp. 44-53, May 1990.
[Ng90]
T.P. Ng, “The Design and Implementation of a Reliable Distributed Operating System ROSE,” Proceedings of IEEE ICDCS, pp. 2-11, 1990.
[Powe92]
D. Powell (Ed.), Delta-4 - A Generic Architecture for Dependable Distributed
Computing, Spring-Verlag, 1992, ISBN 3-540-54985-4.
[Rand75]
B. Randell, “System Structure for Software Fault Tolerance,” IEEE Transactions on
Software Engineering, Vol. 1, N. 2, pp. 220-232, June 1975.
[RS93]
J. Reisinger, and A. Steininger, “The Design of a Fail-Silent Processing Node for the
Predictable Hard Real-Time System MARS,” IEE Distributed System Engineering, Vol.
1, No. 2, pp. 104-111, December 1993.
[Rozi92]
M. Rozier, “Chorus,” Proceedings of USENIX Workshop on Microkernels and other
Kernel Architectures, USENIX Association, 1992.
[Schn84]
F.B. Schneider, “Byzantine Generals in Action: Implementing Fail-Stop Processors,”
ACM Transactions on Computer Systems, Vol. 2, No. 2, pp. 145-154, May 1984.
[SR87]
K.G. Shin, and P. Ramanathan, “Diagnosis of Processors with Byzantine Faults in a
Distributed Computing System,” Digest of Papers, FTCS-17, Pittsburgh, USA, pp. 5560, June 1987.
[SDP91]
S.K. Shrivastava, G.N. Dixon and G.D. Parrington, “An Overview of the Arjuna: A
Proggraming System for Reliable Distributed Computing,” IEEE Software, Vol. 8, No. 1.
Pp. 63-73, January 1991.
[SESTT92] S.K. Shrivastava, P.D. Ezhilchelvan, N.A. Speirs, S. Tao, and A. Tully, “Principal
Features of the VOLTAN Family of Reliable Node Architectures for Distributed
Systems,” IEEE Transactions on Computers, Vol. 41, No. 5, pp. 452-549, May 1992.
[S*78]
D. Siewiorek et al., “A Case Study of C.mmp, Cm*, and C.vmp: Part I - Experiences
with Fault Tolerance in Multiprocessor Systems,” Proceedings of the IEEE, Vol. 66, No.
10, pp. 1178-1199, October 1978.
[SS92]
D.P. Siewiorek, and R.S. Swarz, Reliable Computer Systems: Design and Evaluation
(second edition), Digital Press, USA, 1992, ISBN 0-13-772021-1.
[STBES93] N.A. Speirs, S. Tao, F.V. Brasileiro, P.D. Ezhilchelvan and S.K. Shrivastava, “The
Design and Implementation of VOLTAN Fault-Tolerant Nodes for Distributed Systems,”
Transputer Communications, Vol. 1, No. 2, pp. 93-109, November 1993.
[Theu86]
N. Theuretzbacher, “`VOTRICS': Voting Triple Modular Computing System,” Digest of
Papers, FTCS-16, Vienna, Austria, pp. 144-150, July 1986.
[VB97]
S.R.A. Vasconcelos e F.V. Brasileiro, “Serviços para Tolerância a Faltas no Ambiente
Operacional Seljuk-Amoeba,” Anais do VII Simpósio de Computadores Tolerantes a
Falhas, Campina Grande, Brasil, fevereiro de 1997.
[WB91]
S. Webber, and J. Beirne, “The Stratus Architecture,” Digest of Papers, FTCS-21,
Montréal, Canada, pp. 79-85, June 1991.
[W*78]
J.H. Wensley et al., “SIFT: Design and Analysis of a Fault-Tolerant Computer for
Aircraft Control,” Proceedings of the IEEE, Vol. 66, No. 10, pp. 1240-1255, October
1978.

Documentos relacionados

Processamento Confiável no Amoeba

Processamento Confiável no Amoeba desta cresce. De fato, um dos principais problemas no projeto e implementação de aplicações distribuídas, reside justamente na dificuldade introduzida pela necessidade de se tratar e tolerar falhas...

Leia mais