Transação de Dados cover

Transação de Dados

Capítulo 2: Distribuição de dados

10/Oct/2019
8 minutos

Este é o segundo capítulo de uma série sobre transações de dados em sistemas distribuídos. Recomendo a leitura do primeiro capítulo para uma introdução aos conceitos de transações de dados e a escala ACID/BASE e consistência eventual. Mas, se tiver com preguiça de clicar no link, fica por aqui mesmo.

Não vou te julgar. Muito. …

Base de dados em sistemas distribuídos

Nas glamorosas aplicações distribuídas, ao invés de tentar gerenciar todos os dados de todos os fluxos de todos os domínios com um único SGBD (Sistemas Gerenciadores de Banco de Dados), é usual encontrarmos ecossistemas nos quais cada aplicação possui sua própria base de dados.

Essa estratégia é bastante comum no mundo dos microsserviços, enquanto o costume de possuir apenas uma base de dados é evidenciado nas aplicações monolíticas e, consequentemente, não distribuídas.

Ado, a ado, cada base no seu quadrado

Não necessariamente um servidor para cada base. Existem alternativas: tabelas privadas por serviço, schemas por serviço e base de dados por serviço.

Convém criar obstáculos que reforcem a proteção e a modularidade. Você sabe, os desenvolvedores não resistem a tentação de burlar qualquer proteção para acessar o conteúdo diretamente.

Tomando uma plataforma e-commerce como exemplo — porque todo exemplo exige um e-commerce — a plataforma lida com muito tipos de dados: endereços, estoques, preços, pagamentos, pedidos, etc. Cada tipo tem uma exigência específica: prioridades, desempenhos, valores, consistências, etc.

Essa prática propicia a cada aplicação a oportunidade de atuar como uma camada de negócio antes da persistência, possibilitando o tratamento da informação com as regras do domínio.

Além dessa possibilidade, cito outras boas razões para criar banco de dados individuais para cada serviço: melhor encapsulamento, disponibilidade individual, facilidade de administração, possibilidade de agendamentos periódicos personalizados, escala sob demanda, manutenção apropriada, recuperação de dados, otimização de desempenho, menos conversões e formatações de valores, capacidade de planejamento, etc_._

Algumas dessas vantagens são muito importantes, justificando, por si só, a adoção dessa estratégia. Outras, nem tanto e só fazem volume.

Existem ainda mais, mas vou parar por aqui, porque já deu, né? Você já captou o espírito dos meus argumentos.

Persistência poliglota

Aliás, vou citar apenas uma: persistência poliglota.

De modo similar ao fluxo poliglota e à [programação poliglota] (https://searchsoftwarequality. techtarget.com/definition/polyglot-programming), o poliglotismo na persistência afirma que, para cada cenário, é melhor adotar o modelo SGBD mais apropriado, baseado nas necessidades e em como o dado é manipulado.

Significa escolher a melhor ferramenta para determinado caso. Mesmo que acarrete em múltiplas tecnologias de persistência compartilhando um ecossistema.

Não rola química

Para cada uma desses SGBDs, individualmente, os acrônimos ACID/BASE permanecem fazendo sentido. No entanto, ao observarmos pela ótica da distribuição de dados, o prisma ácido/básico é irrelevante.

Possuir todos SGBDs ácidos não é suficiente para que haja a garantia que todas as transações entre eles sejam ácidas também.

O que é lastimável. Eu realmente gostava dos enxertos inspirados na química inorgânica do texto anterior.

Guerra pela exibição de dados

Ao passo que SGBDs são sobre expor os dados e torná-los úteis, serviços são, paradoxalmente, sobre escondê-los para desacoplar. São dois gladiadores do século XXI em lados opostos, gentilmente se trucidando pela exposição dos dados.

No mundo dos sonhos, conseguiríamos enjaular o sistemas em microsserviços perfeitamente auto-contidos em suas celas octogonais e não haveria digladiação e pancadaria. Transações entre serviços e batalhas pelos dados não seriam sequer necessárias, frustrando os amantes da violência gratuita.

Mas o buraco é mais embaixo. Na computação distribuída, regras de negócio são baseados nos dados alheios, despirocando os nobres guerreiros e justificando cotoveladas e dedadas no olho, tornando o encapsulamento de dados uma guerra sedenta por sangue, tipo um palmeiras vs. corinthians na época do Edílson Capetinha.

Como transações entre os serviços são necessárias, temos que nos preparar para todos os poréns que a comunicação entre sistemas traz: perdas, reordenamento de pacote, complexidade, confiabilidade, latência…

Resta que nos contentemos e nos preparemos para o pior: berremos, desesperadamente, que torcemos para o santos.

Transações frustradas (nunca aconteceu comigo)

Assim como os chutes do Edilson Capetinha e as performances do Anderson Silva, as transações nem sempre são bem-sucedidas. Mas não estou aqui para julgar ninguém.

A internet é, por definição, estocástica, e partições de rede fazem parte do jogo de incerteza.

Sistemas ficam indisponíveis e pacotes se perdem. Ponto. Entretanto, o sistema distribuído, como um todo, não precisa padecer do mesmo mal.

É válido interpretar as partições de rede como as falhas inerentes ao ambiente distribuído sendo, portanto, termos perfeitamente intercambiáveis no contexto.

Felizmente, a replicação de dados permite a recuperação em momentos de partições de rede e o fornecimento de valores mesmo quando um sistema estiver indisponível ou diante da perda de mensagens, habilitando a tolerância a falhas e escancarando uma possível falta de consistência. Ratificando a reatividade pelo aspecto resiliente do sistema.

De um outro modo, também por meio da replicação, poderíamos tratar as falhas de modo consistente, mas abriríamos mão da disponibilidade fazendo com que nem todas as requisições tenham resposta.

A fascinante replicação permitiria que o Edílson Capetinha errasse consistentemente vários chutes a gol. Que beleza!

No nível de abstração distribuído, o pobre espectro ácido/básico, já limitado por natureza, é deliberadamente ignorado. Tanto por responder pouco sobre o sistema que atua quanto por ignorar as propriedades dos fluxos de dados. Por conta disso, os acrônimos ACID/BASE recebem auxílio de um acrônimo mais fashion e descolado: CAPconsistência, disponibilidade e tolerância a partições; despretensiosamente traduzido do inglês: consistency, availability and partition tolerance.

No capítulo anterior, perguntávamos: “qual o pH adequado para a solução?”. Na o texto corrente, perguntamos: como maximizar a consistência, disponibilidade e a tolerância a falhas?

Com um amargor no peito, antecipo: essa maximização é tão inalcançável quanto o hexa da seleção brasileira de futebol.

Isso é, precisamente — excetuando a parte do hexa — o que diz o teorema CAP.

Teorema CAP

O teorema afirma, categórica e matematicamente, que, uma vez que existem contradições em termos entre os três itens, não é possível maximizá-los simultaneamente. Simplificando:

Consistência, disponibilidade, tolerância a falhas, escolha, no máximo, dois.

Em 2000, Eric Brewer, o mesmo que batizou o acrônimo BASE e a quem dediquei minhas palmas no texto anterior, apresentou sua [palestra] (http://www.cs.berkeley.edu/~brewer/cs262b-2004/PODC-keynote.pdf) à comunidade e introduziu ao mundo o teorema CAP. Aparentemente, ele curtia umas siglas.

Também conhecido como o teorema de Brewer — à la Sherlock Holmes, deduzo que é por conta do sobrenome do autor — relata que existem três requisitos essenciais necessários para o sucesso de um projeto distribuído: consistência, disponibilidade e tolerância a partições:

Essas são definições simples dos três aspectos do teorema. Não dá para ter todos simultaneamente. Dá para ter, no máximo dois e, no mínimo nenhum. Pessoalmente, não vejo muita vantagem na segunda opção.

Existem inúmeros artigos disponíveis que discutem as implicações do teorema no mundo real.

Ignorar essa afirmação pode causar resultados catastróficos que incluem a possibilidade de não alcançar nem disponibilidade, nem consistência e nem tolerância a falhas. “corram para as colinas” ou " distribuam currículos" costumam ser bradados, de maneira retumbante, nessas ocasiões.

As restrições do teorema CAP têm papéis monumentais para SGBDs não relacionais. Eles frequentemente fornecem disponibilidade e tolerância a partições em detrimento da consistência e neutralizando a acidez. Comumente, no movimento NoSQL, as bases de dados suportam maior volumes de dados e escalabilidade.

Escalonamento de serviços

Sem a distribuição, tentávamos eliminar as falhas e atingir a consistência aumentando os recursos computacionais, o que é conhecido como escala-y (vulgarmente: escala vertical ou scale up). É dopar e buffar os atletas em campo.

O generoso mundo distribuído nos permite, também, aumentar a disponibilidade. A escala-x (também conhecida como: escala horizontal ou scale out), determina a quantidade de instâncias. Semelhante a adicionar/retirar jogadores no campo de acordo com o nível do adversário.

Além disso, a distribuição possibilita a otimização da performance através da repartição de dados, ou escala-z (sem alcunhas engraçadinhas para esse termo). Cada base gerencia uma parcela dos dados do mesmo domínio. Uma base para clientes cuja identificação começa com 0-4 e outra para os identificações começando com 5-9? É como a marcação por zona, cada jogador fica responsável por preencher uma região do gramado.

Para representar os escalonamentos tri-dimensionais, recorremos a uma ilustração que põe a escala ACID/BASE e o diagrama do teorema CAP no bolso.

A pintura renascentista se assemelha a uma obra de arte de John Lennon com pinceladas expressivas do Niemeyer:

Independentemente da dimensão do escalonamento, a propriedade de alocar ou desalocar recursos com intuito de atender a demanda é chamada de elasticidade e constitui outro meio importante de se atingir a responsividade, principal valor dos sistemas reativos.

Transações distribuídas

Ao decompor um sistema monolítico em microsserviços, uma transação pode ser dividida em diversas requisições executadas em sequência em serviços distintos. Um processo complexo, com engrenagens sujeitas a falhas e propenso a se tornar extenso e não confiável.

No cenário monolítico, o SGBD gerencia as transações e garante o grau de acidez, mas como manter essas propriedades no mundo distribuído? Não há, por padrão, um coordenador global de transações.

Portanto, a fim de garantir um nível de confiabilidade, ou criamos um coordenador global ou as próprias engrenagens que envolvem os dados transitados devem se auto-gerenciar.

Estratégias de confirmação e contra-medidas devem ser pensadas individualmente para cada fluxo com a finalidade de acatar ou cancelar uma transação, respectivamente.

Para saber mais sobre esses mecanismos e se divertir um pouco, leia a continuação deste post. (Pera que eu ainda estou escrevendo!!)

Este texto serviu de base para um capítulo do meu livro. Se você gostou do texto, considere adquirir o livro.

Já que você tá por aqui, dá uma olhada nesses aqui também: