Catálogo de padrões de sistemas distribuídos #5
Olá!
Esse texto faz parte de uma série. Você encontra os textos anteriores nos links abaixo:
Data Replication — Parte 1
Data Replication — Parte 2
Data Replication — Parte 3
Time Management — Parte 4
Neste texto, vou comentar sobre padrões relacionados ao gerenciamento dos clusters.
Lease
Em contextos distribuídos, falhas podem e irão ocorrer. Portanto, quando um nó solicita acesso a algum recurso, é necessário controlar quanto tempo a autorização de uso é permitida, quase como se fosse um aluguel (daí o nome).
A forma mais simples de implementar isso é: quando um cluster tenta acessar algum recurso, é criado junto uma estrutura de dados que contempla qual recurso e qual o tempo de expiração do acesso (também chamado de Time-To-Live, ou TTL).
É de responsabilidade do próprio nó renovar o lease de tempos em tempos. Caso ele sofra alguma indisponibilidade, a renovação não acontecerá automaticamente. Nesses casos, o TTL expira e o recurso é liberado para uso por outros nós.
Sem um mecanismo similar, qualquer indisponibilidade de nós poderia travar o cluster inteiro, devido aos recursos em uso.
Gossip Dissemination
No funcionamento normal de um cluster, é necessário que os nós comuniquem seus metadados de tempos em tempos para os outros componentes, para que o ecossistema opere corretamente como um todo.
Porém, quando os clusters começam a ficar muito grandes, essa comunicação entre os nós pode consumir praticamente toda a largura de banda da rede.
Nesses cenários, o sistema distribuído não executa sua função principal corretamente por falta de recursos de rede disponíveis.
Esse padrão resolve isso. Em intervalos regulares (1 segundo, por exemplo), cada nó escolhe um nó aleatório do cluster e envia seus metadados para ele.
Em termos gráficos, a comunicação ocorreria de uma forma parecida com esta:
Se você leu isso atentamente e conhece um pouco de probabilidade, deve ter pensado que a aleatoriedade da comunicação não necessariamente fará todos se comunicarem entre si a cada intervalo.
E sim, é isso mesmo. Porém, como os intervalos são curtos, ocorre uma consistência eventual na comunicação dos nós. O que costuma ser um pequeno incoveniente se comparado a floodar a rede interna do cluster.
Emergent Leader
Na maioria dos sistemas distribuídos, geralmente os nós são iguais entre si.
O problema ocorre quando é necessário escolher uma máquina para ser a coordenadora das outras por algum motivo.
Para escolher novos líderes (igual ao mencionado neste artigo), geralmente é requerido um critério específico, como o Majority Quorum ou similares.
Uma técnica simples para evitar essa complexidade é este padrão: a máquina com o uptime maior é escolhida como líder automaticamente a cada necessidade de se definir um.
Com esse critério, não é necessário escolher um novo líder através de algoritmos de consenso. Lembrando que é um padrão mais frágil de uma maneira geral do que algoritmos próprios para a escolha de líderes (que possuem mecanismo de tolerância a falhas por definição).
Consistent Core
Conforme o número de máquinas em um cluster aumenta, ações comuns de gerenciamento desse tipo de sistema se tornam mais frequentes, como decidir partições de dados, gerenciamento de permissões e similares. Para que o cluster funcione corretamente, algoritmos de consenso com tolerância a falhas para a escolha de líderes são usados.
Porém, conforme o número de máquinas aumenta, o throughput do cluster decai como um todo, devido ao overhead desse tipo de mecanismo.
Para resolver isso, a ideia é usar o príncipio do dividir para conquistar. Em um cluster grande, de, por exemplo, 20 máquinas, de 3 a 5 podem ser usadas como um núcleo de gerenciamento.
Esse conjunto menor de máquinas é responsável por realizar operações que requerem mais consistência e linearidade do que as demais operações. Lembrando que esse tipo de operação depende do sistema em questão. O core não cuidaria de operações que são críticas na visão dos clientes e sim, na visão do cluster em si.
Em uma representação gráfica, temos:
Eu descobri o que era Zab pesquisando para este artigo. É um algoritmo de consenso usado no Zookeeper (que também é usado no Kafka), similar ao Paxos e o Raft, que já foram mencionados anteriormente. Mais detalhes sobre ele aqui.
State Watch
Geralmente, é do interesse dos clientes serem notificados caso algum tipo de informação passe por atualizações no cluster. É um cenário relativamente comum.
A forma errada de fazer isso é deixar o cliente ficar fazendo pooling no servidor, sobrecarregando o cluster no processo, podendo até causar um DDoS.
Esse padrão simplesmente inverte a responsabilidade da notificação: o cliente que escolhe receber atualizações sobre um determinado recurso e o cluster se encarrega de avisá-lo quando algo ocorrer (as formas de se fazer isso veremos no próximo texto dessa série).
Eu consigo ver similaridade desse padrão com técnicas de outros contextos dentro da computação, como: Tell, Don’t Ask Principle (Orientação a Objetos), Webhooks (APIs) e Callbacks (C++, Javascript).
Lembrando que é necessário um certo cuidado em como essa notificação é enviada, pois pode gerar gargalos no cluster do mesmo jeito.
Espero que esse texto tenha sido útil para você de alguma forma.
Até!
Você gostou do conteúdo e gostaria de fazer mentoria comigo? Clique aqui e descubra como.