Processamento Confiável no Ambiente Operacional Seljuk

Propaganda
Processamento Confiável no
Ambiente Operacional Seljuk-Amoeba
Érica de Lima Gallindo
Francisco Vilar Brasileiro
[email protected]
[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
O sistema operacional distribuído Amoeba não oferece nenhum mecanismo para
tolerância a faltas de processamento. A funcionalidade do seu servidor de
processamento se restringe a um balanceamento de carga dos processadores
disponíveis, identificando aquele que está em melhor condição (e.g.: disponibilidade
de memória, velocidade de CPU, etc) de realizar determinada tarefa. Neste artigo
apresentamos um serviço de processamento confiável para o Amoeba, oferecendo
variados graus de confiabilidade, que podem ser escolhidos pela aplicação em tempo
de ativação. Este serviço é utilizado como base na implementação do ambiente
operacional Seljuk-Amoeba.
ABSTRACT
Processing on the Amoeba distributed operating system is not fault-tolerant. The
only concern of its processing service is to perform load balancing on the available
processors, trying to find the processor that best suits a particular process in terms of
memory availability and CPU speed. In this paper we introduce a fault-tolerant
processing server for the Amoeba system. This server is used in the implementation
of the Seljuk-Amoeba operating environment, which offers processing service with
different failure semantics on a per-process basis.
1. INTRODUÇÃO
Um sistema distribuído é composto por vários elementos computacionais,
interligados por canais de comunicação, usualmente no âmbito de uma rede local. Em tais
sistemas, a profusão de processadores possibilita a distribuição uniforme de tarefas entre
os mesmos, com a finalidade de aumentar o desempenho global do sistema. Também
torna-se possível recuperar as computações que estão executando em processadores que
venham a falhar. Para se conseguir tolerância a faltas, introduz-se redundância, que é
definida como aquela parte não necessária para o funcionamento correto do sistema, se
nenhuma tolerância a faltas é suportada [Jalo94].
Quando a implementação dos mecanismos para tolerância a faltas fica a cargo
da aplicação, a complexidade desta cresce. Em [Bras97] é proposta uma plataforma de
desenvolvimento, denominada Seljuk, que facilita a implementação de aplicações
distribuídas robustas. Uma das abordagens utilizadas pela plataforma é a disponibilização
de serviços que permitem assumir que a aplicação irá executar sobre unidades de
processamento, denominadas de nodos, que falham de forma controlada e previsível. Em
tempo de ativação cada aplicação pode escolher a semântica de falha do serviço de
processamento a ser usado. Quando os processadores sobre os quais o serviço é
implementado, possuem uma semântica de falha menos restritiva do que aquela assumida
pela aplicação, a plataforma implementa os protocolos necessários para garantir a
semântica de falha requerida, liberando as aplicações desta tarefa. Além desses serviços, a
plataforma também oferece outros serviços para tolerância a faltas, que podem ser usados
pelos projetistas de aplicações distribuídas; detalhes sobre esses serviços são relatados em
[VB97].
A semântica de falha de um processador depende, não somente das
características do seu hardware propriamente, mas também, entre outros fatores, dos
requisitos de confia nça no funcionamento 1 exigidos pela aplicação e da duração da sua
execução (tempo de missão). Embora tenha-se conhecimento que processadores
convencionais possam falhar de uma maneira arbitrária [HLD88], a probabilidade desse
tipo de falha ocorrer é tão pequena, que é possível assumir uma semântica de falha
controlada para esses processadores, e ainda assim, atender aos requisitos de
confiabilidade de um grande número de aplicações. Entretanto, existe um número
crescente de aplicações, cujos requisitos de confiança no funcionamento são
suficientemente altos a ponto de, para essas aplicações, não ser possível assumir que
processadores convencionais apresentem semântica de falha controlada. Para estas
aplicações faz-se necessário a construção de nodos que garantam o comportamento
assumido.
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. [Bras95] apresenta protocolos que podem ser usados na
implementação em software de um serviço de processamento com diferentes semânticas
de falha controlada.
Neste trabalho mostraremos a aplicação desse serviço no contexto do ambiente
operacional Seljuk-Amoeba, que é uma implementação da arquitetura Seljuk utilizando o
sistema operacional Amoeba [MRTRS90] como substrato. O Amoeba é um sistema
operacional distribuído baseado na tecnologia de micro-núcleos. O princípio básico desta
tecnologia é minimizar a parte do sistema operacional que executa em modo supervisor (o
micro-núcleo propriamente dito), com o objetivo de aumentar a flexibilidade do sistema.
Todo processador do Amoeba executa um pequeno pedaço de software chamado micronúcleo. Toda a funcionalidade do sistema operacional que não é provida pelo micronúcleo fica a cargo de processos servidores que executam em modo usuário. Um desses
servidores é o Run Server, responsável pela alocação de processadores para a execução de
tarefas. O Run Server não provê qualquer serviço para tolerância a faltas de
processamento.
Nossa proposta é estender a funcionalidade do Run Server, transformando-o em
um servidor de processamento confiável, denominado FT Run Server. O FT Run Server
1
[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, a expressão confiança no funcionamento é usada para traduzir o termo
dependability.
baseia-se nos protocolos para construção de nodos replicados descritos em [Bras95]. As
aplicações executadas pelo FT Run Server podem, em tempo de execução, informar a
semântica de falha assumida para os nodos onde irão executar, bem como a semântica de
falha real dos processadores. O FT Run Server deve então prover, de forma transparente,
a semântica de falha requerida a partir da replicação do processamento em processadores
disponíveis, caso os mesmos tenham uma semântica de falha menos restritiva. Além da
introdução do FT Run Server, é necessário adaptar o serviço de comunicação do Amoeba,
de forma que este implemente as necessidades de comunicação dos protocolos
mencionados anteriormente.
O restante deste artigo é estruturado como segue. A Seção 2 apresenta alguns
conceitos básicos do Amoeba, que são de fundamental importância para o entendimento
da nossa proposta. A Seção 3 descreve o comportamento do servidor de execução do
Amoeba (Run Server). Na Seção 4 é explicado o funcionamento dos nodos com
semântica de falha controlada propostos por [Bras95], enquanto que na Seção 5 será
mostrado como estes nodos serão adaptados para provê o processamento confiável no
ambiente operacional Seljuk-Amoeba. Finalmente, a Seção 6 apresenta as conclusões
deste trabalho.
2. CARACTERÍSTICAS DO AMOEBA
2.1. OBJETOS E CAPABILITIES
Todos os servidores do Amoeba funcionam com base no conceito de objeto, que
é um tipo de dado sobre o qual são realizadas operações bem definidas. Os objetos, no
Amoeba, são gerenciados por servidores específicos. As operações sobre os objetos são
executadas de maneira síncrona, isto é, ao fazer uma chamada de procedimento remoto
(Remote Procedure Call - RPC [BN84]) ao servidor que gerencia o objeto, o cliente fica
bloqueado esperando por uma resposta.
Quando um objeto é criado, o servidor que o gerencia devolve uma capability ao
processo criador. Nas operações subsequentes, para utilizar o objeto, o cliente deverá
apresentar essa capability ao servidor, a fim de identificar o objeto e comprovar a
permissão de manipulá-lo. A capability é uma maneira uniforme de nomear e proteger
todos os objetos do Amoeba. Uma capability consiste em uma estrutura de dados de 128
bits, como mostra a Figura 2.1.
48
Porta do Servidor
24
Objeto
8
Permissões
48
Verificação
Figura 2.1 : Exemplo de uma capability
Na capability, o campo Porta do Servidor é um endereço lógico onde se pode
encontrar o servidor que gerencia o objeto. O segundo campo, Objeto, é usado pelo
servidor para identificar o objeto em questão. Por exemplo, um servidor de arquivos
gerencia diversos arquivos, com o campo Objeto o servidor poderá saber que arquivo em
especial ele está manipulando. Já o campo Permissões informa as operações que o
detentor da capability pode realizar sobre o objeto. Por último, existe o campo
Verificação que serve para validar a capability. Como as capabilities são manipuladas
diretamente por processos do usuário, se não existisse alguma forma de proteção estes
poderiam falsificá-las.
2.2. P ROCESSOS E THREADS
O conceito principal de qualquer sistema operacional é o processo - uma
abstração de um programa em execução. Em muitos sistemas operacionais, como o
UNIX, um processo consiste de um segmento de texto que contém as instruções de
máquinas formando o código executável do programa, um segmento de dados contendo
os dados globais inicializados, um segmento bss que contém os dados globais não
inicializados e um segmento de pilha, todos no mesmo espaço de endereçamento. Além
desses segmentos, outras informações sobre o processo (ex. contexto de execução, tempo
de execução, localização dos segmentos na memória, etc.) são armazenadas em uma
estrutura de dados do sistema operacional, normalmente chamada de tabela de processos.
O processo, nestes sistemas operacionais, tem uma única linha de execução (thread). No
caso do Amoeba um processo pode ter múltiplas threads, todas executando dentro do
mesmo espaço de endereçamento.
O elemento chave dos mecanismos de gerenciamento de processos no Amoeba é
o descritor de processos. Este consiste de quatro partes, como ilustrado na Figura 2.2
abaixo.
cpu
80386
mem
16 Mb
virtual address
length
how
segment 1
segment 2
source
Segment Descriptor
thread 1
program counter
thread 2
stack pointer
process capability
handler capability
system-call state
Thread Descriptor
Figura 2.2: Descritor de Processos
A primeira parte do descritor de processos descreve as propriedades do
processador no qual o processo deve executar. Um processo só pode executar em um
processador que preencha os requisitos indicados no descritor deste processo. Na Figura
2.2, por exemplo, o processo deve ser executado em um processador da arquitetura 386
que tenha pelo menos 16M bytes de memória disponíveis.
A próxima parte descreve o layout - mas não o conteúdo - do espaço de
endereçamento virtual do processo. A memória virtual é segmentada e, para cada
segmento tem-se um descritor de segmentos que contém os campos virtual address,
length, how e source. O campo virtual address indica onde o segmento está mapeado
dentro do espaço de endereçamento; o campo length indica o tamanho do segmento; o
campo how descreve que tipo de acesso o processo tem ao segmento (e.g., leitura,
execução), este campo indica também se o segmento pode crescer e em qual direção; o
campo source contém uma capability para um objeto que provê o conteúdo do segmento
de memória (e.g., um arquivo).
A terceira parte do descritor de processos é o descritor da thread. No Amoeba,
o micro-núcelo gerencia as threads de um processo. Para cada thread o descritor contém:
program counter, stack pointer, o estado das system-calls, e registradores. As únicas
sytem-calls cujos estados necessitam de descrição no descritor da thread são as
bloqueantes.
A última parte do descritor de processos contém duas capabilities necessárias
para gerenciar o processo. A primeira é a capability para o próprio processo; um processo
é visto como um objeto que é gerenciado pelo micro-núcleo do processador no qual ele
executa. Pedidos de operações sobre este objeto (e.g. migrar, suspender, matar) são
enviados à entidade que gerencia o objeto (o micro-núcleo). Assim, quando um processo
é submetido a um processador, o micro-núcleo precisa conhecer a capability usada pelos
pedidos de operações para endereçar o processo. A segunda, é uma capability para o
manipulador de exceções de um processo. Usualmente, este é o processo pai, porém
algumas vezes pode ser um debugger. Quando uma exceção ocorre, o micro-núcleo
constrói um descritor de processos para o processo e envia o descritor que causou a
exceção para o manipulador de exceções.
2.3. C OMUNICAÇÃO ENTRE PROCESSOS
Sistemas operacionais distribuídos são estruturados, tipicamente, em torno do
paradigma cliente-servidor. Neste modelo, um processo chamado de cliente, pede a outro
processo, chamado de servidor, que faça um trabalho para ele. O cliente então fica
bloqueado até que o servidor envie a este uma resposta. O mecanismo de comunicação
usado para implementar o modelo cliente-servidor é o RPC.
Embora o RPC seja uma boa abstração para o tipo de comunicação
pedido/resposta, existe um grande número de aplicações que requer que um grupo de
processos interaja de maneira fechada. Group Communication permite que uma
mensagem seja enviada confiavelmente de 1 remetente para n receptores. Por exemplo,
aplicações podem replicar dados a fim de obter tolerância a faltas. Tal aplicação
necessitará de Group Communication para manter consistente os dados que estão
replicados [BJ87].
No Amoeba encontramos tanto RPC quanto Group Communication. Para dar
suporte ao RPC e Group Communication o Amoeba dispõe de um protocolo de rede
chamado FLIP - Fast Local Internet Protocol [KRST93].
A Figura 2.3 abaixo mostra a organização da comunicação no micro-núcleo do
Amoeba. O micro-núcleo contém duas camadas: uma camada superior que implementa
RPC e Group Communication, e uma camada inferior que implementa o FLIP. Por
exemplo, quando um cliente faz uma chamada trans (primitiva RPC que envia uma
mensagem de um cliente a um servidor e espera por uma resposta), a camada RPC
examina o cabeçalho e o buffer, constrói uma mensagem a partir destes campos, e passa
esta mensagem para a camada de baixo (FLIP), que se encarrega de transmití-la para o
destino.
Cliente
RPC
modo
usuário
GC
Camada FLIP
núcleo
Figura 2.3: Estrutura de comunicação no Amoeba
3. RUN SERVER
Os processos servidores são componentes importantes na configuração do
Amoeba. Entre os processos servidores do Amoeba está o servidor de execução (Run
Server), que é o responsável pelo escalonamento de tarefas. Este não provê nenhum
mecanismo para tolerar faltas de processamento; a sua funcionalidade se resume a um
balanceamento de carga dos processadores. Para este balanceamento leva-se em
consideração fatores como: memória disponível, velocidade do processador, arquitetura
do hardware, fragmentação de memória, entre outros.
O poder computacional do Amoeba está localizado em um ou mais pools de
processadores. Um pool de processadores é formado por um conjunto de CPUs
interligadas através de uma rede. Cada CPU tem sua própria memória local e executa o
micro-núcleo do Amoeba.
Antes de executar um processo, o Run Server tem que decidir em qual tipo de
arquitetura ele deve executar e qual processador deve ser o escolhido. No Amoeba as
tarefas são submetidas ao Run Server através de um interpretador de comandos (shell).
Quando dá-se entrada a um comando pelo shell, este extrai a primeira palavra da linha de
comando, assume que é o nome de um programa executável, procura por este programa
no sistema de arquivos, e se encontrá-lo, faz com que este seja executado.
Antes de solicitar a execução do programa, o shell localiza as arquiteturas para as
quais este programa está disponível. Para localizar as arquiteturas disponíveis, o shell
procura o comando no diretório /bin (diretório onde encontram-se os executáveis no
amoeba). Se o programa estiver disponível para várias arquiteturas, este não será um
arquivo, e sim um diretório contendo os executáveis para cada arquitetura disponível. Em
seguida o shell faz uma RPC ao Run Server enviando a este os descritores de processos,
para todas as arquiteturas disponíveis, do programa em questão, e solicitando ao Run
Server a escolha de uma arquitetura e uma CPU específica para executar o programa.
Para escolher a CPU, o Run Server verifica que arquiteturas dispõe para executar
o programa. Isto é feito verificando o diretório onde localizam-se os vários pools de
processadores, chamado de pooldir (Figura 3.1).
Figura 3.1: Diretório de pools de processadores
A seleção de qual processador usar, é feita da seguinte forma. Em primeiro lugar,
faz-se a interseção dos descritores de processos enviados pelo shell e das arquiteturas
disponíveis no pooldir. Por exemplo, se existem descritores de processos para as
arquiteturas 386, SPARC e 680X0, e no pooldir encontram-se pools de processadores de
arquiteturas 386, SPARC e VAX, somente as arquiteturas 386 e SPARC serão
consideradas.
Em seguida, o Run Server verifica quais das máquinas consideradas tem memória
suficiente para executar o programa, eliminando aquelas que não satisfazem as exigências
do processo. O Run Server mantém-se informado da memória e da CPU usada por cada
um de seus processadores fazendo, regularmente, uma chamada getload a cada um,
requisitando estes valores. Assim os números na tabela do Run Server estão
continuamente atualizados.
Por último, para cada uma das máquinas restantes, faz-se uma estimativa do poder
computacional que está disponível para executar o novo processo. Cada CPU faz sua
própria estimativa. Para esta estimativa leva-se em consideração o poder computacional
da CPU e o número de threads ativas rodando nela. Por exemplo, se uma máquina de 20
MIPS tem quatro threads ativas no momento, a soma de mais uma thread significará que
cada uma, incluindo a nova, terá 4 MIPS em média. Se outro processador tem 10 MIPS e
uma thread ativa, nesta máquina o novo processo poderá ter até 5 MIPS. O Run Server
escolhe então o processador que pode liberar a maior quantidade de MIPS e retorna para
o shell a capability para este processador.
O shell então, faz uma RPC ao servidor de processos do processador escolhido,
enviando a capability fornecida pelo Run Server. Junto com a capability, o shell envia ao
servidor de processos, o descritor de processo da arquitetura escolhida pelo Run Server,
para que o processo possa ser criado. A Figura 3.2 mostra todos os passos envolvidos na
criação de um processo no Amoeba.
RPC
Shell
1
2
4
Run
Server
capability para um
processador
RPC
capability do
processo
pool de
processadores
3
Servidor
de
Processo
Figura 3.2: Fases da criação de um processo no Amoeba.
Com base no funcionamento do Run Server então, apresentaremos um novo
servidor de execução (tolerante a faltas de processamento) que, ao invés de disparar um
pedido de execução de uma instância de uma determinada aplicação, possa solicitar a
execução de várias instâncias desta, dependendo do nível de tolerância a faltas desejado.
As várias cópias dos processos irão interagir, formando assim o nodo que terá a semântica
de falha escolhida pela aplicação em tempo de execução. Antes de discutirmos as
mudanças a serem introduzidas no Run Server, discutiremos na próxima seção a
implementação de nodos replicados com semântica de falha controlada.
4. NODOS COM SEMÂNTICA DE FALHA CONTROLADA
Nodos com semântica de falha controlada podem ser construídos agrupando-se
processadores convencionais que falham de maneira independente. A computação é
replicada e executada simultaneamente em cada um dos processadores formando um
nodo. Os resultados da computação de cada um dos processadores são avaliados por um
mecanismo apropriado que garante a semântica de falha do nodo, evitando que respostas
incorretas, sejam repassadas para o nível da aplicação.
Neste trabalho, usamos os protocolos de tolerância a faltas descritos em
[Bras95]. Esses protocolos foram construídos baseados na arquitetura da família de nodos
Voltan [SESTT92]. Essa família abrange duas classes de nodos com semântica de falha
controlada, a saber: nodos com semântica de falha mascarada (fail-masking nodes) e
nodos com semântica de falha silenciosa (fail-silent nodes). Os nodos com semântica de
falha mascarada possuem uma semântica de falha equivalente à sua semântica
operacional, isto é, o nodo ainda libera seu serviço mesmo na ocorrência de um número
limitado de falhas de seus componentes, que são mascaradas; enquanto que nodos com
semântica de falha silenciosa, possuem uma semântica de falha segura, isto é, depois de
detectada uma falha, estes nodos não liberam nenhuma saída, eles simplesmente param.
Nesse ambiente, assume-se que as aplicações distribuídas não-replicadas são
compostas de um número de processos que não compartilham memória; a interação é
feita somente por troca de mensagens. Considera-se ainda que os processos replicados
comportam-se de maneira determinística [Bras97]; e que toda réplica correta de um
processo recebe as mesmas mensagens, processando-as na mesma ordem.
As mensagens enviadas pelos processos são assinadas, de forma que nenhum
processador incorreto possa falsificar mensagens; os mecanismos de assinaturas digitais
aqui supostos, estão descritos em [FB97]. Supõe-se também que o meio de comunicação,
no qual as mensagens trafegam, é síncrono, isto é, existe um tempo máximo δ para o
processamento e transmissão de mensagens trocadas entre quaisquer dois processos
corretos. [CB97] mostra uma forma de implementar um canal de comunicação síncrono a
partir de redes assíncronas.
Considera-se que os nodos são compostos por N processadores, onde N=2π+1
no caso dos nodos com semântica de falha mascarada e N=π+1 no caso nodos com
semântica de falha silenciosa; e que seus componentes podem sofrer no máximo π faltas
(π>0). A restrição de N=2π+1 e N=π+1 é necessária apenas para que o esquema de
validação funcione corretamente, já que assim, o processadores corretos podem obter uma
maioria, no primeiro caso, e garante-se que pelo menos um processo está correto, no
segundo caso.
Na Figura 4.1 abaixo, é mostrada uma visão geral da arquitetura dos nodos
Voltan. Além dos processos das aplicações (Servidor), cada processador correto de um
nodo executa cinco processos, chamados de Receptor, Transmissor, Ordenador,
Validador e Remetente.
Servidor
PMQ
DMQ
Links
Ordenador
Remetente
Links
Links
RMQ
Sim
deve ser
ordenada?
Não
Validador
ECL
ICL
VMQ
Links
Receptor
Mensagens originadas da rede
Transmissor
Mensagens destinadas à rede
Figura 4.1: Visão de um processador correto executando processos em um nodo Voltan
A função de cada processo é descrita a seguir.
• Remetente: este processo recebe as mensagens produzidas pelo servidor
daquele processador, assina-as e as envia para os outros processadores do nodo
para que possam ser validadas.
• Ordenador: executa um protocolo de ordenação em conjunto com os outros
processadores do nodo. Sua função é construir filas de mensagens para serem
tratadas pelos servidores de todos os processadores corretos do nodo; essas filas
devem conter as mesmas mensagens e na mesma ordem.
• Validator: a função deste processo depende do tipo do nodo. No caso de
nodos de falha mascarada, o processo de validação é feito através de votação. Fazse uma comparação das mensagens assinadas e enviadas por outros processadores
com as que foram geradas localmente. Se a comparação falha, a mensagem é
descartada; caso contrário, a mensagem é contra-assinada. Se na mensagem
existirem π+1 assinaturas, ela é considerada uma mensagem válida. Em seguida,
esta é repassada ao processo Transmissor para entrega à aplicação. Se existirem
menos que π+1 assinaturas na mensagem, ela é enviada para os outros
processadores do nodo que ainda não a assinaram. Já no caso de nodos de falha
silenciosa, o processo Validador comporta-se como um comparador. Este
comparador é semelhante ao Validador, só com a diferença de que ao se detectar
uma falha, ao invés de simplesmente descartar a mensagem recebida, este
Validator pára por completo, como também o processo Remetente.
• Transmissor: este é o processo responsável por enviar as mensagens com π+1
assinaturas para a aplicação destino.
• Receptor: este processo autentica as mensagens recebidas de micro-núcleo
outros processadores do nodo ou de outros nodos, descartando qualquer
mensagem cuja autenticação falhe, ou que seja duplicada. Mensagens autenticada
vindas originárias da rede de comunicação são enviadas para o processo
Ordenador local; mensagens autênticas vindas de outro processador do nodo que
tenham menos que π+1 assinaturas, são enviadas parao processo Validador local.
A comunicação entre dois processos executando no mesmo processador é
realizada através de listas e filas de mensagens. A diferença básica entre listas e filas é
que na lista os processos podem retirar mensagens de qualquer posição, enquanto que na
fila os processos só podem acessar mensagens que estejam no topo da mesma. Na Figura
4.1 são mostradas as seguintes filas e listas:
• RMQ - Received Message Queue: contém mensagens válidas originadas da
rede e autenticadas pelo processo Receptor, prontas para serem ordenadas.
• DMQ - Delivered Message Queue: contém mensagens ordenadas prontas para
serem processadas pelo processo Servidor.
• PMQ - Processed Message Queue: contém mensagens ainda não assinadas
produzidas pelo processo Servidor local. Estas têm que ser validadas pelo
processo Validador, antes de sua transmissão ao seu destino.
• ECL - External Candidate Message List: contém mensagens assinadas e
autenticadas que tenham sido recebidas de outros processadores para validação.
• ICL - Internal Candidate Message List: contém mensagens não assinadas, à
espera de mensagens na lista ECL que coincidam com elas.
• VMQ - Validate Message Queue: contém mensagens com π+1 assinaturas
(válidas) prontas para serem transmitidas através da rede.
5. FT RUN SERVER
O serviço de processamento do Amoeba, assume que o processo que está em
execução, e o processador no qual ele executa, nunca irão falhar. A única preocupação do
Run Server é fazer com que esse processo seja executado no processador que esteja com a
menor carga de processamento no momento. Com o propósito de inserir mecanismos para
tolerância a faltas no serviço de processamento do Amoeba, é necessário fazer com que
um mesmo processo seja executado por mais de um processador ao mesmo tempo. Desta
forma se um dos processadores falhar, outros ainda permanecerão executando réplicas do
referido processo.
No Amoeba pode-se ter processadores heterogêneos. Por este motivo, é possível
obter-se 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 de maneira mostrada na Figura 5.1.
Em sua versão original, o Amoeba só tratava de executáveis para arquiteturas
diferentes. Com as mudanças introduzidas, este agora manipula também várias versões de
um mesmo programa para várias arquiteturas. A figura abaixo mostra um exemplo da
organização atual do diretório onde se encontram os executáveis no 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.
/bin
pd.i80386
versão1
sort
dir
i80386
pd.VAX
versão2
versão3
Figura 5.1: Sistema de arquivos do Seljuk-Amoeba
Vejamos na Figura 5.2 como fica o cenário da criação de um processo, depois de
introduzir-se no serviço de processamento as mudanças necessárias para que este utilize
os mecanismos de nodos com semântica de falha controlada.
RPC
Shell
FT Run
Server
modo
usuário
descritor de
um nodo
RPC
descritor do
nodo
Servidor de
Nodos
SP
processador A
micro-núcleo
Servidor de
Nodos
SP
processador B
nodo de falha controlada
Figura 5.2: Serviço de processamento confiável no Amoeba
Vamos supor que o shell é a aplicação que deseja utilizar o serviço de
processamento confiável. Primeiro ele faz uma RPC com o FT Run Server, através de um
de seus pedidos de execução de um processo (estes serviços são detalhados mais adiante).
Além de uma indicação do código a ser executado e da semântica de falha dos
processadores do sistema, alguns parâmetros adicionais são enviados nesta RPC. 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 shell. 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 shell, é 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 shell 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]). Finalmente, um último
parâmetro a ser adicionado 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 shell executará uma
implementação diferente da mesma aplicação.
Depois de fazer uma RPC com o FT Run Server, enviando todos os parâmetros
necessários à execução da aplicação, o shell fica bloqueado esperando uma resposta. O
FT Run Server então, retorna ao shell um descritor do nodo criado. Este descritor contém
as seguintes informações: o identificador do nodo, uma listas dos processadores
pertencentes a este nodo (o primeiro processador da lista é o coordenador do nodo), e uma
capability para o nodo. Assim, de posse deste descritor de nodo, o shell faz uma RPC
com o servidor de nodos do processador coordenador do nodo, solicitando a criação do
processo (Figura 5.2). O servidor de nodos é um conceito não existente na versão original
do Amoeba. Esta entidade foi introduzida para provê o serviço de criação das réplicas de
um processo. O servidor de nodos do processador coordenador, além de solicitar ao
servidor de processos local que crie o processo, envia o mesmo pedido aos outros
servidores de nodos de todos os processadores pertencentes ao nodo. Os servidores de
nodos dos outros processadores, por sua vez, solicitam aos seus respectivos servidores de
processos a criação das réplicas. Tanto o servidor de nodos, quanto o servidor de
processos, estão contidos no micro-núcleo que executa em toda máquina no Amoeba.
No projeto do FT Run Server, para fazer o controle das réplicas, utilizamos os
mecanismos para implementação de nodos com semântica de falha controlada
apresentados na seção anterior. Na Figura 5.3 a seguir, são mostradas as threads que
devem ser adicionadas ao micro-núcleo do Amoeba, bem como o fluxo de informação
entre estas, para a implementação de um serviço de processamento confiável.
Servidor
PMQ
modo
usuário
DMQ
Links
Ordenador
Remetente
RPCin / GCin
RPCout / GCout
Links
Não o processo
RMQ
Sim
deve ser
ordenada?
Não
ECL
Validador
é replicado?
micro-núcleo
Sim
Sim
Não
Links
ICL
o processo é
replicado?
VMQ
Receptor
Transmissor
FLIP
Mensagens originadas da rede
Mensagens destinadas à rede
Figura 5.3: Réplica implementando o serviço de processamento confiável
Quando uma mensagem chega pelo adaptador de rede do processador, que faz
parte de um nodo replicado, esta é enviada para a thread Receptor que faz a sua
autenticação, descartando as mensagens que sejam duplicadas ou inválidas. Deve-se
considerar o destino da mensagem para decidir se esta deve ser ordenada ou não. Se a
mensagem foi enviada para um processo replicado então ela deve ser ordenada, de forma
que todas as réplicas da aplicação (Servidor) recebam as mesmas mensagens e na mesma
ordem. Caso contrário ela deve ser repassada para a parte do micro-núcleo do sistema
operacional que implementa o recebimento de mensagens nos protocolos de comunicação
de mais alto nível (representados na Figura 5.3 por RPCin/GCin). Outros dois tipos de
mensagens podem ser recebidas pela thread Receptor. Mensagens enviadas pela threads
Ordenador dos outros processadores que formam o nodo replicado, as quais devem ser
repassadas para a thread Ordenador local; e mensagens enviadas pelas threads Validador
dos outros processadores que são entregues à thread Validador para que sejam validadas.
Uma vez que a mensagem tenha chegado à aplicação, esta é processada e
depositada na PMQ. Em seguida, esta mensagem é entregue a thread Remetente. Se a
mensagem é oriunda de um processo replicado, esta é depositada na ICL ficando à espera
de uma mensagem na ECL que coincida com ela. Se a mensagem for proveniente dos
links de comunicação com os outros processadores do nodo, esta é repassada para a parte
do micro-núcleo que implementa a entrega das mensagens nos protocolos de
comunicação de mais alto nível (no caso RPCout/GCout). Em seguida a mensagem é
entregue a thread Transmissor para que este a envie para seu destino.
6. CONCLUSÃO
O serviço de processamento confiável do ambiente operacional Seljuk-Amoeba é
uma importante ferramenta para a construção de aplicações distribuídas robustas, na
medida que ele provê uma redução na complexidade do desenvolvimento destas. O
programador pode fazer suposições mais restritivas quanto à semântica de falha dos
nodos e dessa forma ter a tarefa de implementação dos mecanismos para tolerância a
faltas facilitada. A gerência dos processadores redundantes necessários para garantir a
semântica assumida para o nodo fica a cargo do Seljuk-Amoeba.
Este serviço também oferece a flexibilidade de permitir que a semântica de falha
dos nodos nos quais a aplicação executa seja definida quando a aplicação é ativada. Dessa
forma, se os requisitos de confiança no funcionamento da aplicação mudarem ao longo do
tempo, não há necessidade nem mesmo de recompilação da aplicação, já que o serviço de
processamento confiável está inserido no próprio sistema operacional.
Uma outra vantagem do serviço é que o custo (em termos de perda de
desempenho) do serviço recai apenas sobre aquelas aplicações com requisitos de
confiança no funcionamento.
Vale lembrar que quando a semântica de falha dos processadores disponíveis é
pelo menos tão restritiva quanto a semântica de falha requerida pela aplicação, o FT Run
Server comporta-se de forma semelhante ao Run Server, e não impõe nenhuma perda de
desempenho para a aplicação.
AGRADECIMENTOS
Os autores agradecem o apoio financeiro do CNPq (processos 180.301/94-2 e
300.646/96-8).
REFERÊNCIAS BIBLIOGRÁFICAS
[AST92]
A.S. Tanenbaum, Modern Operating Systems, Prentice-Hall, Amsterdam,
1992, ISBN 0-13-588187-0.
[AST95]
A.S. Tanenbaum, Distributed Operating Systems, Prentice Hall, Amsterdam,
1995, ISBN 0-13-219908-4.
[BJ87]
K.P. Birman e T.A. Joseph, “Reliable Communication in the Presence of
Failures”, ACM Transactions on Computer Systems, Vol. 5, No. 1, pp. 4776, fevereiro 1987.
[BN84]
A.D. Birrell e B.J. Nelson, “Implementing Remote Procedure Calls”, ACM
Transactions on Computer Systems, Vol 5, No. 1, pp. 39-59, fevereiro 1984.
[Bras95]
F.V.Brasileiro, “Constructing Fail-Controlled Nodes for Distributed
Systems”, Tese de Doutorado, University of Newcastle upon Tyne, maio
1995.
[Bras97]
F.V. Brasileiro, “Seljuk: Um Ambiente para Suporte ao Desenvolvimento e à
Execução de Aplicações Distribuídas Robustas”, submetido ao VII Simpósio
de Computadores Tolerantes a Falhas, março de 1997.
[CB97]
V.S. Catão e F.V. Brasileiro, “Serviço de Comunicação Síncrona para Nodos
Replicados”, submetido ao VII Simpósio de Computadores Tolerantes a
Falhas, março de 1997.
[HLD88]
R.E. Harper, J.H. Lala, e J.J. Deyst, “Fault Tolerant Processor Architecture
Overview”, Digest of Papers, FTCS-18, Tokyo, Japan, pp. 252-257, junho
1988.
[KRST93]
M.F. Kaashoek, R. Renesse, H. va Staveren, A.S. Tanembaum, “FLIP: An
Internetwork Protocol
for Supporting Distributed Systems”, ACM
Transactions on Computer Systems, Vol. 11, No. 2, pp. 73-106, fevereiro
1993.
[LV91]
R. de Lemos e P. Verissímo, “Confiança no Funcionamento - Proposta para
uma Terminologia em Português”, Comunicação Pessoal, dezembro de 1991.
[MRTRS90]
S. J. Mullender, G. van Rossum, A. S. Tanenbaum, R. van Renesse, e H. van
Staveren, “Amoeba: A Distributed Operating System for the 1990’s”, IEEE
Computer, Vol. 23, No. 5, pp. 44-53, maio 1990.
[Mull95]
S. J. Mullender, Distributed Systems, Addison-Wesley, ACM Press, 1993,
ISBN 0-201-62427-3.
[PJ94]
Jalote, Pankaj, Fault Tolerance in Distributed Systems, Prentice Hall, New
Jersey, 1994, ISBN 0-13-301367-7.
[SESTT92]
S.K. Shrivastava, P.D. Ezhilchelvan, N.A. Speirs, S. Tao, e 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, maio 1992.
[VB97]
S.R. Vasconcelos e F.V. Brasileiro, “Serviços para Tolerância a Faltas no
Ambiente Operacional Seljuk-Amoeba”, submetido ao VII Simpósio de
Computadores Tolerantes a Falhas, março de 1997.
Download