Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Affinity é um controle que é fornecido principalmente para ajudar a facilitar a transição de aplicativos monolíticos maiores para o mundo da nuvem e microsserviços. Também é usado como uma otimização para melhorar o desempenho dos serviços, embora isso possa ter efeitos colaterais.
Digamos que você esteja trazendo um aplicativo maior, ou que simplesmente não foi projetado com microsserviços em mente, para o Service Fabric (ou qualquer ambiente distribuído). Este tipo de transição é comum. Você começa levantando todo o aplicativo para o ambiente, empacotando-o e certificando-se de que ele está funcionando sem problemas. Então você começa a dividi-lo em diferentes serviços menores que comunicam entre si.
Eventualmente, você pode achar que o aplicativo está enfrentando alguns problemas. As questões geralmente se enquadram em uma destas categorias:
- Alguns componentes X no aplicativo monolítico tinham uma dependência não documentada do componente Y, e você acabou de transformar esses componentes em serviços separados. Como esses serviços agora estão sendo executados em nós diferentes no cluster, eles estão quebrados.
- Esses componentes se comunicam via (pipes nomeados locais | memória compartilhada | arquivos no disco) e eles realmente precisam ser capazes de gravar em um recurso local compartilhado por motivos de desempenho agora. Essa dependência rígida é removida, talvez mais tarde.
- Tudo está bem, mas acontece que esses dois componentes são bastante verbosos e sensíveis ao desempenho. Quando os moveram para serviços separados, o desempenho geral do aplicativo diminuiu ou a latência aumentou. Consequentemente, a aplicação global não está a corresponder às expectativas.
Nestes casos, não queremos perder o nosso trabalho de refatoração e não queremos voltar ao monólito. A última condição pode até ser desejável como uma simples otimização. No entanto, até que possamos redesenhar os componentes para funcionar naturalmente como serviços (ou até que possamos resolver as expectativas de desempenho de outra forma), precisaremos de algum senso de localidade.
O que fazer? Bem, você pode tentar ativar a afinidade.
Como configurar a afinidade
Para configurar a afinidade, você define uma relação de afinidade entre dois serviços diferentes. Você pode pensar em afinidade como "apontar" um serviço para outro e dizer "Este serviço só pode ser executado onde esse serviço está sendo executado". Às vezes, nos referimos à afinidade como uma relação pai/filho (onde você aponta a criança para o pai). O Affinity garante que as réplicas ou instâncias de um serviço sejam colocadas nos mesmos nós que as de outro serviço.
ServiceCorrelationDescription affinityDescription = new ServiceCorrelationDescription();
affinityDescription.Scheme = ServiceCorrelationScheme.Affinity;
affinityDescription.ServiceName = new Uri("fabric:/otherApplication/parentService");
serviceDescription.Correlations.Add(affinityDescription);
await fabricClient.ServiceManager.CreateServiceAsync(serviceDescription);
Observação
Um serviço infantil só pode participar numa única relação de afinidade. Se você queria que a criança fosse afiliada a dois serviços parentais ao mesmo tempo, você tem algumas opções:
- Inverta as relações (faça com que parentService1 e parentService2 apontem para o serviço filho atual) ou
- Designe um dos pais como um hub por convenção e faça com que todos os serviços apontem para esse serviço.
O comportamento de posicionamento resultante no cluster deve ser o mesmo.
Diferentes opções de afinidade
A afinidade é representada através de um dos vários esquemas de correlação e tem dois modos diferentes. O modo mais comum de afinidade é o que chamamos de NonAlignedAffinity. Em NonAlignedAffinity, as réplicas ou instâncias dos diferentes serviços são colocadas nos mesmos nós. O outro modo é AlignedAffinity. Aligned Affinity é útil apenas com serviços com estado. A configuração de dois serviços com estado para terem afinidades alinhadas garante que os primários desses serviços sejam colocados nos mesmos nós. Isso também faz com que cada par de secundários para esses serviços sejam colocados nos mesmos nós. Também é possível (embora menos comum) configurar NonAlignedAffinity para serviços com estado. Para NonAlignedAffinity, as diferentes réplicas dos dois serviços com estado seriam executadas nos mesmos nós, mas as suas primárias poderiam terminar em nós diferentes.
Estado desejado de melhor esforço
Uma relação de afinidade é o melhor esforço. Ele não fornece as mesmas garantias de integração ou confiabilidade que a execução no mesmo processo executável. Os serviços em uma relação de afinidade são entidades fundamentalmente diferentes que podem falhar e ser movidas de forma independente. Uma relação de afinidade também pode se romper, embora essas ruturas sejam temporárias. Por exemplo, as limitações de capacidade podem significar que apenas alguns dos objetos de serviço na relação de afinidade podem caber em um dado nó. Nesses casos, mesmo que exista uma relação de afinidade, ela não pode ser aplicada devido às outras restrições. Se for possível fazê-lo, a violação é automaticamente corrigida mais tarde.
Correntes vs. estrelas
Atualmente, o Gerenciador de Recursos de Cluster não é capaz de modelar cadeias de relações de afinidade. O que isto significa é que um serviço que é uma criança numa relação de afinidade não pode ser pai noutra relação de afinidade. Se você quiser modelar esse tipo de relacionamento, você efetivamente tem que modelá-lo como uma estrela, em vez de uma cadeia. Para passar de uma cadeia para uma estrela, o filho mais inferior seria ligado ao pai do primeiro filho. Dependendo da organização dos seus serviços, poderá ter de o fazer várias vezes. Se não houver um serviço pai natural, talvez seja necessário criar um que sirva como espaço reservado. Dependendo de suas necessidades, você também pode querer examinar Grupos de Aplicativos.
Outra coisa a notar sobre as relações de afinidade hoje é que elas são direcionais por padrão. Isto significa que a regra de afinidade apenas impõe que a criança tenha sido colocada com o progenitor. Não garante que o progenitor esteja localizado com a criança. Portanto, se houver uma violação de afinidade e, para corrigir a violação, por algum motivo não for viável mover o filho para o nó do pai, então, mesmo que mover o pai para o nó do filho corrigisse a violação, o pai não será movido para o nó do filho. Definir a configuração MoveParentToFixAffinityViolation como true removeria a direcionalidade. Também é importante notar que a relação de afinidade não pode ser perfeita ou aplicada instantaneamente, uma vez que diferentes serviços têm ciclos de vida diferentes e podem falhar e mover-se de forma independente. Por exemplo, digamos que o nó principal de repente comuta para outro nó porque ele crashou. O Gerenciador de Recursos de Cluster e o Gerenciador de Failover lidam primeiro com o failover, pois manter os serviços ativos, consistentes e disponíveis é a prioridade. Quando o failover for concluído, a relação de afinidade será interrompida, mas o Gerenciador de Recursos de Cluster achará que está tudo bem até perceber que a criança não está localizada com o pai. Este tipo de verificações são realizadas periodicamente. Mais informações sobre como o Gerenciador de Recursos de Cluster avalia restrições estão disponíveis neste artigo, e este fala mais sobre como configurar a cadência na qual essas restrições são avaliadas.
Suporte de particionamento
A última coisa a notar sobre afinidade é que as relações de afinidade não são suportadas quando o elemento principal é particionado. Serviços pai particionados poderão ser suportados eventualmente, mas atualmente não é permitido.
Próximos passos
- Para obter mais informações sobre como configurar serviços, Saiba mais sobre como configurar serviços
- Para limitar os serviços a um pequeno conjunto de máquinas ou agregar a carga de serviços, use Grupos de Aplicativos