Pesquisar este blog

domingo, 30 de março de 2014

Arquitetura de Sistemas Distribuídos

Arquitetura

Sistemas distribuídos são sistemas complexos, que contem diversos componentes espalhados por várias máquinas em diferentes redes de computador. Saber administrar e organizar estes sistemas é um ponto crucial para obter um melhor desempenho.

Existem dois tipos organização que devem ser feitos, ao se planejar o desenvolvomento de um sistema distribuído, o tipo lógico que trata de onde e como organizar os softwares deste sistema, e o físico, que trata da organização física das máquinas em cada rede.

A arquitetura de um sistema distribuído deve levar em conta quais são os seus componentes de software e como eles interagem entre si, para que com esta análise, seja possível decidir qual é a melhor maneira de alocar as máquinas disponíveis para constituí-lo.

Construir um sistema distribuído depende da instanciação de vários componentes de software, como um servidor web, um servidor de cache, um servidor de banco de dados, servidor da camada de negócios, um firewall, um proxy, etc, e existem diversas maneiras diferentes de se organizar estes sistemas. 

Esta organização também é conhecida como arquitetura de software, que pode ser classificada em dois tipos a centralizada onde uma máquina contém muitos dos componentes daquele sistema e a descentralizada, onde cada software roda em um servidor diferente.

Monitorar as máquinas destes sistemas também é um passo importante para obter-se alta disponibilidade. Fatores como o desempenho ou o tempo de resposta de uma certa máquina podem ser utilizados para se decidir quando criar novas instâncias daquele software ou camada, ou quando derrubá-las para economizar recursos. O monitoramento também pode indicar áreas de gargalo onde melhorias de desempenho devem ser implementadas a fim de obter-se um melhor aproveitamento do parque máquinas disponíveis.

Existem ferramentas de mercado que ajudam a descobrir o comportamento dos seus usuários, monitorando os seus cliques, o movimento do mouse. Estas ferramentas também disponibilizam dados como, sexo, idade, profissão, onde mora, quais lugares frequenta, quando acorda, que horas chega ao trabalho e algumas vezes inclusive a renda provável.

Estes dados são capturados pelas empresas afim de prover anúncios, ou mostrar produtos de forma a conseguir uma maior taxa de vendas. Como cada usuário gera uma quantidade considerável de dados, e os sites possuem milhares de usuários, a forma de armazenar e processar estes dados será diferente, eles geralmente não se encaixam em um sistema de armazenamento comum, como um banco de dados SQL, mas isto será discutido em um outro momento neste blog.

Estilos de arquitetura

A discussão sobre os estilos de arquitetura será realizada no nível dos componentes, em como eles se conectam entre si, como eles trocam dados e finalmente em como eles serão configurados em um sistema.
Os estilos de arquitetura de componentes são mostrados a seguir:
  1. Arquitetura nivelada
  2. Arquitetura baseada em Objetos
  3. Arquitetura de Dados Centralizados
  4. Arquitetura baseada em Eventos

Na arquitetura nivelada os componentes são organizados em várias camadas e uma requisição percorre os componentes apenas em uma direção.

Em uma arquitetura baseada em Objetos cada objeto é definido como um componente, e estes componentes são conectados através de chamadas do tipo RPC, que será utilizada por sistemas do tipo Cliente-Servidor.

Arquitetura baseada em dados centralizado diz que todos os processos devem se comunicar através de um sistema de repositórios (ativo ou passivo) comum. Exemplo temos softwares que utilizam apenas um tipo de banco de dados.

Arquitetura baseada em eventos os processos se comunicam através da propagação de eventos os quais opcionalmente poderão carregar dados. Como exemplo temos sistemas de publish/subscribe, ou mesmo aplicativos que usam o Akka Toolkit. Um processo publica um evento enquanto o middleware garante que alguém estará escutando aquele evento, a grande vantagem desta arquitetura é que os processos são desacoplados e ocorrem em paralelo, sem depender um do outro.

Arquiteturas de Sistema

Sistemas distribuídos são divididos em várias camadas, neste tópico serão abortados os sistemas de duas, três e multicamadas.

Duas Camadas

Um sistema de duas camadas é composto por um servidor, que contém algum tipo de armazenamento de dados como um banco de dados ou um sistema de arquivos distribuídos e por um cliente, onde ficam as regras de negócio e a interface do usuário. Este sistema era muito comum nos anos 90, onde os sistemas não eram tão complexos e poucas máquinas se conectavam ao servidor de banco de dados.

Neste modelo o servidor será responsável pelo armazenamento dos dados compartilhado, os clientes serão responsáveis por processar os dados retornados pelo servidor, fazendo com que o tráfego de dados seja muito alto entre o servidor e os seus clientes, pois muitas vezes os dados são selecionados crus no servidor e enviados ao cliente, que é quem realiza um tratamento nos dados. Por exemplo para fazer uma query ordenada, todos os dados serão selecionados no servidor e a ordenação será realizada no cliente.

Esta configuração funciona muito bem em locais onde a velocidade de rede alta, como em uma rede local, já que o tráfego de dados pela rede será alto.

A grande vantagem desta configuração é que o processamento dos dados será realizado por muitas máquinas diferentes, aliviando o processamento no servidor. Entretanto como o código de execução está instalado em várias máquinas diferentes, a instalação e manutenção destas máquinas torna-se uma tarefa muito complicada, fazendo com que a execução do software dependa das várias plataformas onde cada uma delas estiver instalada, o que costuma gerar muitos erros e incompatibilidades.

Um outro ponto a ser observado é que como a interface com o usuário está junto das regras de negócio, muitas vezes o código que desenha a interface e o código das regras de negócio estão misturados, o que dificulta a manutenção deste tipo de sistema, pois os designers (responsáveis pelas telas) e os desenvolvedores (responsáveis pelas regras de negócio) acabam trabalhando no mesmo código.

Três Camadas

Com a popularização de aplicativos web, ou mesmo a evolução dos escritórios para multi pontos em várias cidades, tornou necessário o desenvolvimento de uma nova arquitetura para atender estas novas limitações.

Em um sistema web ou multi pontos, velocidade da rede é bem inferior ao de uma rede local, além existirem muitas plataformas que acessam a web, como celular, pda, tablet, netbooks, pcs, servidores, etc. Com este novo modo de negócio a utilização de um sistema distribuído de duas camadas caiu em desuso.

A criação da terceira camada, serviu para parametrizar a separação entre as camadas de software, o que não existia no sistema de duas camadas.

Pela definição as três camadas deste sistemas são, o repositório de dados, a camada intermediária, que contem as regras de negócio e por último a camada de interface, que contem as interfaces do sistema, como telas, páginas web, etc.

A separação das regras de negócio em uma camada, facilitou a organização do código, isolando o código que será utilizado pelos desenvolvedores, dos códigos que serão alterados pelos designers, além de possibilitar o escalonamento desta camada.

Multicamadas

Na arquitetura multicamada existem diversos tipos de separação que podemos realizar entre o cliente e o servidor, que serão mostradas na figura abaixo:


A linha roxa indica a separação de o que é realizado no servidor e o que é realizado no cliente.

Começando a analise da esquerda para a direita, no primeiro caso "a" o servidor tem total controle do que será mostrado ao usuário, neste caso temos uma tela burra que somente mostra informações para o usuário não realiza nenhuma validação.

Uma alternativa a este caso é colocar toda a camada de interface na máquina do cliente, como mostra o caso "b", nestes casos a aplicação será dividida em duas, o front end o qual se comunica com o servidor em um protocolo específico do aplicativo e neste caso o front end ainda não faz nenhum tipo de processamento para apresentar a interface ao usuário. E um aplicativo que será executado no servidor com todas as regras de negócio, algo similar a web 1.0.

No caso c é mostrado que também podemos mover parte do aplicativo para o cliente e um exemplo típico deste caso é um aplicativo que tenha um formulário que deve ser preenchido completamente antes de ser processado, neste caso o front end pode checar a consistência dos dados e interagir com o usuário, um exemplo de aplicativo assim são os forms que preenchemos ao se cadastrar em sites que usam a Web 2.0. Se o nome do usuário já está cadastrado, eles já avisam ao usuário pedindo a troca, assim como CPF inválido, etc.

Muitos dos sistemas cliente servidor possuem as organizações mostradas nos casos d e e. Estes casos são utilizados quando a máquina cliente é um PC que se conectam a um sistema distribuído de arquivos, ou um banco de dados, através de uma rede interna. Essencialmente todas as operações como regra de negócios rodam no cliente, e somente o armazenamento dos arquivos/dados é feito no servidor.

Além da separação física das camadas, cliente-servidor, um sistema multicamadas consiste em separar as camadas de execução do código, como serviços, repositórios, lógica, apis, etc.

Em um sistema multicamadas, pode conter mais de um sistema de armazenamento de dados, como um sistema de cache, ou um sistema de armazenamento de arquivos (imagens, etc).

Arquiteturas Descentralizadas

Cada camada de um aplicativo multicamadas corresponde diretamente a organização das aplicações e a distribuição em camadas é conhecida como distribuição vertical. Esta distribuição vertical consiste em dividir o aplicativo em camadas lógicas que ficam alocadas em diferentes servidores.

Nos sistemas de hoje, o que conta geralmente é como os clientes e os servidores estão distribuídos, o que é chamado de distribuição horizontal, ou também de sistemas ponto a ponto.

Arquitetura Microserviços

Uma outra forma de distribuir um sistema em multicamadas é a chamada arquitetura de microserviços, onde temos diversas máquinas provendo serviços para um sistema. Estes sistemas podem rodar cada um em um servidor diferente, ou podemos ter serviços classificados por tipos, por exemplo serviços referentes ao usuário, como o cadastro, alteração e remoção da conta do usuário, rodar em um servidor isolado.

Estes serviços podem ser colocados em servidores bem pequenos que ficarão isolados.

Nesta arquitetura tem-se a possibilidade de escalar muito bem cada tipo de serviço, se o sistema está passando por uma grande demanda no cadastro dos usuários, podemos replicar as máquinas que serão responsáveis por este tipo de serviço e esta demanda será atendida.

Este comportamento é bem diferente de um sistema onde todos os serviços ficam em uma mesma máquina, neste caso para atender uma demanda destas, deveríamos replicar todos os serviços do sistema.

Como desvantagens nesta arquitetura estão a maior dificuldade de administrar uma maior quantidade de sistemas rodando em paralelo, assim como repositório de código, entre outros. Um outro fator que pode ser citado é, dependendo de como foi implementado o software, o compartilhamento de código comum pode ficar complicado, e decisões erradas de arquitetura podem levar a reescrever boa parte do código.

Arquiteturas ponto a ponto Estruturadas

Neste tipo de arquitetura os componentes são organizados dentro de uma rede e eles são construídos através da configuração de rede. A configuração mais utilizada é a de Tabela Hash Distribuída. Neste sistema os itens de dados recebem uma chave randômica de 128 ou 160 bits. Além dos dados cada ponto, ou cada nó da rede, também recebe uma chave randômica. O ponto chave deste tipo de sistema é conseguir implementar um sistema eficiente e determinístico em que cada chave aponta para apenas um objeto.

Em um sistema de Chord (Acorde) os nós ficam disponíveis em círculo já que cada nó aponta, pelo menos, para o seu sucessor.

Porém caso cada nó contivesse somente o seu antecessor, uma busca por um nó poderia ter que percorrer a rede inteira até encontrá-lo, por isso no sistema Chord cada nó também contém uma tabela que aponta para os outros nós do círculo, sendo que esta tabela pode conter até todos os elementos do circulo, formando uma espécie de cache dos endereços dos componentes do sistema. Com esta tabela o tempo de busca de um nó dentro de um Chord cai consideravelmente.

Para um novo nó se juntar a rede, ele precisa saber somente o dado do seu antecessor, já quando um nó deixa a rede, uma reorganização deverá ser feita, já que o seu sucessor deverá alterar o seu antecessor para o antecessor do nó que está deixando a rede.

Content Addressable Network (CAN) é um outro sistema baseado em DHT, que foi desenvolvida para ser escalável, tolerante a falhas e auto organizável. O design desta rede é um plano cartesiano de coordenadas virtuais, onde são colocados os endereços virtuais dos pontos de rede o que não tem nenhum relacionamento com a localização física desta rede. Cada ponto é uma área do plano cartesiano e cada ponto da rede contém os endereços de todos os seus vizinhos e ele usa o posicionamento virtual para estabelecer a melhor rota entre dois pontos de uma rede. Quando um novo ponto é adicionado ele pega um valor arbitrário de um ponto, o qual terá a sua área divida em dois, sendo que o ponto novo e o ponto escolhido, ficarão cada um com uma metade da sua área anterior.

Porém quando um ponto sai da rede um dos seus vizinhos assumirá a sua área, o que nem sempre gerará um retângulo. Neste caso todos os vizinhos do nó que está deixando a rede é informado do seu novo vizinho, gerando uma distorção no caminho da rede. Por isso existe um processamento que roda em background para reorganizar a rede, que neste caso irá cuidar da reorganização daquela área da rede.

Arquiteturas de ponto a ponto não estruturadas

Sistemas de ponto a ponto não estruturados utilizam algoritmos randômicos para conectar os pontos, fazendo com que cada ponto tenha uma lista de pontos vizinhos que é construída randomicamente. Esta lista possui um parâmetro de tempo de vida, o qual indica quão velho é a conexão com aquele nó. Os nós, quando se comunicam, trocam informações sobre seus vizinhos.

Em um algoritmo que cuida de uma rede não estruturada, existem threads que varrem estas listas tentando otimizar as conexões destas redes.

O principal fator da troca de informações entre dois nós, é a construção de uma lista otimizada, para isso eles devem decidir quais informações descartar na criação da nova lista de vizinhos. Existem muitas formas de se fazer isso, incluindo o descarte das informações que foram enviadas ao outro nó, descartar os nós mais antigos.

Como não existe uma maneira especifica de determinar uma rota entre dois pontos de uma rede não estruturada, este tipo não é escalável.

Superpontos

Os superpontos foram uma solução proposta para resolver o problema de escalabilidade de redes não estruturadas. Nesta proposta os superpontos são nós que contém as ligações para os seus vizinhos, e qualquer nós que queira contactar algum nó em outra rede, deverá antes passar por um superponto. Neste tipo de rede, todo nó comum deve estar conectado a um superponto.

Qualquer ponto que se junte a rede, deverá se conectar a um superponto, e ao deixá-la ele somente deverá atualizar a conexão com o superponto.

O grande desafio desta arquitetura é como eleger os pontos que serão usados como superpontos, uma vez que um superponto deverá ser confiável e duradoura.

Arquiteturas hibridas

Até aqui abordamos separadamente arquiteturas ponto a ponto e de sistemas cliente servidor, mas muitos dos sistemas distribuídos utilizam um mix destas arquiteturas, unindo estes dois tipos de arquiteturas torna-se possível aproveitar os pontos positivos de cada uma delas.

Sistemas Edge Server

Os sistemas de Servidores Edge são um dos exemplos híbridos a serem mostrados neste post. Estes sistemas fazem parte da arquitetura de provedores de internet.

Os provedores de internet são utilizados por muitos usuários, incluindo empresas inteiras e também usuários caseiros. Estes servidores são deployados no ponto de conexão com a internet, e a principal função deles é servir conteúdo, aplicando-se alguns filtros e funções de transcrição. Os servidores de edge também são utilizados para replicar parte dos dados que ele pegam da internet, para que com isso, diminua a necessidade de conexão e de transporte de dados entre os provedores e a internet em si. Uma vez tendo a informação mais perto, no caso armazenada no provedor, o usuário final terá um acesso mais rápido as informações, pois ao invés de sua requisição ter que passar pela internet, ela já estará armazenada no seu provedor.

Sistemas Colaborativos Distribuídos

Estes sistemas proveem um sistema descentralizado de distribuição de conteúdo. Um bom exemplo deste tipo de sistema é o BitTorrent, que é um sistema de download ponto a ponto. Neste sistema os arquivos são quebrados em pacotes e quando um usuário deseja pegar algum arquivo, ele poderá baixar vários pacotes de lugares diferentes. Um dos principais pontos do design do BitTorrent é a colaboração, pois uma vez que um usuário não compartilha nada, o servidor irá baixar a velocidade com a que ele realiza os downloads.

Para fazer um download de um arquivo, o usuário deverá acessar um diretório global, que contém os arquivos .torrent. Estes arquivos carregam as informações sobre o arquivo que o usuário deseja baixar, incluindo as informações conhecidas com tracker.

Um tracker é um servidor que o usuário deverá se conectar para saber onde se encontram os nós ativos que estão provendo partes deste arquivo. Os trackers ordenam os nós de acordo com a velocidade de conexão dele, a quantidade de arquivos compartilhados, etc.

Claramente o BitTorrent faz a utilização de sistemas centralizados e sistemas descentralizados.

Um outro exemplo clássico de sistemas colaborativos é o Globule, que se trata de um sistema de colaboração de conteúdo distribuído. Este sistema se baseia nos sistemas de arquitetura Edge discutidos anteriormente. Porém neste caso, ao invés de provedores de internet disponibilizarem os servidores Edge, usuários comuns e empresas disponibilizam servidores web onde o conteúdo da rede Globule será armazenado. Estes servidores devem conter as seguintes funcionalidades:

  1. Componente que consiga redirecionar requisições a outros servidores.
  2. Componente para analisar os padrões de acesso.
  3. Componente para administra a replicação de páginas da Web.

Arquitetura versus Middleware

O middleware fica em uma camada entre os aplicativos e as plataformas dos sistemas distribuídos, e o que geralmente acontece é que eles seguem um estilo de arquitetura específico. Com isso o desenvolvimento de sistemas fica mais simples, entretanto nem sempre o estilo de arquitetura do middleware condiz com o aplicativo que o desenvolvedor irá fazer.

Interceptadores 

Os interceptadores são um tipo de software que desvia o fluxo de um aplicativo, permitindo a execução de um código específico, entre duas camadas. Alguns exemplos de interceptadores incluem particionamento dos pacotes e a sua montagem posterior, transformações na mensagem a fim de adaptá-la, incluindo modificações de encoding, etc.

Monitoramento

Um dos principais pontos de um sistema distribuídos é o monitoramento, uma vez que o hardware, o software, a rede a energia podem falhar e esperamos que os sistemas continuem funcionando quando estas falhas acontecem.

Estes sistemas necessitam de um monitoramento contínuo para que em qualquer uma destas falhas, alguma atitude seja tomada a fim de corrigir o problema.

Além de monitorar a energia, a rede e o hardware estão funcionando, o sistema também deve monitorar se o hardware não está sendo super utilizado ou subutilizado. Isso acontece pois este dois casos afetam o negócio, o primeiro com um baixo desempenho, e o segundo com um custo maior do que o necessário.

O monitoramento deve prover respostas de se o hardware está sendo suficiente para a execução do sistema, ou se mais máquinas, ou máquinas mais potentes serão necessárias.

Sistemas distribuídos auto administrados

Sistemas Auto administrados são aqueles em que existe uma camada de software responsável por tomar atitudes que resolvem as falhas detectadas, por exemplo em um sistema distribuído de múltiplas zonas (quando o sistema está em mais de um datacenter em locais diferentes), quando um dos seus datacenters tenha problemas e fique offline, o sistema automaticamente redistribuí as chamadas para o datacenter que está funcionando e se necessário aumenta a quantidade de máquinas naquele datacenter automaticamente, sem interferência humana, para que este problema não afete o desempenho do software.

Quando acontecer um pico de demanda, o dispositivo que administra o sistema deverá aumentar a quantidade de máquinas disponíveis, e quando houver uma queda na demanda, o sistema deverá diminuir as máquinas disponíveis e assim o gasto com máquinas será otimizado evitando desperdícios ou mesmo lentidão.

Mesmo tendo um software administrando o sistema, é sempre bom ter alguém responsável para ficar de sobreaviso caso o software de monitoramento falhe ou mesmo alguma falha que o sistema não esteja preparado para resolver aconteça.

Sistemas distribuídos com gerenciamento manual

Um sistema com gerenciamento manual possui as mesmas características de um sistema auto administrado a grande diferença entre os dois é que aqui a administração do sistema depende de um humano, com isso qualquer decisão de modificação será tomada por uma pessoa, ao invés de por um software. 

Neste sistema pessoas ficam de olho nos dados providos pelos monitores do sistema e quando algo não está funcionando da maneira esperada o funcionário responsável pelo sistema deverá tomar alguma atitude para corrigir a falha.

Arquitetura de Micro Serviços (Microservices)

Com a evolução da internet e o aparecimento dos serviços as arquiteturas evoluíram afim de se adaptar as novas demandas. No início todos os serviços estavam alocados em apenas um servidor, o que é chamado de arquitetura monolítica, então quando um aplicativo tinha uma alta demanda, por exemplo, para um serviço específico, uma nova máquina deveria ser criada e todos os serviços sobem junto com esta máquina.

Os servidores web também evoluíram e alguns deles ocupam bem pouca memória e processamento das máquinas. Estes servidores também tem um tempo de inicialização bem curto. Com isto, surgiu a proposta de se criar uma arquitetura de microserviços, onde cada serviço específico estaria alocado em um servidor próprio, para que quando houvesse uma demanda muito específica, como a listagem de produtos em um ecommerce, operação realizada quando um usuário entra em na página principal de um ecommerce, o que pode acontecer quando um email de promoção é disparado para os clientes. Para fazer com que a experiência do usuário, seja a melhor possível, e o tempo de espera para carregar a página não seja longo, réplicas do servidor que contem este serviço devem ser inicializadas, ou em máquinas novas, ou mesmo em máquinas cuja capacidade de processamento estava ociosa.

Nesta arquitetura, a resposta a demandas específicas é bem mais curta e o desperdício de recursos também, já que havendo uma demanda específica apenas aquele serviço vai subir novamente.

Porém, como há muitos servidores rodando ao mesmo tempo, a administração do ambiente se torna mais complexa, já que temos diversos servidores rodando para manter em pé, apenas um aplicativo.

A grande diferença desta arquitetura para uma arquitetura monolítica, onde todos os serviços ficam dentro de um mesmo servidor, é que nela podemos configurar melhor e fazer com que o aproveitamento do hardware seja o melhor possível.

Arquitetura sem servidor (Serverless)

Atualmente existe uma diversificação dos serviços disponibilizados pelos provedores de Cloud. A cada dia um novo serviço surge, e estes serviços podem ser utilizados para executar parte, ou totalmente a lógica de negócio de um aplicativo/site. No início estes serviços foram descritos como Backend as a Service (BaaS).

Inicialmente, o termo serverless foi utilizado para descrever aplicações que dependem muito, ou totalmente, destes serviços dos provedores de cloud para rodar.

Uma outra forma de definirmos a arquitetura Serverless são aplicativos os quais a lógica, ao invés de rodar em servidores que ficam sempre ligados e conectados, elas rodam em serviços que são oferecidos pelos provedores cloud e são disparados por evento, ou são do tipo ephemeral (rodam apenas uma vez) e são totalmente administrados pelo provedor. Estes serviços são conhecidos como Function as a Service (FaaS).

Todos estes serviços disponibilizados pelos provedores de cloud são auto escaláveis, ou seja, eles conseguem responder a grandes variações nas demandas de utilização do seu serviço.

Dentre as principais vantagens desta arquitetura é a facilidade de desenvolvimento, o rápido tempo para colocar algo em produção, não precisar tomar conta dos servidores, planejar alocação ou desalocação de máquinas. Poder desenvolver um software com várias linguagens, já que cada serviço é independente um do outro.

Também podemos citar como vantagem o fato de que os serviços só cobram por tempo de execução, portanto, se você tiver um site/app onde parte do dia ele não recebe visitas nada será cobrado neste período. 

Mas este tipo de arquitetura não se aplica para todos os casos e também deve-se analisar as suas desvantagens antes de começar a desenvolver algo sobre ela. Dentre as principais desvantagens temos a dificuldade em debugar uma aplicação de forma local, como não teremos a mesma arquitetura disponível para os desenvolvedores isto pode ser um grande problema. Como não temos controle de onde estes serviços estão rodando, teremos uma latência maior, ou seja o tempo de execução do serviço será maior. Os provedores possuem um limite de memória e tempo de execução para cada função e isto pode ser um problema em alguns casos. Você ficará preso ao ser provedor de cloud, uma vez que cada um possui uma forma diferente destes serviços e migrar de um para o outro pode resultar em ter que reescrever todo o seu software.


Apresentação

terça-feira, 18 de março de 2014

Sistemas Distribuídos Comunicação Multicast

Nos posts anteriores, Comunicação socket, stream,mpi e message queue e Comunicação (protocolo de rede, rpc e dce) foram explicados os sistemas de comunicação em sistemas distribuídos, aqui será descrito o sistema de multicast

Multicast

Multicast é utilizado quando há a necessidade de difundir uma informação para vários pontos diferentes, dentro de uma mesma rede. Várias técnicas foram utilizadas para difundir as informações, incluindo espalhamento por pontos, técnicas de infecção e protocolo de fofoca.

A ideia principal no multicast feito ao nível de aplicativos é fazer com que os nós se reconheçam dentro de uma mesma rede, e com isso consigam disseminar informações.

Existem duas maneiras de se construir uma rede para multicast, na primeira delas os nós se organizarão em uma árvore, o que significa que só existirá um caminho entre qualquer par de nós. Já na outra maneira os nós são organizados em forma de malha, onde cada ponto tem múltiplas conexões com outros nós. A principal diferença entre estes dois tipos de rede é que na segunda, em forma de malha, uma falha de um nó não afeta muito a performance da rede, já que a rede não precisará se reorganizar imediatamente, ou seja ela é mais robusta. Já na primeira, em forma de árvore, cada falha de um nó, irá impedir um caminho entre dois pontos, obrigando a rede a se reorganizar.

Técnicas de infecção

As técnicas de infecção foram algorítmos criados a partir de estudos do comportamento dos vírus, de como eles fazem para se espalhar nos organismos vivos. Estes algorítmos tentam reproduzir no software o mesmo comportamento dos vírus, só que aqui este comportamento será utilizado para disseminar informações.

Um dos principais modelos de propagação é o de anti-entropia e neste modelo um nó I pega um outro nó D randomicamente e troca informações com este nó D. Neste modelo existem três formas de propagação da informação.

  1. I somente envia informações para o D 
  2. I somente recebe informações do D
  3. I recebe e envia informações com o D

No primeiro caso, as informações não serão espalhadas rapidamente, já que a informação só será espalhada pelos nós que estão contaminados (por contaminados entenda atualizados), com isso no começo poucas atualizações serão repassadas. Ao mesmo tempo, quando muitos nós estão atualizados, as chances de eles selecionarem um nó ainda não atualizado é relativamente pequena, o que faz com que demore para completar a disseminação para todos os nós.

O segundo caso trabalha muito bem quando muitos nós estão contaminados, já que as chances de se conectar a um nó não contaminado é grande.

Dentre os modelos de propagação apresentados, o mais rápido será o terceiro, onde as informações vão para os dois nós, o que faz com que ela se propague mais rapidamente.

Uma variância deste método é o chamado de método de fofoca, que funciona exatamente da mesma forma como quando conversamos sobre alguma novidade. Imagine que você gostaria de contar algo novo aos seus amigos, no inicio você liga para uma pessoa e conta a novidade.

Assim como você esta pessoa também ficará empolgada em espalhar esta atividade, até que ela tente contar a novidade para uma pessoa que já saiba o fato, isso fará com que o disseminador (leia-se fofoqueiro) desanime de contar a novidade para outras pessoas, já que isso não será mais novidade.

No modelo de fofoca, os nós vão espalhando a informação até que encontrem alguém que já foi atualizado, a partir dai este nó para de disseminar a informação. Este método é uma maneira muito boa de se espalhar as informações, porém com ela não é possível garantir que a informação será espalhada para todos os nós.

A grande vantagem dos algorítmos de epidemia é a sua escalabilidade, já que o número de sincronizações entre os processos é bem pequena.

Removendo dados

Remover dados utilizando os algorítmos de epidemia é complicado, esta complicação se dá pois após remover os dados de um nó, ele ficará vazio, e eventualmente ele irá receber uma atualização que recarregará os dados nele. 

A dica para remover dados usando um algorítmo de epidemia é gravar a remoção como sendo uma atualização de dados, com isso os dados daquele nó não serão atualizados novamente.

O grande problema desta solução é que ela é muito custosa em relação ao espaço ocupado pelas informações, uma vez que os dados apagados, não foram retirados do sistema.



quarta-feira, 12 de março de 2014

Sistemas Distribuídos Comunicação (Socket, stream, mpi e message queue)

A descrição da comunicação em sistemas distribuídos, começou a ser mostrada no post anterior, aqui neste post a comunicação dos sistemas distribuídos continuará a ser descrita, incluindo a comunicação orientada por mensagens e broadcasting.


1. Comunicação orientada por mensagens

Remote procedure calls e remote object invocations são chamadas que promovem a transparência nas chamadas e com isso acabam escondendo um pouco da comunicação existente para a realização destas chamadas.

Ao fazer uma RPC não conseguimos detectar se o sistema, onde faremos a chamada está rodando, com isso o desenvolvimento de sistemas de comunicação alternativos foram necessários. Além disto, a natureza síncrona de uma chamada RPC algumas vezes precisa ser substituída por outra implementação.

Aqui serão apresentados os sistemas de mensagem que são uma alternativa ao RPC nos sistemas distribuídos.

2. Sockets

Conceitualmente um socket é um ponto de conexão onde uma aplicação pode escrever dados que serão transmitidos pela rede, ou ler dados que chegam pela rede. O socket é uma camada de abstração utilizada pelo sistema operacional e por um protocolo de transmissão de dados específico, para abrir um canal de comunicação entre duas máquinas.

Um servidor socket, quando se inicializa, reserva recursos da máquina para mandar e receber mensagens em um protocolo específico, isso se dá por reservar uma porta local para a transmissão dos dados.

A implementação de socket possui uma lista de comandos primitivos que serão utilizados para estabelecer a comunicação e transmitir dados, estes comandos são listados a seguir:

  1. Socket Cria um endpoint de comunicação
  2. Bind Anexa um endereço local em um socket
  3. Listen Escuta um endereço para aceitar conexões 
  4. Accept Bloqueia o chamador até que uma requisição seja feita 
  5. Connect Tenta estabelecer uma conexão
  6. Send Manda dados pela conexão
  7. Receive Recebe dados pela conexão
  8. Close Fecha a conexão

Ao inicializar um processo socket no servidor, ele irá utilizar o comando de bind de uma porta, ou seja, ele irá atribuir uma porta ao serviço de socket. Esta porta ficará esperando requisições de um cliente para transmitir dados. Um cliente socket conectado ao servidor, pode executar chamadas de leitura e escrita de dados nele, e estas mensagens podem ser tanto síncronas quanto assíncronas.

Um ponto importante a ser observado na comunicação que utiliza um socket é que o servidor deve manter aberta a porta de conexão enquanto ele estiver rodando para que com isso,  seja possível transmitir dados entre duas máquinas. Este ponto é uma das desvantagens do socket já que os recursos das máquinas dos servidores devem ficar alocados enquanto uma comunicação é esperada.

3. Interface de envio de mensagens MPI

Conforme as máquinas foram evoluindo e com o aparecimento de processadores com multiplos cores, o que gerou a necessidade de se criar softwares que podiam processar requisições em paralelo. Surgiu uma interface de envio de mensagens, e com isso, inicialmente os fabricantes de grandes máquinas desenvolveram sistemas próprios de comunicação, adaptada e otimizada para o seu tipo de hardware.

Estas mensagens eram incompatíveis entre elas e isso gerou um problema de transcrição para os programadores.

Caso fosse necessário realizar uma comunicação entre dois sistemas de fabricantes diferentes, uma tradução de mensagens deveria ser implementada pelos programadores, o que se mostrou uma das desvantagens destes sistemas.

Desta incompatibilidade surgiu um padrão de troca de mensagens que fosse independente de plataforma e hardware, este sistema foi chamado de MPI (Message Passing Interface).

A MPI assume que falhas de rede e problemas sérios com as máquinas são fatais e não precisam de uma recuperação automática, ela assume também que a comunicação é feita por um grupo conhecido de processos, no qual cada grupo possui um identificador, assim como cada processo de um grupo também possui um identificador, o que identifica unicamente o emissor e o destino de uma mensagem.

Tanto operações transientes síncronas e assíncronas são suportadas pela MPI, tudo dependerá de quais comandos primitivos serão executados durante a troca de mensagens. Mensagens transientes são aquelas mensagens que não são armazenadas.

4. Fila de Mensagens

Um sistema de fila prove um protocolo de comunicação por troca de mensagens onde quem envia e quem recebe não precisam tratar a mensagem ao mesmo tempo. A mensagem é armazenada em uma fila até que um recebedor peça para processá-la.

As mensagens são repassadas entre servidores de comunicação até que elas, eventualmente, serão entregues ao seu destino final, mesmo quando o seu destino não estiver funcionando quando a mensagem for entregue.

Existem leitores de mensagens, que são responsáveis por receber, enfileirar e processar as mensagens recebidas, e os escritores os quais enviam mensagens aos receptores. Na maioria das vezes eles estão diretamente conectados, o que faz com que as mensagens sejam enviadas diretamente.

Os leitores possuem uma fila de mensagens a serem processadas, que serão processadas uma a uma, obedecendo o algorítimo de ordenamento da fila (fifo, filo, etc)

Neste tipo de processamento quem envia a mensagem tem a garantia que a sua mensagem será colocada na fila de processamento do receptor, mas não há garantias de quando isso vai acontecer, nem se esta mensagem um dia será lida, pois isto é totalmente determinado pelo comportamento do leitor da mensagem.

As mensagens poderão carregar qualquer tipo de dado, o ponto mais importante das mensagens é o endereço de entrega. A maioria dos sistemas de fila habilitam a instalação de uma função de callback, a qual será executada quando a mensagem for colocada na fila. A função de callback serve para avisar a quem enviou a mensagem, de que a sua mensagem foi executada, com sucesso ou não.

Um sistema de fila é persistente já que as mensagens são armazenadas e podem ser recuperadas em caso de falha da máquina.

Existem várias possibilidades de acontecer uma troca de mensagens, já que quem recebe e quem envia não precisam estar necessariamente rodando quando uma mensagem será processada. Tanto um, quanto o outro podem estar desligados quando a mensagem for enviada ou recebida, mas isso não altera o resultado final do processamento da mensagem.

Um sistema de fila típico, possui um administrador de filas, ou broker, que é configurado pelo administrador do sistema. Ele será responsável por armazenar e endereçar as mensagens aos receptores corretos, assim como administrar o tamanho da fila e das mensagens, que são limitados, alem de um software que irá retirar e processar as mensagens que foram colocadas na fila, e um software que enviará mensagens para a fila.

O administrador da fila irá armazenar as mensagens recebidas até que algum recebedor peça a ele aquela mensagem, ou que essa mensagem caduque, ou seja, estoure um tempo determinado pelao configuração daquela fila. O processamento da mensagem irá acontecer assim que a mensagem é transferida ao recebedor.

Um sistema de fila pode possuir mais de um administrador de fila, e eles podem estar tanto em máquinas diferentes, quanto em redes ou localidades diferentes.

Este tipo de sistema também é usado como backpressure, ou seja, ele pode atenuar a chegada de uma grande quantidade de mensagens em um período muito curto, e evitar que o sistema de processamento caia.

5 Comunicação por Stream

Stream pode ser definido como fluxo de dados em um sistema de computador. Até agora só estudamos sistemas onde mandávamos um pacote de dados, uma mensagem, e pronto, mas e quando precisamos enviar uma grande quantidade de dados? Ou mesmo e quando devemos transmitir algo que está acontecendo neste momento, como transmissões de voz, vídeo, etc. 

Nas outras formas de transmissões estudadas até agora, a sequência em que os dados eram enviados, ou recebidos não importavam tanto, já que eles poderiam ser reordenados antes de serem processados. Quando o stream é usado, isso não acontece, pois durante a transmissão de um show, não dá para misturar a sequência de sons, eles tem que ser transmitidos na mesma sequência.

Uma outra maneira de se utilizar o stream é durante a leitura dos arquivos de dados que temos armazenados em um hd. Estas operações de leitura, escrita ou atualização, utilizam um stream, visto que, ele também deverá ser aberto e gravado de forma sequencial.

Na transmissão de dados multimídia, por exemplo um vídeo que contém tanto o som quanto as imagens e estes dois fluxos de dados devem ser sincronizados para que o vídeo seja mostrado corretamente para o usuário.

Existem vários exemplos de sistemas de stream disponíveis na web, como o youtube, o netflix, deezer, spotify, globoplay, além de transmissões de dados de eventos ao vivo, como jogos, rádios, etc. Vejam que, alguns destes exemplos implementam um sistema que diminui a qualidade do vídeo, ou mesmo do som, de acordo com a velocidade de conexão do usuário. Conforme a velocidade de conexão aumenta, a qualidade do vídeo e do som melhora, conforme ela diminui, a qualidade do vídeo e do som piora, isto é muito útil em casos de conexões com velocidades variáveis como a internet dos celulares, já que ao se movimentar com um aparelho celular, nem sempre é possível manter a mesma velocidade da sua conexão.



sexta-feira, 7 de março de 2014

Sistemas Distribuídos Comunicação (Protocolo de rede, RPC e DCE)

Comunicação em Sistemas Distribuídos

A comunicação exerce um papel crucial em um sistema distribuído. Estudar sistemas distribuídos sem estudar comunicação não faz nenhum sentido.

Como sabemos, em um sistema distribuído, várias máquinas dividem a tarefa de executar um processo e, por isso saber como elas conversam entre si é um fator tão importante. Este post inicia os estudos de como é feita a comunicação entre cada um dos componentes de um sistema distribuído. Esta comunicação abrange desde os protocolos de rede utilizados na troca de informações entre as máquinas quanto as quatro maneiras de comunicação mais utilizadas nos sistemas de hoje, chamada de procedimento remota (RPC- Remote Procedure Call), middleware orientado a mensagens (MOM Message Oriented Middleware), streaming e finalmente comunicação do tipo multicasting será descrita.

Protocolos de rede

Quando duas máquinas querem conversar elas não compartilham a memória, ao invés disto elas enviam e recebem mensagens de comunicação.

O primeiro passo para se estabelecer uma comunicação entre duas máquinas é a definição do protocolo que será utilizado na comunicação entre elas. Os protocolos são análogos as línguas que usamos para falar,  portanto duas máquinas conversando com protocolos diferentes é a mesma coisa que colocarmos um Árabe para falar com um Chinês, como eles não falam a mesma língua a conversa não vai fluir.

No caso das pessoas basta que elas saibam uma língua em comum para que elas consigam se comunicar de forma eficiente, já no caso das máquinas elas precisam definir qual protocolo será utilizado.

Um protocolo define desde a parte física da comunicação, definindo atributos, como a quantidade de volts que serão utilizadas para determinar o valor do 1 e o valor do 0, no caso de uma comunicação binária, quanto saber qual é a última informação de uma mensagem, se ela perdeu alguma informação entre a transmissão e a recepção. Este tipo de controle é muito importante para manter o fluxo de comunicação de maneira correta e válido. Outros tipos de informações muito importantes a serem definidos nos protocolos são, as informações de qual será o tamanho das variáveis numéricas, textuais e outros tipos de dados. Todas estas informações são necessárias para estabelecer a comunicação entre duas máquinas.

O padrão mais conhecido de comunicação entre duas máquinas é o modelo OSI, que foi criado em 1995. Este modelo divide a comunicação entre máquinas em 7 camadas, que serão mostradas a seguir:

  1. Física: onde são definidos quais dispositivos serão usados como modem, Bluetooth, USB, DSL, Rede Ethernet, etc
  2. Enlace ou dados: camada utilizada para corrigir os possíveis erros de comunicação existentes entre as partes, controla o fluxo e estabelece comunicação entre sistemas diretamente conectados, como Ethernet, 802.11 WiFi, etc.
  3. Rede: Fornece meios funcionais para conexões entre redes e realiza o roteamento das funções,podendo realizar uma fragmentação dos dados, como IP(IPV4, IPV6), IPSec.
  4. Transporte: Responsável pelo transporte dos dados recebidos pela camada de sessão para a camada de Rede. Dentre as funções desta camada temos o controle de fluxo, a ordenação dos pacotes e a correção de erros. Garante a entrega das mensagens na sequencia correta, sem perder ou duplicar pacotes. Esta camada separa as camadas de nível físico (1 a 3) das camadas do nível de aplicação (5 a 7), e ela é utilizada pelo TCP, UDP, RTP, SCTP, etc
  5. Sessão: Determina como será a transmissão dos dados para que duas máquinas diferentes se comuniquem. Marca os dados, no intuito de possibilitar a correção deles no futuro para caso haja falha na transmissão dos pacotes, a transmissão será reiniciada de onde parou, usado por exemplo, pelo NetBIOS, etc
  6. Apresentação: Responsável por realizar traduções, como uma Tabela ASCII para outro padrão, pela compactação dos dados e pode ser usada com alguma criptografia, como exemplos temos o  XDR, TLS, etc
  7. Aplicação: São os programas que usamos para se comunicar na rede, é a interface entre o usuário e a máquina, como exemplos temos o BitTorrent, Telnet, SSH, DNS, Ping, HTTP, FTP, SMTP, etc.

Antes de definir como os computadores se comunicam iremos abordar alguns pontos importantes para o entendimento de como os parâmetros são passados para os métodos em uma linguagem.

Stub

Stub em ciência da computação é usado para definir um esboço de um método e eles são muito úteis para portabilidade, sistemas distribuídos e teste de software.

Um método stub contém algumas partes de código que realizam uma abstração de uma camada de software. Eles se comportam como um proxy para objetos remotos. Tendo como exemplo um método de soma, localizado em um servidor, um stub deste método seria uma interface local, com apenas a mesma assinatura deste método e ao ser chamado ele chamaria o método remoto. Atuaria como um proxy.

Call-by-name e Call-by-value 

Quando usamos parâmetros em métodos dentro de um programa que estamos construindo, eles podem ser interpretados de maneiras diferentes, que são definidos por call-by-name, e call-by-value.

Um parâmetro Call by value  tem o seu valor copiado para o parêmetro do método, ou seja, quando o método alterar aquela variável nada acontecerá com o valor da variável original.

Já em um parâmetro do tipo Call by name isso não acontece, pois ela é passada como um ponteiro para o método, e o valor utilizado dentro daquele método referencia a mesma área da memória que a variável original, com isso qualquer modificação realizada no método também será realizada na variável original. 

Na linguagem C parâmetros do tipo int, byte são value e parâmetros do tipo array são name. O mesmo vale para Java e C#, assim como as outras linguagens que são executadas em seus ambientes.

Esta diferença entre as variáveis recebidas pelos métodos também acontece, nas chamadas remotas a métodos, conforme será mostrado a seguir.

RPC

RPC é um tipo de chamada remota a um método, e estas chamadas quase sempre se comportam de maneira análoga ao procedimento realizado localmente na máquina, quando estamos tratando de parâmetros dos métodos, mesmo para os parâmetros Call-by-name caso este valor seja alterado remotamente, a variável local será alterada também. Como exemplo de RPC podemos ter a leitura de um arquivo, a execução de um método, a autenticação, etc.

As RPCs são utilizadas quando queremos rodar um método, ou um procedimento em uma máquina remota.

No caso desta execução ser em um método de leitura de dados, por exemplo uma leitura de um arquivo do sistema de armazenamento, quando este tipo de operação é realizada em um sistema local, o computador chama um procedimento de leitura de dados do Sistema Operacional, ou seja, existe uma interface entre o método de leitura da linguagem utilizada e a chamada a leitura do Sistema Operacional. Para fazer uma chamada de leitura de dados de maneira remota, uma chamada análoga é realizada, só que desta vez faremos uma requisição de leitura para o stub da máquina remota. 

Por padrão as RPCs são síncronas, ou seja, ao chamar um método seu sistema fica travado, esperando que a resposta deste método chegue, para poder continuar a execução.

Chamadas síncronas são utilizadas quando a resposta daquele método é necessária para a continuidade da execução do método corrente, por exemplo, em um método de login, a validação da senha pode ser uma chamada síncrona, já que ela é necessária para validar se o usuário pode ou não prosseguir.

RPC Assíncrono

Em uma execução de um RPC comum o cliente ficará travado, esperando pelo resultado da chamada ao método para poder continuar a sua execução. Ao fazer uma chamada assíncrona isso não acontece. Esta implementação de RPC provê ferramentas para facilitar a utilização dela de maneira assíncrona. 

Um exemplo de chamada assíncrona é o carregamento de dados após um login, muitas vezes o sistema já carrega dados do usuário, que não são necessários para o login, como endereço, telefones, etc, assincronamente, com isso é possível logar em um site, e ir para a home, sem ter que esperar o resultado da busca destas informações no banco de dados.

DCE ou Distributed Computing Environment

O DCE é uma implementação de chamadas remotas a procedimentos, no nível do sistema operacional. Esta implementação provê uma maneira de realizarmos chamadas remotas as interfaces do sistema operacional, e isso é feito de maneira que elas pareçam ser realizadas realizadas localmente, pelo menos pro programador há esta impressão. Este tipo de implementaçã é uma abstração do sistema operacional para a rede.

Ele foi inicialmente desenvolvido para o Unix por um consórcio chamado de Apollo Computer, mas depois uma implementação para o Windows foi realizada.

A implementação do DCE provê um framework para o desenvolvimento de aplicativos cliente/servidor, que inclui RPC, um serviço de nomeação de diretórios, autenticação, um serviço de relógio e um sistema de arquivos distribuído.

As implementações de WebServices, Java e a própria internet carregam em si muitos dos conceitos elaborados pelo DCE. Uma das implementações atuais de DCE é o sistema de ODBC da Microsoft, utilizado para comunicação com banco de dados.

O DCE é dividido em células onde cada uma delas contem um Serviço de Segurança, um Diretório, que será o repositório de Controle de acesso ao sistema e um Sistema de relógio distribuído.