Ignite Service Grid - Reinicializar

Em 26 de fevereiro, realizamos um encontro Apache Ignite GreenSource, onde colaboradores do projeto de código aberto falaram Apache IgniteName. Um acontecimento importante na vida desta comunidade foi a reestruturação da componente Ignite Grade de Serviço, que permite implantar microsserviços personalizados diretamente em um cluster Ignite. Ele falou sobre esse processo difícil no encontro Vyacheslav Daradur, engenheiro de software e colaborador do Apache Ignite há mais de dois anos.

Ignite Service Grid - Reinicializar

Vamos começar com o que é o Apache Ignite em geral. Este é um banco de dados que é um armazenamento distribuído de Chave/Valor com suporte para SQL, transacionalidade e cache. Além disso, o Ignite permite implantar serviços personalizados diretamente em um cluster Ignite. O desenvolvedor tem acesso a todas as ferramentas que o Ignite fornece - estruturas de dados distribuídas, mensagens, streaming, computação e grade de dados. Por exemplo, ao usar o Data Grid, o problema de administrar uma infraestrutura separada para armazenamento de dados e, como consequência, os custos indiretos resultantes desaparecem.

Ignite Service Grid - Reinicializar

Usando a API Service Grid, você pode implantar um serviço simplesmente especificando o esquema de implantação e, consequentemente, o próprio serviço na configuração.

Normalmente, um esquema de implementação é uma indicação do número de instâncias que devem ser implementadas em nós de cluster. Existem dois esquemas de implantação típicos. O primeiro é Cluster Singleton: a qualquer momento, é garantido que uma instância de um serviço de usuário esteja disponível no cluster. O segundo é o Node Singleton: uma instância do serviço é implementada em cada nó do cluster.

Ignite Service Grid - Reinicializar

O usuário também pode especificar o número de instâncias de serviço em todo o cluster e definir um predicado para filtrar nós adequados. Neste cenário, o próprio Service Grid calculará a distribuição ideal para implantação de serviços.

Além disso, existe um recurso chamado Affinity Service. Afinidade é uma função que define o relacionamento das chaves com as partições e o relacionamento das partes com os nós na topologia. Usando a chave, você pode determinar o nó primário no qual os dados são armazenados. Dessa forma, você pode associar seu próprio serviço a um cache de função de chave e afinidade. Se a função de afinidade for alterada, ocorrerá a redistribuição automática. Desta forma, o serviço estará sempre localizado próximo dos dados que necessita manipular e, consequentemente, reduzirá o overhead de acesso à informação. Este esquema pode ser chamado de um tipo de computação colocada.

Agora que descobrimos qual é a beleza do Service Grid, vamos falar sobre sua história de desenvolvimento.

O que era antes

A implementação anterior do Service Grid foi baseada no cache do sistema replicado transacional do Ignite. A palavra “cache” no Ignite refere-se ao armazenamento. Ou seja, não se trata de algo temporário, como você pode imaginar. Apesar do cache ser replicado e cada nó conter todo o conjunto de dados, dentro do cache ele possui uma representação particionada. Isso se deve à otimização do armazenamento.

Ignite Service Grid - Reinicializar

O que aconteceu quando o usuário quis implantar o serviço?

  • Todos os nós do cluster se inscreveram para atualizar dados no armazenamento usando o mecanismo integrado de consulta contínua.
  • O nó inicial, sob uma transação de leitura confirmada, fez um registro no banco de dados que continha a configuração do serviço, incluindo a instância serializada.
  • Ao ser notificado de uma nova entrada, o coordenador calculava a distribuição com base na configuração. O objeto resultante foi gravado de volta no banco de dados.
  • Se um nó fizesse parte da distribuição, o coordenador teria que implantá-lo.

O que não nos convinha

Em algum momento chegamos à conclusão: não é assim que se trabalha com serviços. Houve vários motivos.

Se ocorreu algum erro durante a implantação, ele só poderá ser descoberto nos logs do nó onde tudo aconteceu. Havia apenas implantação assíncrona, portanto, após devolver o controle ao usuário a partir do método de implantação, era necessário algum tempo adicional para iniciar o serviço - e durante esse tempo o usuário não conseguia controlar nada. Para desenvolver ainda mais o Service Grid, criar novas funcionalidades, atrair novos usuários e facilitar a vida de todos, algo precisa mudar.

Ao projetar o novo Service Grid, queríamos, em primeiro lugar, fornecer uma garantia de implantação síncrona: assim que o usuário retornasse o controle da API, ele poderia usar imediatamente os serviços. Eu também queria dar ao iniciador a capacidade de lidar com erros de implantação.

Além disso, queria simplificar a implementação, nomeadamente, afastar-me das transações e do reequilíbrio. Apesar do cache ser replicado e não haver balanceamento, surgiram problemas durante uma implantação grande com muitos nós. Quando a topologia muda, os nós precisam trocar informações e, com uma implantação grande, esses dados podem pesar muito.

Quando a topologia estava instável, o coordenador precisava recalcular a distribuição dos serviços. E, em geral, quando você precisa trabalhar com transações em uma topologia instável, isso pode levar a erros difíceis de prever.

Problemas

O que são mudanças globais sem problemas associados? A primeira delas foi uma mudança na topologia. Você precisa entender que a qualquer momento, mesmo no momento da implantação do serviço, um nó pode entrar ou sair do cluster. Além disso, se no momento da implantação o nó ingressar no cluster, será necessário transferir de forma consistente todas as informações sobre os serviços para o novo nó. E não estamos falando apenas do que já foi implantado, mas também de implantações atuais e futuras.

Este é apenas um dos problemas que podem ser reunidos em uma lista separada:

  • Como implantar serviços configurados estaticamente na inicialização do nó?
  • Saindo de um nó do cluster – o que fazer se o nó hospedasse serviços?
  • O que fazer se o coordenador mudou?
  • O que fazer se o cliente se reconectar ao cluster?
  • As solicitações de ativação/desativação precisam ser processadas e como?
  • E se eles pedissem a destruição do cache e tivéssemos serviços de afinidade vinculados a isso?

E isso está longe de tudo.

Solução

Como meta, escolhemos a abordagem Event Driven com a implementação da comunicação do processo por meio de mensagens. O Ignite já implementa dois componentes que permitem que os nós encaminhem mensagens entre si - spi de comunicação e spi de descoberta.

Ignite Service Grid - Reinicializar

Communication-spi permite que os nós se comuniquem diretamente e encaminhem mensagens. É adequado para enviar grandes quantidades de dados. O Discovery-spi permite enviar uma mensagem a todos os nós do cluster. Na implementação padrão, isso é feito usando uma topologia em anel. Também há integração com Zookeeper, neste caso é utilizada uma topologia em estrela. Outro ponto importante que vale a pena notar é que o Discovery-spi oferece garantias de que a mensagem será definitivamente entregue na ordem correta para todos os nós.

Vejamos o protocolo de implantação. Todas as solicitações do usuário para implantação e cancelamento de implantação são enviadas por meio do Discovery-spi. Isto dá o seguinte garantia:

  • A solicitação será recebida por todos os nós do cluster. Isso permitirá que a solicitação continue sendo processada quando o coordenador mudar. Isso também significa que em uma mensagem cada nó terá todos os metadados necessários, como a configuração do serviço e sua instância serializada.
  • A ordem estrita de entrega de mensagens ajuda a resolver conflitos de configuração e solicitações concorrentes.
  • Como a entrada do nó na topologia também é processada via Discovery-spi, o novo nó receberá todos os dados necessários para trabalhar com os serviços.

Quando uma solicitação é recebida, os nós do cluster a validam e criam tarefas de processamento. Essas tarefas são enfileiradas e processadas em outro thread por um trabalhador separado. Ele é implementado dessa maneira porque a implantação pode levar um tempo significativo e atrasar intoleravelmente o caro fluxo de descoberta.

Todas as solicitações da fila são processadas pelo gerenciador de implementação. Possui um trabalhador especial que extrai uma tarefa desta fila e a inicializa para iniciar a implantação. Depois disso, ocorrem as seguintes ações:

  1. Cada nó calcula a distribuição de forma independente graças a uma nova função de atribuição determinística.
  2. Os nós geram uma mensagem com os resultados da implantação e a enviam ao coordenador.
  3. O coordenador agrega todas as mensagens e gera o resultado de todo o processo de implantação, que é enviado via discovery-spi para todos os nós do cluster.
  4. Quando o resultado é recebido, o processo de implantação termina, após o qual a tarefa é removida da fila.

Ignite Service Grid - Reinicializar
Novo design orientado a eventos: org.apache.ignite.internal.processors.service.IgniteServiceProcessor.java

Se ocorrer um erro durante a implantação, o nó inclui imediatamente esse erro em uma mensagem que envia ao coordenador. Após a agregação da mensagem, o coordenador terá informações sobre todos os erros durante a implantação e enviará esta mensagem via discovery-spi. As informações de erro estarão disponíveis em qualquer nó do cluster.

Todos os eventos importantes no Service Grid são processados ​​usando este algoritmo operacional. Por exemplo, alterar a topologia também é uma mensagem via discovery-spi. E em geral, quando comparado com o que era antes, o protocolo revelou-se bastante leve e confiável. O suficiente para lidar com qualquer situação durante a implantação.

O que acontecerá depois?

Agora sobre os planos. Qualquer mudança importante no projeto Ignite é concluída como uma iniciativa de melhoria do Ignite, chamada IEP. O redesenho do Service Grid também conta com um IEP - PEI #17 com o título zombeteiro “Troca de óleo na rede de serviços”. Mas, na verdade, não trocamos o óleo do motor, mas sim todo o motor.

Dividimos as tarefas do IEP em 2 fases. A primeira é uma fase importante, que consiste em retrabalhar o protocolo de implantação. Já está incluso no master, você pode experimentar o novo Service Grid, que aparecerá na versão 2.8. A segunda fase inclui muitas outras tarefas:

  • Reimplantação a quente
  • Versionamento de serviço
  • Maior tolerância a falhas
  • Cliente magro
  • Ferramentas para monitorar e calcular diversas métricas

Finalmente, podemos aconselhá-lo sobre o Service Grid para a construção de sistemas tolerantes a falhas e de alta disponibilidade. Convidamo-lo também a visitar-nos em lista de desenvolvedores и Lista de usuários compartilhe sua experiência. Sua experiência é muito importante para a comunidade; ela irá ajudá-lo a entender para onde ir em seguida, como desenvolver o componente no futuro.

Fonte: habr.com

Adicionar um comentário