Pesquisar este blog

terça-feira, 6 de maio de 2014

Consistência e Replicação

Consistência e Replicação

Para que um sistema seja escalável, não basta distribuir ele em várias máquinas e pronto, problema resolvido. Alguns serviços, como os de armazenamento de dados, necessitam de algum tipo de replicação e isso gera um trabalho para manter os dados consistentes. Ou seja assegurar que estes dados são os mesmos em todas as cópias, o que não é uma tarefa fácil.
A replicação de um banco de dados é realizada para aumentar a capacidade do sistema de responder a um grande volume de requisições. Porém assim que uma atualização é realizada em um ponto do sistema, ou uma instância do seu banco, é importante que esta alteração seja replicada para todas as instâncias, para que com isso os dados mantenham-se consistentes.
Em alguns casos de uso, a consistência dos dados não é uma requisição, como nas redes sociais, onde um post de um determinado usuário não precisa ser visualizado por todos seus amigos, assim que ele envia esta requisição, mas em uma grande parte dos sistemas, como no caso de instituições financeiras, os dados precisam ser consistentes. Não faz sentido se um depósito é realizado na sua conta bancária em Porto Alegre, e você não consiga ver este depósito realizado, ao tirar um extrato em Salvador.
Consistência, disponibilidade e processamento paralelo, formam o teorema de CAP nos diz que é impossível termos consistência, disponibilidade e processamento paralelo em um sistema de armazenamento de dados ao mesmo tempo, para isso devemos escolher apenas duas destas características.

Motivos para realizar uma replicação

Um dos principais motivos para se realizar uma replicação dos dados é por causa da confiabilidade do sistema, pois caso o seu sistema de armazenamento de dados esteja rodando em apenas uma máquina e esta máquina falhe, aqui podemos contar como falha de hardware, eletricidade, rede, ou mesmo software, o seu sistema inteiro estará comprometido.
Performance também aparece dentre as principais razões para a realização da replicação dos dados. Uma replicação de performance é importante quando o sistema distribuído necessita escalar em números e/ou geolocalização. A replicação por performance ocorre quando existem muitos processos tentando acessar dados de apenas uma máquina, com a replicação é possível que o trabalho desta máquina seja dividido entre várias maquinas aumentando a performance do sistema.
Em uma replicação por área geográfica acontece quando os clientes de um determinado serviço estão espalhados em diversas áreas e colocar uma cópia dos servidores perto dos seus clientes diminuirá o tempo gasto para que eles acessem os dados.
O grande ponto fraco da replicação é a quebra da consistência dos dados, quando uma cópia recebe uma atualização, ela ficará diferente das outras cópias, com isto esta atualização deverá ser replicada em todas as cópias para manter a consistência dos dados.

Replicação como uma solução de escalabilidade

Tanto a replicação como o cache são amplamente utilizados para se resolver os problemas de escalabilidade. A escalabilidade de um sistema geralmente aparece por causa de problemas de performance, quando o seu serviço não está respondendo de uma maneira aceitável. Colocar cópias dos dados em localidades mais próximas aos seus clientes é uma solução utilizada para aumentar a sua performance, pois os dados levarão menos tempo para ir de um ponto ao outro.
Manter várias réplicas de dados consistentes pode gerar um problema de performance. Tem-se que uma coleção de dados está consistente quando todas as cópias possuem os mesmos valores, o que significa que a leitura de um dado em qualquer uma das cópias deverá sempre retornar o mesmo resultado. Para manter-se consistente, assim que uma atualização é realizada, ela deverá ser propagada para todas as réplicas antes que qualquer outra operação de leitura.
Este tipo de consistência muitas vezes também é referenciado como replicação síncrona, neste caso a cada atualização todas as réplicas serão atualizadas em uma operação atômica, ou seja quando uma atualização é realizada ela só se completará quando todas as réplicas forem atualizadas. Completar uma operação síncrona em uma rede com muitas máquinas, que muitas vezes estão espalhadas em várias redes diferentes em uma rede de larga escala é uma operação bem complicada, principalmente quando esta atualização precise completar-se rapidamente.
Manter estas cópias atualizadas é um problema que, muitas vezes, necessita de muita largura de banda da rede. Considerando um processo P1 que acessa uma réplica R1 X vezes. Levando-se em conta que esta réplica é atualizada U vezes, caso X seja muito menor que U, ou seja a replica recebe muito mais atualizações do que leituras, o que gera um desperdício de banda e comunicação entre estas máquinas. Colocar uma réplica R1 próximo ao processo P1, ou aplicar uma estratégia de atualização diferente não serão a melhor maneira de resolver este problema.
Isto gera um problema interessante, por um lado temos que replicar, fazer cache aumenta consideravelmente a performance do nosso dispositivo de armazenamento, porem manter todas as cópias sincronizadas requer uma sincronização global, o que é bem custoso em termos de performance.
Muitas vezes, para ganharmos performance, deveremos perder a consistência dos dados. Algumas vezes podemos relaxar um pouco as regras de consistência, evitando que uma operação de update atômica instantânea seja necessária, neste caso nem sempre todas as réplicas do sistema terão os mesmos dados.

Modelo de consistência baseado em dados.

Um modelo de consistência é um contrato entre os processos e o local de armazenamento de dados. O qual pode ser um banco de dados, um sistema de armazenamento de arquivos ou um sistema de memória compartilhada. Este local de armazenamento de dados pode estar espalhado por diversas máquinas, e cada processo que está acessando dados pode ter uma cópia local dos dados que ele está acessando.
Uma operação é classificada de duas maneiras, como escrita quando qualquer alteração tenha sido realizada nos dados ou como leitura em qualquer outro tipo de operação.
A falta de um modelo de relógio único e global, faz com que seja muito difícil estabelecermos qual foi o último processo de escrita realizado.
Um modelo de consistência é um contrato entre os locais de armazenamento de dados e os processos, e nele são estabelecidas as regras, que se obedecidas, garantem o funcionamento correto deste armazenamento de dados.

Consistência contínua

Pelo o que vimos até agora, a replicação de dados implica em uma perda de consistência que não poderão ser resolvidas eficientemente. Porém o tipo de perda de consistência que cada aplicação pode suportar depende muito de como e do que ela trata.
Existem três maneiras independentes de definição de inconsistência, o de valores numéricos, o de staleness e o de ordenação de operações de atualização. Estes desvios são conhecidos como intervalo de consistência contínua.
Medir inconsistência usando o desvio numérico, faz sentido para aplicações que onde os dados possuem uma semântica numérica. Por exemplo ao fazer um aplicativo de compra e venda de ações, podemos especificar que duas cópias do banco de dados, um valor de uma determinada ação não pode desviar em mais de 2 centavos, o que é considerado um desvio numérico absoluto. Uma alternativa a isto é definido como desvio numérico relativo, neste caso podemos definir que uma cópia não pode diferir de outra em mais de 0.7%.
Inconsistência de desvio numérico também pode ser medido em relação ao número de operações de foram realizadas em uma determinada cópia, mas ainda não foram aplicadas as outras. Por exemplo em um aplicativo que realiza operações em batch, por exemplo um sistema que utiliza cache e o cache ainda não foi atualizado pelas operações realizadas no processo de batch.
Desvios staleness são relacionados a data da última atualização de uma réplica. Em alguns casos, os aplicativos podem mostrar dados desatualizados, como em aplicativos de previsão do tempo, onde muitas vezes podemos mostrar dados de previsão com algumas horas de atraso, sem prejudicar o comportamento do aplicativo.
Desvios de ordem da atualização dos dados podem ser suportados por alguns tipos de aplicativos. Por exemplo uma atualização pode ser aplicada temporariamente a uma cópia local, a qual fica esperando a confirmação de todas as réplicas. E como consequência alguns casos podemos ter que desfazer uma atualização e ela será aplicada de uma maneira diferente antes de se tornar permanente. Deste tipo de operação surgiu a ordenação consistente de operações onde vamos estudar a consistência sequencial e a consistência casual.

Consistência sequencial

A consistência sequencial é um importante modelo de consistência centralizado em dados. Neste modelo, quando processos rodam concorrentemente, muitas vezes em máquinas separadas, qualquer sequencia de operações de leitura e escrita é válida quando todos os processos recebem os dados na mesma sequência. Note que aqui não há uma definição de tempo, pois um atraso na propagação dos dados é completamente aceitável, se os dados forem propagados na mesma sequência.

Consistência Casual

O modelo de consistência casual é um relaxamento das regras da consistência sequencial. Neste modelo operações de escrita que são potencialmente relacionados pela casualidade, deverão ser vistos por todos os processos na mesma ordem.
Na consistência casual, quando ocorrem escritas concorrentes, ou seja, várias Threads executando operações de escrita em diversas cópias do banco ao mesmo tempo, podem ser vistas em uma ordem diferente em cada uma das réplicas.
Operações relacionadas pela casualidade são aquelas onde uma escrita em um certo dado X, é referente a um processamento no valor anterior dele. Por exemplo a atualização de um valor de estoque de um produto, estas atualizações acontecem com uma computação (decremento ou acréscimo da quantidade de produtos) sobre um valor previamente armazenado na base. Em um sistema de consistência casual, estas operações devem ser realizadas na mesma ordem em todo o sistema de armazenamento, as operacoes nao casuais, poderao ser executadas em ordens diferentes em cada uma das cópias.

Modelo de consistência centralizados no cliente

Os modelos de consistência apresentados até agora tratam da consistência de todo o sistema, porém pode-se assumir que processos concorrentes podem alterar dados simultaneamente e para prover este tipo de atualização, novos modelos foram propostos.

Consistência eventual

O modelo de consistência eventual são aqueles onde poucas atualizações ocorrem e quando elas acontecem elas não são propagadas instantaneamente. Este modelo necessita que eventualmente todas as atualizações sejam propagadas para todas as cópias. Conflitos de escrita escrita são relativamente fáceis de se resolver já que poucos processos realizam escrita.
São exemplos de consistência eventual o sistema de DNS, os sistemas de cacheamento de sites da internet, como o proxy, e base de dados onde a maioria dos processos é de leitura.
O sistema de consistência eventual funciona muito bem quando os clientes sempre acessam uma mesma réplica, porém quando múltiplas réplicas são acessadas em um curto período de tempo, os problemas aparecem. Imagine um aplicativo de celular que se conecta a uma réplica e faz várias atualizações. Depois de um curto período de tempo este aplicativo se reconecta ao serviço, agora em uma outra réplica, ou por causa de troca do tipo de acesso wifi, 3g, etc, ou pela própria localidade do celular. Ao se conectar a uma réplica diferente as atualizações inseridas anteriormente podem não estar disponíveis para o aplicativo, fazendo com que o usuário perceba a inconsistência do armazenamento.

Leitura Monotônica

O sistema de leitura monotônica foi o primeiro modelo de consistência baseado no cliente. Este sistema é baseado na condição de que quando um processo le um dado x, qualquer leitura sucessiva do x por aquele processo sempre retornará o mesmo valor, ou um valor mais atualizado.
Considere um sistema de email distribuído, onde a operação de leitura não afeta, altera, os dados da caixa de entrada. Imagine que um cliente acesse o seu email de São Paulo, e depois de algum tempo do Rio de Janeiro, neste acesso a leitura monotônica garante que todas as mensagens que foram mostradas em São Paulo, também serão mostradas no acesso realizado do Rio de Janeiro.

Escrita Monotônica

Em muitos casos é importante que as operações de escrita sejam propagadas na ordem correta para todas as réplicas do sistema de armazenamento de dados. Neste sistema a escrita é controlada de maneira que nenhuma operação de escrita em um dado elemento x ocorra fora de ordem. Nem que para isso o processo de escrita tenha que aguardar um outro processo de escrita completar. Note que este sistema consideramos que uma operação de escrita é controlada pelo processo e não pelo sistema inteiro.

Leitura das suas escritas

Neste modelo uma atualização de dados, realizadas por um processo, sempre será vista por uma leitura daquele processo. Ou seja, uma operação de escrita sempre deve ser completada antes de uma chamada de leitura do mesmo processo, não importa onde esta chamada de leitura tenha sido realizada.
A falta da leitura das suas escritas pode ser notada quando estamos editando um documento na web e fazemos uma pré visualização daquele documento, muitas vezes no navegador cacheia esta página e quando tentamos visualizar outras modificações, realizadas após o cacheamento da página, o navegador mostra a versão antiga. O modelo de leitura das suas escritas garante que este comportamento não acontecerá.

Escrita após a leitura

Neste modelo de consistência focado no cliente, toda operação de atualização dos dados será realizado em uma cópia do valor da última leitura realizada pelo processo. Por exemplo, imagine que um processo A leu uma determinada linha de um container de dados da tabela Usuário. Qualquer atualização realizada na tabela de usuário será realizada sobre o último valor lido da tabela de usuários por aquele processo.

Administração de réplica

A escolha de quando, onde e por quem as réplicas devem ser colocadas/administradas é uma decisão importante a ser tomada quando estamos planejando sistemas distribuídos. Esta decisão deve ser dividida em dois pontos, o primeiro onde os servidores serão posicionados, onde devemos nos preocupar com a melhor localidade e infra estrutura dos servidores, que armazenarão parte dos nossos dados. E a outra é em quais servidores colocar cada pedaço dos dados. É claro que primeiro deve-se estabelecer a localização dos servidores, para depois tomar a decisão de qual conteúdo cada um deles armazenará.

Localização dos servidores de réplica

Este é mais um problema de administração e comercial, do que um problema de otimização. Entretanto monitoramento da rede e analise dos clientes é um fator importante para ajudar a tomar decisões.
Existem várias formas de se determinar a melhor localização de um servidor, porém muitas delas são baseadas em cálculos heurísticos. As distâncias entre as máquinas podem ser baseadas em largura de banda e latência, e uma das soluções é selecionar o servidor onde a distância média entre ele e os seus clientes seja menor.
O grande problema destes algoritmos são que eles são computacionalmente caros, a complexidade deles é O(N^2) ou seja, o crescimento dos nós N da sua rede, provoca um aumento de tempo computacional deste algoritmo exponencialmente.
Um algoritmo de localização de servidores de réplica foi desenvolvido como um método onde as réplicas podem ser facilmente identificadas. A ideia deste método é identificar os maiores clusters de uma rede e determinar um nó destes clusters como uma réplica. Para identificar estes clusters, a rede é dividida em células, e as células mais densas são escolhidas para se colocar os servidores de réplica.
A escolha do tamanho da célula é um fator muito importante neste algoritmo, uma vez que ao escolhermos uma célula muito pequena, ela terá muitos nós e muitas réplicas por região, e ao escolher uma célula muito grande, ela terá uma réplica para mais de uma região. Para determinar o tamanho ideal das células podemos utilizar um algoritmo que computa a distância entre os nós através do tempo que eles demoram para se comunicar. Experimentos mostraram que colocar réplicas nos 20 melhores lugares para uma rede de 64.000 nós é aproximadamente 50.000 vezes mais rápido, com isso este tipo de replicação pode ser feito em tempo real.

Réplica permanente

Réplicas permanentes são as réplicas geralmente imutáveis, que ficam permanentemente disponíveis e na maioria dos casos o número das réplicas permanentes são bem pequenos.
Considerando um exemplo de um website, onde os seus arquivos são distribuídos por um número limitado de servidores web. Existem duas maneiras de se distribuir estas réplicas, na primeira delas os dados são copiados em um número limitado de servidores dentro de uma mesma localização e as requisições serão distribuídas por um roteador round-robin.
A segunda maneira de se distribuir um website é chamada de espelhamento. Neste caso os dados do site é copiado por um número limitado de servidores espalhados pela internet. Na maioria dos casos o cliente escolherá uma das cópias, geralmente baseando-se em proximidade física, para acessá-la.

Réplicas inicializadas pelo servidor

Diferente das réplicas permanentes, as réplicas inicializadas pelos servidores são réplicas mirando a performance as quais são criadas pelo administrador do armazenamento de dados. Considerando o exemplo de um website, as suas réplicas podem estar todas em um datacenter localizado em São Paulo e isto pode ser, na maioria das vezes, suficiente para termos uma performance aceitável. Porém, por algum motivo, podemos ter um grande número de requisições de uma outra localidade, como Curitiba, e neste caso o servidor pode escolher colocar cópias dos arquivos físicos do site, em um datacenter de Curitiba, afim de reduzir o tempo gasto por estas requisições para pegar este tipo de arquivo.

Réplica inicializada pelo cliente

Estas réplicas, geralmente conhecidas como cache de cliente, são cópias temporárias de alguns arquivos, utilizadas para armazenar dados que foram baixados recentemente.
Por exemplo, quando entramos em um website, algumas informações podem ser armazenadas localmente, para evitar tráfego no futuro, como a imagem do logotipo daquele site. Tendo ela em cache local, ao entrarmos a próxima vez, não será necessário baixar novamente esta imagem.
O grande problema deste tipo de armazenamento é manter as cópias atualizadas, por isso este tipo de cache deve ter um determinado tempo de vida, para prevenir que as informações fiquem desatualizadas por muito tempo.

Replicação de Conteúdo

A administração de uma réplica deve tratar da propagação do conteúdo atualizado aos servidores de réplica.

Estado vs Operações

Um ponto importante a ser analisado é o que realmente deverá ser propagado e basicamente existem três opções.
  1. Propagar apenas uma notificação de conteúdo
  2. Transferir dados de uma cópia para outra
  3. Propagar as operações de atualização para as outras cópias
Propagar a notificação de conteúdo é o que os protocolos de invalidação realizam. Nestes protocolos as cópias recebem a informação de que os dados que eles contém estão desatualizados. Estas notificações podem conter especificações de quais partes dos dados estão desatualizadas. Quando uma informação é requisitada em uma réplica ela primeiro checa se os dados que ela contém estão atualizados, caso eles não estejam antes de enviar uma resposta a réplica cuidará de atualizar os seus dados.
A grande vantagem destes protocolos é a baixa utilização da rede, já que a única informação que deverá ser propagada é quais dados não estão mais válidos.
Considerando um caso onde muitas atualizações são realizadas e poucas leituras são feitas. Considerando que toas as atualizações são replicadas instantaneamente. Neste caso, podemos ter mais de uma atualização entre duas operações de leitura, ou seja uma das atualizações foi enviada sem ser lida, gerando um desperdício de rede e processamento.
Transferir os dados de atualização de uma cópia para outra é a segunda alternativa e ela é bem útil quando a taxa de leitura é muito maior que a taxa de leitura, pois neste caso a chance da propagação de uma atualização ser inútil é bem pequena.
A terceira alternativa é não transferir nenhum dado de atualização, porém dizer para as réplicas quais operações de atualização ela deve realizar, enviando apenas os parâmetros da alteração. Este parâmetro também é conhecido como replicação ativa. O grande beneficio desta alternativa é que as atualizações podem ser replicadas com o mínimo uso da rede, porém estas operações de atualização podem ser bem complexas gerando uma dificuldade de administração das réplicas.

Protocolo de recebimento vs envio

Um outro problema de design é como as atualizações são enviadas ou requisitadas, em um protocolo baseado em atualizações enviadas, ou também conhecidas como protocolos de servidor. As atualizações são enviadas para as réplicas sem que elas peçam para serem atualizadas.
O protocolo de envio de atualizações são utilizados quando um alto grau de consistência é necessário, já que as atualizações são propagadas pelas réplicas sem a necessidade de consulta.
Uma das desvantagens do protocolo de envio é que ele deve conhecer todos os seus clientes, já que é o servidor que dispara as atualizações e como já vimos anteriormente o armazenamento da lista de todos os pontos de uma rede não é simples de se fazer.
Já um protocolo de recebimento, o cliente enviará uma mensagem requisitando as últimas atualizações de uma determinada parte do armazenamento.

Unicast vs multicast

Relacionado ao protocolo de envio e recebimento temos a decisão de como será realizada a propagação das mensagens.
Com a propagação via unicast, quando um servidor deve enviar uma mensagem para múltiplos servidores, ela será enviada uma mensagem para cada máquina, multiplicando-se o número de mensagens necessário para realizar a replicação.
No caso do multicast a rede cuidará de dissipar a mensagem a todos os recebedores. Com isso ele se integra muito bem com o protocolo de envio de mensagem.

Protocolo de Consistência

Até agora vimos modelos de consistência, aqui vamos nos concentrar na implementação destes modelos focando nos protocolos de consistência. Um protocolo de consistência descreve a implementação de um modelo de consistência.

Consistência contínua

Para implementar a consistência contínua, um número de protocolos de consistência foi criado.

Desvio numérico limitado

Considerando nas escritas de um determinado item de dados X. Cada operação de escrita no dado X, terá um peso, que será determinado pelo valor numérico de X, esta operação será submetida a uma das cópias, e neste caso este servidor será considerado a origem da operação de escrita. Esta operação de escrita será propagada e a utilização de um protocolo de epidemia vai espalhar estas informações rapidamente. 
Todas as operações de escrita que foram realizadas são armazenadas em um log em cada réplica. O objetivo deste protocolo é manter o valor de cada réplica, em um determinado tempo não deve desviar mais que um determinado delta (valor do desvio numérico). Quando um servidor X nota que um outro servidor Y não esteja realizando as operações de escrita da maneira correta (valor da diferença é maior que o delta) ele submete a sua própria lista de alterações para serem realizadas no servidor Y. Desta maneira o sistema consegue manter todos os valores dentro de um determinado delta.

Valor de desvio staleness

Existem muitas formas de se manter o desvio staleness dentro de um determinado valor. Uma delas é fazer com que o servidor X mantenha um relógio de vetor de tempo real, onde este servidor veja todas as operações de escrita que foram submetidas a um servidor Y até um determinado período de tempo. Para este caso consideramos que todas as operações de escritas possuem um atributo de tempo associada a elas.
Se o relógio das réplicas estiverem dessincronizados, uma maneira aceitável de controlar este problema é aplicar todas as alterações realizadas após o período da diferença entre os relógios do servidor A ao B. Suponha que o relógio do Servidor A esteja 10 minutos adiantado, comparando-se com o relógio do servidor B. Neste caso o servidor B deverá realizar todas as operações de atualização que foram realizadas no servidor A, contando o horário local do relógio de B, no servidor A, mais os 10 minutos da diferença do relógio destes servidores.

Limite de desvio de ordem

Relembre que desvios de ordem são gerados em casos onde cada réplica recebe uma operação de atualização ao mesmo tempo. Neste caso cada réplica terá uma fila local das operações de escrita que devem ser aplicadas a sua cópia, porém a ordem de aplicação destas operações ainda devem ser determinada. O desvio de ordem é determinado pelo tamanho desta fila.
Neste caso, determinar quando a consistência de ordem deve ser reforçada é simples, quando o tamanho da fila de escrita extrapolar um determinado valor máximo. Neste ponto o servidor não aceitará mais operações de escrita, e tentará comitar as operações de escrita negociando a ordem em que elas devem ser aplicadas, com os outros servidores. Existem muitas formas que esta ordem pode ser determinada, uma delas é baseada em atributo de índice primário, ou no quorum.

Protocolos baseados atributo de índice primário

No caso de consistência sequencial, os protocolos baseados no atributo de índice prevalecem, nestes protocolos cada item armazenado, possui um índice de primarieadade, o qual será responsável por ordenar as operações de escrita

Protocolo de escrita remota

O protocolo primário mais simples existente é aquele conhecido como protocolo de backup, neste protocolo as operações de escrita serão encaminhadas para um único servidor e as operações de leitura podem ser processadas localmente. Neste protocolo, quando temos uma operação de escrita, ela será realizada localmente e depois esta operação será enviada ao servidor central, o qual enviará uma mensagem para todas as réplicas e assim que todas as réplicas forem atualizadas o processo de escrita inicial é avisado, o que caracteriza uma consistência sequencial já que todos os processos veem as operações de escrita na mesma ordem, não importa qual réplica seja consultada.
Este tipo de operação de escrita pode demorar muito tempo, já que o processo de escrita fica esperando todas as cópias serem atualizadas.

Protocolo de escrita local

Uma variação do protocolo descrito anteriormente acontece quando um processo quer realizar uma operação de escrita em um dado elemento x, ele procura a cópia primária daquele elemento, copia o seu valor para a réplica local e realiza a atualização nele. Com isto é possível realizar múltiplas operações de escrita ao mesmo tempo, já que a operação de escrita é realizada localmente, assim como as operações de leitura. Cada operação de escrita deverá ser copiada para as réplicas assim que a alteração da réplica primária finaliza, o faz com que o processo de atualização seja não bloqueante, já que ele não precisa esperar todas as réplicas se atualizarem.
Este tipo de protocolo também pode ser utilizado em sistemas móveis e para isso ele deve assumir o papel de cópia primária para todos os elementos que ele deseja alterar quando desconectado, com isso o sistema altera os dados localmente e assim que ele se conecta a rede ele poderá atualizar as réplicas deixando a base em um estado consistente novamente.
Uma última variação deste tipo de protocolo são utilizados em sistemas de arquivo distribuídos, o que neste caso habilita alterações sequenciais localmente e assim que estas operações finalizam elas são propagadas para as réplicas, com isso a velocidade de escrita deste protocolo é bem alta.

Protocolo de escrita replicada

Neste protocolo as operações de escrita podem ser enviadas para múltiplas réplicas, ao invés de somente uma, como acontece no procolo baseado em primariedade. Uma distinção pode ser feita entre a replicação ativa, onde as operações de atualização são enviadas a todas as réplicas, e os protocolos de consistência que são baseados em votação da maioria.

Replicação ativa

Na replicação ativa, cada réplica possui um processo associado que carrega as operações de atualização. Neste caso cada operação de escrita é enviada a todas as réplicas.
Um problema da replicação ativa é que estas operações deverão ser enviadas na mesma ordem para todas as réplicas, com isso um mecanismo de multicast totalmente ordenado é necessário. Existem várias formas de se implementar esta ordenação, todas elas são baseados no índice de primariedade de um dado

Protocolo baseado em quorum

Um exemplo de como este algoritmo funciona é em um sistema de arquivos distribuídos, supondo que um arquivo está replicado em N servidores. Pode-se estabelecer uma regra para atualização onde para atualizar um determinado arquivo, o cliente deverá contactar mais que a metade dos servidores e eles devem aceitar a atualização daquele arquivo. Assim que eles aceitam o arquivo é alterado para uma nova versão, que será associada ao novo arquivo. Esta versão será utilizada para determinar se o arquivo é o mesmo em todas as réplicas.
Para ler um arquivo deste sistema, o cliente também deverá contactar a maioria dos servidores e perguntar pela versão do arquivo, se todas as versões forem a mesma a leitura poderá ser realizada.

Protocolo de coerência de cache

Como os caches são armazenados nos clientes, ao invés dos servidores, a ideia de sincronizá-los para manter a sua coerência, parece um pouco diferente do que vimos até agora, mas não é.
A primeira solução encontrada foi validar a consistência do dado utilizado, neste caso assim que uma transação é iniciada, o cache vai verificar, possivelmente no servidor, se o dado utilizado está consistente, e neste caso a transação não pode continuar enquanto esta consistência não é verificada.
Uma segunda forma de fazer isto, é deixar a transação continuar, ou seja assume-se que o dado é consistente quando a transação inicia, enquanto isso a consistência do dado é checada, e caso o dado seja inconsistente a transação será abortada.
O terceiro caso esta validação acontece somente quando a transação é comitada, neste caso todas as operações são realizadas e depois que todo o trabalho é feito o dado acessado é checado pela consistência e caso os dados estiverem atualizados a transação é abortada.
Uma outra preocupação destes protocolos de cache é a estratégia de coerência, que irá determinar como os dados do cache serão mantidos consistentes com as cópias dos servidores. A maneira mais simples de se resolver este problema é desabilitar o cache de dados compartilhados. Os dados compartilhados ficam somente no servidor e a consistência destes dados é mantida utilizando-se um dos protocolos apresentados até agora. Neste caso somente os dados privados são passíveis de cache.
Quando os dados compartilhados podem ser cacheados, existem duas maneiras de forçar a coerência do cache. Na primeira delas, o servidor de cache irá enviar uma mensagem de invalidação para todos os caches, assim que um dado for modificado. E a segunda é simplesmente propagar a atualização.
Por último devemos considerar o que acontece quando um processo altera um dado cacheado. Quando caches somente de leitura são utilizados, as operações de atualização serão realizadas somente no servidor, que as enviarão para os servidores de cache através de algum protocolo de distribuição. Na maioria dos casos, um protocolo de recebimento é utilizado, ou seja o cache detecta que os dados estão desatualizados e requisitam uma atualização do cliente.
Uma alternativa é permitir que os caches atualizem os dados e estas atualizações são enviadas para os servidores.

Nenhum comentário:

Postar um comentário