Anda di halaman 1dari 12

O Sistema Mozart para Programacao

Distribuda
Fabio Mascarenhas
4 de julho de 2005

Introduc
ao

A programacao de sistemas distribudos e geralmente feita usando-se uma


linguagem para programacao centralizada mais bibliotecas que acrescentam
distribuicao, como bibliotecas para troca de mensagens entre os nos do sistema ou para chamada remota de metodos/procedimentos. Bibliotecas com
um grau maior de sofisticacao normalmente sao chamadas de middlewares.
Em comum a todos esses casos esta o fato da linguagem permanecer inalterada. De fato, algumas bibliotecas podem ser usadas por programas de
diversas linguagens. Exemplos dessa abordagem sao a programacao de sockets TCP/IP, os espacos de tuplas e os middlewares orientados a mensagens
(MOM).
Outra abordagem para a programacao de sistemas distribudos e extender
uma linguagem centralizada, adicionando comportamento distribudo a seus
elementos. Uma caracerstica comum e fazer que a distribuicao seja transparente ao programador: a forma de se usar um elemento e a mesma, seja
ele centralizado ou distribudo. A meta e facilitar a programacao de sistemas
distribudos, tornando-a similar `a programacao de sistemas concorrentes na
linguagem escolhida (similar para o programador, nao na implementacao
subjacente).
O sistema Mozart e um exemplo dessa segunda abordagem. Ele extende
a linguagem Oz, permitindo que um programa Oz concorrente se torne distribudo com mudancas mnimas no seu codigo. A linguagem Oz tem suporte
a diversos paradigmas de programacao e concorrencia, e Mozart extende isso
com suporte a diversos paradigmas de distribuicao, podendo simular troca de
mensagens, chamadas remotas e mobilidade de codigo. A visao dos autores de
Mozart e a de que um sistema de programacao distribuda e a implementacao
de uma linguagem distribuda.
1

Essa monografia faz uma apresentacao do sistema Mozart, baseada na tese


de doutorado de um dos autores do sistema [4]. Primeiro apresento o n
ucleo
do sistema, a linguagem para programacao concorrente Oz, e seus principais
elementos. Na secao seguinte, apresento como o sistema Mozart acrescenta
distribuicao a esses elementos, descrevendo tanto o seu comportamento no
sistema quanto o protocolo que implementa este comportamento, em linhas
gerais. Finalmente, apresento uma analise do sistema Mozart em comparacao
com outros sistemas para programacao distribuda, tanto integrados quanto
baseados em bibliotecas.

A Linguagem Oz

Oz [1] e uma linguagem que reune caractersticas imperativas (o modelo de


computacao sao threads executando instrucoes em sequencia, e as instrucoes
podem ter efeitos colaterais), funcionais (funcoes, todos os elementos da linguagem sao first-class, escopo lexico) e orientadas a objeto (um sistema de
classes com heranca m
ultipla). Ela e dinamicamente tipada, e e interpretada
por uma maquina virtual.
As variaveis em Oz so podem ter um u
nico valor atribudo a elas; quando
sao declaradas seu valor e desconhecido, e apos a primeira atribuicao o valor
nao pode ser mudado. Qualquer instrucao que precise do valor de uma
variavel que ainda nao foi inicializada bloqueia a thread que a esta executando. Esse e o mecanismo basico da linguagem para sincronizacao e
comunicacao entre threads. Valores mutaveis sao representados por celulas,
que associam um nome a uma variavel, e a variavel associada ao nome pode
ser mudada livremente (e a mudanca e uma operacao atomica).
Um exemplo de como as variaveis de Oz sao usadas para sincronizacao
esta no trecho abaixo, que declara uma variavel X, dispara uma thread que
ira usar essa variavel de depois chama uma funcao para calcular o seu valor.
Quando a thread consumidora usar X ela bloqueara ate que algum valor seja
associado a X:
local X in
thread {Consumer X} end
{Producer X}
end
O trecho a seguir mostra como se usam as celulas, e suas operacoes primitivas (criacao, leitura, troca atomica):
local C X1 X2 X3 in
2

{NewCell foo C}
{Exchange C X1 bar}
{Exchange C X2 foo|bar}
{Access C X3}
end
A segunda linha do exemplo cria uma nova celula C, e atribui o valor foo
a ela (um atomo, uma string imutavel e u
nica no sistema). A linha seguinte
atribui o valor bar `a celula, e faz a variavel X1 assumir o valor anterior
(foo). A quarta linha faz uma nova atribuicao `a celula. Agora ela tem a
lista foo|bar como valor, e a variavel X2 assume o valor bar. Finalmente, a
u
ltima linha faz X3 assumir o valor corrente da celula.
Os outros elementos de Oz sao definidos em funcao desses elementos
basicos (variaveis e celulas), embora sua implementacao nao seja feita dessa
maneira, por razoes de eficiencia. Objetos sao uma funcao com apenas um
parametro, a mensagem (chamada de metodo) para esse objeto. A closure do
objeto faz referencia a celulas que guardam o estado do objeto. Os metodos
sao procedimentos que recebem uma referencia para o estado do objeto e a
mensagem. Classes sao um registro (um dos tipos imutaveis de Oz) contendo
a tabela de metodos e atributos, usados para construir o objeto.
A linguagem tem syntactic sugar para facilitar a criacao e uso de classes
e objetos, como mostrado no trecho a seguir:
class Counter
attr i
meth init i <- 0 end
meth inc i <- @i + 1 end
meth get(X) X = @i end
end
Obj = {New Counter init}
{Obj inc}
{Print {Obj get($)})
Outro elemento derivado sao as travas reentrantes, usadas para exclusao
m
utua. Elas tambem sao funcoes de um parametro, mas recebem uma funcao
sem parametros que define a secao crtica. A trava e reentrante pois uma
thread que possui a trava pode chama-la novamente sem problemas. Internamente (em sua closure) a funcao da trava mantem uma estrutura uma celula
a qual ela atribui uma variavel indefinida antes de entrar na secao crtica,
e espera ate o valor antigo dela ficar definido (a celula e inicializada com
3

um valor definido e u
nico). Saindo da secao crtica ela define a variavel que
associou anteriormente `a celula, liberando a proxima thread da sequencia.
Portas, canais assncronos para troca de mensagens entre threads, sao
mais um elemento da linguagem Oz. Uma porta encapsula uma lista cuja
cauda e uma variavel nao definida. Mandar uma mensagem para a porta
define essa variavel e aumenta a lista com mais uma variavel nao definida.
Ler a porta e ler a cauda da lista, o que faz a thread bloquear ate chegar
uma nova mensagem.

Acrescentando Distribui
c
ao a Oz

Valores (n
umeros, registros, listas, funcoes), variaveis e celulas sao as entidades basicas da linguagem Oz, com outras entidades como objetos, travas
e portas sendo compostas a partir destas entidades basicas. Mozart, portanto, acrescenta distribuicao `a linguagem Oz definindo o comportamento
distribudo de cada uma dessas entidades basicas. Cada uma das tres tem
um comportamento especfico, e um protocolo que o implementa.
Valores tem o protocolo mais simples: como sao imutaveis, sao copiados
toda vez que passam de um no a outro, e nao ha necessidade de nenhum
protocolo para manter a sua consistencia. O comportamento distribudo
das threads tambem e simples: elas nao podem ser transmitidas de um no
para o outro (a mobilidade de codigo em Mozart se restringe a funcoes). O
comportamento distribudo das outras entidades do sistema, e os protocolos
que o iplementam, sao o topico das proximas secoes.

3.1

Vari
aveis

Uma variavel em Oz tem dois estados bem distintos: ou nao esta definida,
e aguardando uma atribuicao que a defina, ou ja foi definida e nao pode
mais ser mudada. Na primeira vez que uma variavel nao definida e passada
para outro no, o sistema Mozart cria um manager para a variavel nesse
no, e substitui a referencia pra variavel por uma referencia para um proxy,
que por sua vez referencia o manager. Outro proxy e criado no no destino,
tambem com uma referencia para o manager. O sistema cria um novo proxy
sempre que uma variavel nao definida chega a um novo no, e todos os proxies
referenciam o mesmo manager.
A Figura 1 mostra o caso em que uma variavel nao definida foi mandada
para outros dois nos, e o protocolo que acontece quando o no 2 faz uma
atribuicao a ela. Essa atribuicao e enviada para o manager, que a aprova
e manda o novo valor da variavel para todos os nos. Isso nao e mostrado
4

No 1

No 2
3

P
1
2
3
4

2
3

No 3

4
Thread faz a atribuiao e bloqueia
Proxy envia atribuiao para o manager
Manager autoriza atribuiao e envia o valor para os proxies
Proxy passa o valor para a thread, que reinicia
Figura 1: Atribuicao a uma variavel

na figura, mas depois que um no recebe o valor da variavel ele descarta o


proxy, ja que a variavel nao pode mais ser mudada. A partir desse momento
a variavel tem o mesmo comportamento distribudo de um valor.

3.2

C
elulas e Objetos

Uma celula pode mudar de valor diversas vezes, e todos os nos que a referenciam devem ter uma visao consistente do valor atual da celula. Uma maneira
de se implementar esse comportamento seria manter o valor da celula em um
u
nico no, e fazer que todos os outros nos acessem a celula atraves dele. Isso
e basicamente o que Mozart faz, com uma mudanca: uma operacao de troca
de valor faz a celula migrar do no onde esta para o no que esta efetuando
a troca. A razao para isso e uma aposta de que o no que esta fazendo a
mudanca fara outras operacoes na celula em breve, e essas operacoes serao
mais rapidas se a celula estiver armazenada localmente.
Como uma variavel, uma celula sendo exportada pela primeira vez para
outro no faz o sistema Mozart criar um manager no no de origem, e substituir
as referencias diretas pra celula por referencias para proxies. O proxy do no
onde a celula esta tem uma referencia para ela. A partir da, exportar a
celula para outros nos implica na criacao de novos proxies para ela, em cada
um dos nos. Todos esses proxies tem uma referencia para o manager.
As Figuras 2 a 4 mostram o progresso de uma operacao de troca do
valor de uma celula. A Figura 2 mostra a situacao antes da execucao do
protocolo. Um pedido de troca feito pela thread T faz com o que o proxy
P c2 mande uma mensagem ao manager M c pedindo o valor de celula. O
5

Pc1

{Exhange C X Y}

Mc

Pc2

Valor 1

Valor 2

Figura 2: Uma celula referenciada por dois sites

(a) Get

(b) Forward
Pc1

Mc
(c) Transfer

Valor 1

Pc2

Valor 2

Figura 3: O protocolo de transferencia de estado

Pc1

Mc

Pc2

Valor 1

Valor 2

Valor 1 X

Figura 4: O estado da celula passou para outro no


manager repassa essa mensagem ao dono atual da celula, o proxy P c1, e
ele entao manda o valor para o novo no da celula. Isso esta mostrado na
Figura 3. A Figura 4 mostra o resultado final do protocolo, com o novo dono
da celula sendo o proxy P c2. Como todas as transacoes envolvendo a celula
passam pelo manager, a consistencia global das operacoes e garantida.
O comportamento distribudo dos objetos e uma consequencia do comportamento de suas partes. Um objeto Oz tem partes imutaveis, como a
classe, e uma celula que contem os atributos do objeto. Quando um objeto
e transferido entre nos, as partes imutaveis sao copiadas para o novo no,
e um proxy e criado para a celula. Operacoes no objeto fazem a celula se
mover para o no que executou a operacao. Por padrao, os objetos no sistema
Mozart sao moveis, e suas operacoes sao executadas localmente.
Mozart tambem tem suporte a objetos estacionarios, com operacoes executadas remotamente. A implementacao usa portas e uma thread que encapsula o objeto e fica em um loop lendo mensagens de uma porta e as
repassando ao objeto. A chamada remota e feita postando uma mensagem
nessa porta. A chamada remota retorna valores atraves de variaveis remotas.

Coleta de Lixo

Managers e proxies sao criados automaticamente toda vez que uma variavel
ou celula e referenciada remotamente. O sistema precisa ter uma maneira de
detectar quando as referencias remotas nao estao sendo mais usadas, para
que os proxies e managers sejam apagados e o as variaveis e celulas voltem a
ser apenas locais.
A deteccao e feita atraves de um algoritmo de contagem de referencias, em
que cada entidade ganha um dado n
umero de creditos quando fica disponvel
para outros nos. Os creditos sao distribudos entre os nos que a recebem,
7

e esses nos por sua vez distribuem parte dos creditos que receberam para
outros nos, quando repassam as entidades. Quando uma entidade e coletada
pelo coletor de lixo local, os creditos sao mandados de volta para o no onde
a entidade foi criada. Quando esse no recebe todos os creditos de volta e
porque a entidade nao tem mais referencias remotas, e o manager e coletado.
Se a entidade for exportada de novo outros managers e proxies sao criados,
independente dos anteriores.
Como todo mecanismo de contagem de referencia, esse mecanismo nao
funciona no caso de referencias cclicas entre celulas de diferentes nos. Nesse
caso o controle tem que ser feito pelo proprio programador, quebrando o ciclo
quando quiser que as celulas sejam coletadas.

Outras Quest
oes

O estabelecimento das conexoes iniciais entre nos e feito por meio de tquetes.
Um tquete e uma representacao textual de uma referencia remota. Eles podem ser um-pra-um, validos apenas para uma conexao, ou um-para-muitos.
Uma vez que um no consegue ma referencia para uma entidade em outro
no, outras podem ser obtidas pelas construcoes normais de linguagem Oz (a
referencia inicial pode ser para um objeto que retorna outros nas chamadas
a seus metodos, por exemplo).
Os protocolos apresentados acima nao funcionam bem na presenca de
falhas. A sua implementacao real e diferente, de modo a ser mais robusta
em caso de falha de nos (especialmente o que contem o manager). O programador tem liberdade para mudar o comportamento padrao do sistema
quando encontra uma falha, atraves da instalacao de handlers, chamados em
caso de falha da entidade para qual o handler foi instalado, durante alguma
operacao nessa entidade, e de watchers, que detectam falhas em entidades
mesmo quando nenhuma operacao esta sendo feita.
Finalmente, ha a questao de seguranca. No aspecto de seguranca da
linguagem, a linguagem Oz nao permite forjar referencias (e o sistema Mozart
nao permite forjar tquetes). O escopo lexico junto com funcoes como valores
de primeira classe permite a criacao facil de sandboxes que limitam o acesso a
determinados recursos. A maquina virtual nao faz uma checagem da validade
dos bytecodes, entretanto, o que e problematico em um sistema que permite a
transmissao de codigo. Mas uma solucao para esse problema seria ortogonal
ao resto do sistema, e nao afetaria o funcionamento dele. O mesmo vale para
seguranca no nvel da comunicacao entre os nos: nada impede que o sistema
seja modificado para usar conexoes seguras entre os nos.

Mozart e os Outros Sistemas

Uma maneira de se programar sistemas distribudos e usar uma biblioteca


de troca de mensagens, junto com uma linguagem centralizada. Esse tipo
de biblioteca existe para praticamente todas as linguagens. Essa abordagem
deixa explcita a caracterstica distribuda do sistema, ja que todo sistema
distribudo e em essencia um conjunto de nos trocando mensagens para atingir algum objetivo.
A vantagem de se programar um sistema distribudo dessa maneira e
que se tem o controle total das operacoes realizadas, e quantas mensagens
cada operacao demanda, assim como se tem o controle do tamanho de cada
mensagem. O programador paga por esse controle com o baixo nvel de
abstracao dessa abordagem. A programacao de sistemas distribudos desse
modo tem um paralelo com a programacao em uma linguagem de montagem:
oferece a possibilidade de se programar sistemas com grande eficiencia, mas
a programacao se torna mais difcil.
Sistemas integrados, por outro lado, adicionam a distribuicao `a propria
linguagem, procurando deixar a programacao de um sistema distribudo
proxima da programacao de um sistema concorrente. Abstracoes nesse sistema podem ser mapeadas nao para um u
nico envio de uma mensagem entre
nos, mas para a execucao de um protocolo envolvendo diversos nos. O custo
da maior facilidade na programacao e na menor eficiencia, com um n
umero
maior de mensagens enviadas e com o maior tamanho das mensagens.
Mozart e um sistema integrado, mas existem outros. Nas proximas secoes
farei uma comparacao do sistema Mozart com Java RMI, o sistema Voyager
e a linguagem Erlang distribuda.

6.1

Java RMI

O objetivo do Java RMI [5] e permitir a chamada de metodos em objetos


Java remotos de maneira transparente para o programador. O programacao
desses objetos remotos tambem e transparente. Chamadas para um objeto
remoto sao automaticamente convertidas em uma mensagem para o no onde
o objeto se encontra. Chegando la, a mensagem e convertida de volta em
uma chamada de metodo Java, executada, e o valor de retorno e mandado
de volta em outra mensagem. Todo o processo e sncrono, ou seja, a thread
que chamou o metodo so continua sua execucao quando receber a resposta.
A transparencia do RMI e limitada, entretanto, se comparada `a do sistema Mozart. No RMI, a transparencia so e garantida se os argumentos e valores de retorno da chamada sao valores primitivos, outros objetos imutaveis
ou objetos remotos. Nessas condicoes o comportamento de uma chamada
9

remota e o mesmo de uma chamada local (a parte possveis falhas). Todo


objeto nao remoto passado como argumento, ou retornado por um chamada
RMI, e serializado e uma copia dele recriada no outro no, ou seja, os objetos
sao passados por valor. Isso e diferente de uma chamada local Java, em que
o objeto e passado por referencia, e o metodo chamado recebe o mesm objeto
passado como argumento, e nao uma copia dele. A programacao com RMI
exige um certo cuidado do programador, portanto.
Ou
nico tipo de objeto remoto no RMI sao os objetos estacionarios. Um
objeto nunca sai do no onde foi criado, e todas as chamadas a ele vindas
de outros nos serao sempre remotas. Mozart oferece objetos estacionarios,
mas tambem oferece objetos moveis, que migram de no em no para que
as operacoes sejam sempre executadas localmente. As chamadas no RMI
sao sempre sncronas. Chamadas assncronas podem ser simuladas fazendo
a chamada em sua propria thread, mas threads Java sao pesadas, ja que
mapeiam diretamente em threads do sistema operacional. Mozart tambem
oferece chamadas assncronas, e as threads sao leves.
Finalmente, o compartilhamento de codigo entre nos de um sistema
Java RMI pode ser problematico. Em Mozart, o codigo que implementa
os metodos de uma classe ficam nela mesma, e sao transmitidos junto com
a classe, quando um objeto e referenciado por outro no pela primeira vez.
Pode ate existir uma classe com o mesmo nome no no destino, mas ha uma
garantia de que nao havera conflito entre as duas. Em Java, nem classes
nem metodos sao valores de primeira classe; a associacao entre um objeto
e uma classe e pelo nome dela. RMI possui um esquema para transmitir o
codigo da classe para o no remoto, caso ela nao exista. Mas nada impede que
exista uma classe no no remoto com o mesmo nome, mas que seja diferente
da classe original, causando um conflito. Novamente, isso pode ser resolvido,
mas exige maior disciplina do programador.

6.2

Voyager

Voyager [3] e um sistema para Java que conserta algumas deficiencias do


RMI. A limitacao da transparencia nas chamadas a metodos continua; o
programador deve ter cuidado ao passar objetos mutaveis. Mas Voyager
tambem permite fazer chamadas assncronas, sem precisar de uma thread so
para a chamada. Para permitir chamadas assncronas com valores de retorno,
Voyager introduz na linguagem Java o conceito de futuros, uma estrutura
que ira armazenar o valor de retorno quando ele estiver disponvel. Threads
podem ler esses futuros, e ate bloquear ate que o valor fique disponvel. Isso e
similar ao comportamento distribudo das variaveis de Mozart, com algumas
diferencas. Em primeiro lugar, um acesso a uma variavel nao-definida sempre
10

bloqueia a thread, em Mozart, enquanto um futuro pode ser examinado sem


bloquear. Em segundo lugar, atribuir uma variavel nao definida a outra
une as duas variaveis, em Mozart, fazendo elas essencialmente se tornarem a
mesma variavel; isso nao e possvel com futuros. Finalmente, uma variavel
Mozart nao definida pode ser atribuda por qualquer thread que tenha uma
referencia a ela, enquanto um futuro so pode receber o valor de retorno da
chamada assncrona.
Voyager tambem permite a migracao de objetos, mas essa migracao e
explcita e direcionada mais `a implementacao de agentes moveis (objetos
ativos que migram entre nos) do que o tipo de objeto movel da linguagem
Mozart, que sao objetos que migram passivamente entre nos para que se
executem operacoes neles. Agentes moveis podem ser implementados em
Mozart, mas nao sao primitivos no sistema. Voyager tambem herda do RMI
a limitacao quanto ao compartilhamento do codigo das classes.

6.3

Erlang

Erlang [2] e uma linguagem de programacao funcional, dinamicamente tipada


e interpretada, com suporte integrado a concorrencia. O modelo de concorrencia de Erlang sao processos se comunicando atraves de troca assncrona
de mensagens. Processos nao compartilham dados. Os processos de Erlang
nao tem relacao com processos do sistema operacional subjacente, sendo
muito mais leves. Funcoes em Erlang nao sao valores de primeira classe, ao
contrario das funcoes em Oz.
Erlang tambem tem distribuicao integrada `a linguagem; a comunicacao
entre processos em nos diferentes e identica `a comunicacao entre processos
locais, para o programador. Processos Erlang possuem estado, e podem ser
usados para implementar objetos ativos. No caso distribudo, os processos
viram objetos estacionarios. A linguagem nao tem mobilidade de codigo,
portanto objetos moveis nao podem ser implementados para o caso geral (se
o codigo do processo existir em todos os nos um tipo de mobilidade pode ser
implementado usando replicas).

Refer
encias
[1] DKFI. Oz Versao 2, 1996. Available at http://www.ps.uni-sb.de/
oz2/.
[2] Ericsson. Open Source Erlang, 2005. Available at http://www.erlang.
org.

11

[3] ObjectSpace. Voyager, 2005. Available at http://www.erlang.org.


[4] Per Brand. The Design and Philosophy of Distributed Programming
Systems: The Mozart Experience, 2005. Available at http://www.sics.
se/perbrand/mozart.pdf.
[5] Sun Microsystems. The Remote Method Invocation Specification, 1997.
Available at http://www.javasoft.com.

12

Anda mungkin juga menyukai