Dimensionamento no Service Fabric

O Azure Service Fabric facilita a criação de aplicativos escalonáveis gerenciando os serviços, partições e réplicas nos nós de um cluster. A execução de muitas cargas de trabalho no mesmo hardware permite a máxima utilização de recursos, mas também oferece flexibilidade em termos de como você escolhe dimensionar suas cargas de trabalho. Este vídeo do Channel 9 descreve como você pode criar aplicativos de microsserviços escaláveis:

O dimensionamento no Service Fabric é realizado de várias maneiras diferentes:

  1. Dimensionamento criando ou removendo instâncias de serviço sem monitoração de estado
  2. Dimensionamento criando ou removendo novos serviços nomeados
  3. Dimensionamento criando ou removendo novas instâncias de aplicativos nomeados
  4. Dimensionamento usando serviços particionados
  5. Dimensionamento adicionando e removendo nós do cluster
  6. Dimensionamento usando métricas do Gerenciador de Recursos de Cluster

Dimensionamento criando ou removendo instâncias de serviço sem monitoração de estado

Uma das maneiras mais simples de dimensionar dentro do Service Fabric funciona com serviços sem monitoração de estado. Ao criar um serviço sem monitoração de estado, você tem a chance de definir um InstanceCountarquivo . InstanceCount Define quantas cópias em execução do código desse serviço são criadas quando o serviço é iniciado. Digamos, por exemplo, que existam 100 nós no cluster. Digamos também que um serviço é criado com um InstanceCount de 10. Durante o tempo de execução, essas 10 cópias em execução do código podem ficar muito ocupadas (ou podem não estar ocupadas o suficiente). Uma maneira de dimensionar essa carga de trabalho é alterar o número de instâncias. Por exemplo, alguma parte do código de monitoramento ou gerenciamento pode alterar o número existente de instâncias para 50 ou 5, dependendo se a carga de trabalho precisa ser dimensionada ou reduzida com base na carga.

C#:

StatelessServiceUpdateDescription updateDescription = new StatelessServiceUpdateDescription(); 
updateDescription.InstanceCount = 50;
await fabricClient.ServiceManager.UpdateServiceAsync(new Uri("fabric:/app/service"), updateDescription);

PowerShell:

Update-ServiceFabricService -Stateless -ServiceName $serviceName -InstanceCount 50

Usando a contagem dinâmica de instâncias

Especificamente para serviços sem monitoração de estado, o Service Fabric oferece uma maneira automática de alterar a contagem de instâncias. Isso permite que o serviço seja dimensionado dinamicamente com o número de nós disponíveis. A maneira de optar por esse comportamento é definir a contagem de instâncias = -1. InstanceCount = -1 é uma instrução para o Service Fabric que diz "Execute este serviço sem estado em cada nó". Se o número de nós mudar, o Service Fabric alterará automaticamente a contagem de instâncias para corresponder, garantindo que o serviço esteja sendo executado em todos os nós válidos.

C#:

StatelessServiceDescription serviceDescription = new StatelessServiceDescription();
//Set other service properties necessary for creation....
serviceDescription.InstanceCount = -1;
await fc.ServiceManager.CreateServiceAsync(serviceDescription);

PowerShell:

New-ServiceFabricService -ApplicationName $applicationName -ServiceName $serviceName -ServiceTypeName $serviceTypeName -Stateless -PartitionSchemeSingleton -InstanceCount "-1"

Dimensionamento criando ou removendo novos serviços nomeados

Uma instância de serviço nomeada é uma instância específica de um tipo de serviço (consulte Ciclo de vida do aplicativo Service Fabric) dentro de alguma instância de aplicativo nomeada no cluster.

Novas instâncias de serviço nomeadas podem ser criadas (ou removidas) à medida que os serviços se tornam mais ou menos ocupados. Isso permite que as solicitações sejam distribuídas por mais instâncias de serviço, geralmente permitindo que a carga nos serviços existentes diminua. Ao criar serviços, o Gerenciador de Recursos de Cluster do Service Fabric coloca os serviços no cluster de forma distribuída. As decisões exatas são regidas pelas métricas no cluster e outras regras de posicionamento. Os serviços podem ser criados de várias maneiras diferentes, mas as mais comuns são por meio de ações administrativas, como alguém chamando New-ServiceFabricService, ou por chamada de CreateServiceAsynccódigo. CreateServiceAsync pode até ser chamado de dentro de outros serviços em execução no cluster.

A criação dinâmica de serviços pode ser usada em todos os tipos de cenários e é um padrão comum. Por exemplo, considere um serviço com monitoração de estado que represente um fluxo de trabalho específico. As chamadas que representam o trabalho vão aparecer para este serviço, e este serviço vai executar as etapas para esse fluxo de trabalho e registrar o progresso.

Como você faria essa escala de serviço em particular? O serviço pode ser multilocatário de alguma forma e aceitar chamadas e iniciar etapas para muitas instâncias diferentes do mesmo fluxo de trabalho de uma só vez. No entanto, isso pode tornar o código mais complexo, já que agora ele tem que se preocupar com muitas instâncias diferentes do mesmo fluxo de trabalho, todas em estágios diferentes e de clientes diferentes. Além disso, lidar com vários fluxos de trabalho ao mesmo tempo não resolve o problema da escala. Isso ocorre porque em algum momento esse serviço consumirá muitos recursos para caber em uma máquina específica. Muitos serviços não criados para esse padrão em primeiro lugar também experimentam dificuldade devido a algum gargalo inerente ou lentidão em seu código. Esses tipos de problemas fazem com que o serviço não funcione tão bem quando o número de fluxos de trabalho simultâneos que ele está rastreando fica maior.

Uma solução é criar uma instância desse serviço para cada instância diferente do fluxo de trabalho que você deseja acompanhar. Esse é um ótimo padrão e funciona independentemente de o serviço ser stateless ou stateful. Para que esse padrão funcione, geralmente há outro serviço que atua como um "Serviço de Gerenciador de Carga de Trabalho". A função deste serviço é receber pedidos e encaminhá-los para outros serviços. O gerente pode criar dinamicamente uma instância do serviço de carga de trabalho quando recebe a mensagem e, em seguida, passar solicitações para esses serviços. O serviço de gerenciamento também pode receber retornos de chamada quando um determinado serviço de fluxo de trabalho conclui seu trabalho. Quando o gerente recebe esses retornos de chamada, ele pode excluir essa instância do serviço de fluxo de trabalho ou deixá-la se mais chamadas forem esperadas.

Versões avançadas desse tipo de gerenciador podem até criar pools dos serviços que ele gerencia. O pool ajuda a garantir que, quando uma nova solicitação chega, ela não precise esperar que o serviço funcione. Em vez disso, o gerente pode simplesmente escolher um serviço de fluxo de trabalho que não esteja ocupado no momento do pool ou rotear aleatoriamente. Manter um pool de serviços disponíveis torna o tratamento de novas solicitações mais rápido, já que é menos provável que a solicitação tenha que esperar que um novo serviço seja gerado. A criação de novos serviços é rápida, mas não gratuita ou instantânea. O pool ajuda a minimizar a quantidade de tempo que a solicitação tem que esperar antes de ser atendida. Muitas vezes, você verá esse padrão de gerente e pool quando os tempos de resposta forem mais importantes. Enfileirar a solicitação e criar o serviço em segundo plano e, em seguida, passá-lo adiante também é um padrão de gerenciamento popular, assim como criar e excluir serviços com base em algum rastreamento da quantidade de trabalho que o serviço tem atualmente pendente.

Dimensionamento criando ou removendo novas instâncias de aplicativos nomeados

Criar e excluir instâncias inteiras de aplicativos é semelhante ao padrão de criação e exclusão de serviços. Para esse padrão, há algum serviço de gerente que está tomando a decisão com base nas solicitações que está vendo e nas informações que está recebendo dos outros serviços dentro do cluster.

Quando a criação de uma nova instância de aplicativo nomeado deve ser usada em vez de criar uma nova instância de serviço nomeada em algum aplicativo já existente? Há alguns casos:

  • A nova instância do aplicativo é para um cliente cujo código precisa ser executado sob alguma identidade específica ou configurações de segurança.
    • O Service Fabric permite definir pacotes de código diferentes para serem executados sob identidades específicas. Para iniciar o mesmo pacote de código sob identidades diferentes, as ativações precisam ocorrer em instâncias de aplicativos diferentes. Considere um caso em que você tenha as cargas de trabalho de um cliente existente implantadas. Eles podem estar sendo executados sob uma identidade específica para que você possa monitorar e controlar seu acesso a outros recursos, como bancos de dados remotos ou outros sistemas. Nesse caso, quando um novo cliente se inscreve, você provavelmente não deseja ativar seu código no mesmo contexto (espaço de processo). Embora você possa, isso torna mais difícil para o código de serviço agir dentro do contexto de uma identidade específica. Normalmente, você deve ter mais código de gerenciamento de segurança, isolamento e identidade. Em vez de usar diferentes instâncias de serviço nomeadas dentro da mesma instância de aplicativo e, portanto, do mesmo espaço de processo, você pode usar diferentes instâncias de Aplicativo do Service Fabric nomeadas. Isso facilita a definição de diferentes contextos de identidade.
  • A nova instância do aplicativo também serve como um meio de configuração
    • Por padrão, todas as instâncias de serviço nomeadas de um determinado tipo de serviço em uma instância de aplicativo serão executadas no mesmo processo em um determinado nó. Isso significa que, embora você possa configurar cada instância de serviço de forma diferente, fazer isso é complicado. Os serviços devem ter algum token que usem para procurar suas configurações dentro de um pacote de configuração. Normalmente, este é apenas o nome do serviço. Isso funciona bem, mas associa a configuração aos nomes das instâncias de serviço nomeadas individuais dentro dessa instância de aplicativo. Isso pode ser confuso e difícil de gerenciar, já que a configuração é normalmente um artefato de tempo de design com valores específicos da instância do aplicativo. Criar mais serviços sempre significa mais atualizações de aplicativos para alterar as informações dentro dos pacotes de configuração ou implantar novos para que os novos serviços possam procurar suas informações específicas. Muitas vezes, é mais fácil criar uma nova instância de aplicativo nomeada. Em seguida, você pode usar os parâmetros do aplicativo para definir qualquer configuração necessária para os serviços. Dessa forma, todos os serviços criados nessa instância de aplicativo nomeada podem herdar definições de configuração específicas. Por exemplo, em vez de ter um único arquivo de configuração com as configurações e personalizações para cada cliente, como segredos ou limites de recursos por cliente, você teria uma instância de aplicativo diferente para cada cliente com essas configurações substituídas.
  • O novo aplicativo serve como um limite de atualização
    • No Service Fabric, diferentes instâncias de aplicativos nomeados servem como limites para atualização. Uma atualização de uma instância de aplicativo nomeada não afetará o código que outra instância de aplicativo nomeado está executando. Os diferentes aplicativos acabarão executando versões diferentes do mesmo código nos mesmos nós. Isso pode ser um fator quando você precisa tomar uma decisão de dimensionamento, porque você pode escolher se o novo código deve seguir as mesmas atualizações que outro serviço ou não. Por exemplo, digamos que uma chamada chegue ao serviço de gerenciamento responsável por dimensionar as cargas de trabalho de um cliente específico criando e excluindo serviços dinamicamente. Neste caso, no entanto, a chamada é para uma carga de trabalho associada a um novo cliente. A maioria dos clientes gosta de ficar isolada uns dos outros não apenas pelas razões de segurança e configuração listadas anteriormente, mas porque oferece mais flexibilidade em termos de execução de versões específicas do software e escolha de quando eles são atualizados. Você também pode criar uma nova instância de aplicativo e criar o serviço lá simplesmente para particionar ainda mais a quantidade de seus serviços que qualquer atualização irá tocar. Instâncias de aplicativos separadas fornecem maior granularidade ao fazer atualizações de aplicativos e também permitem testes A/B e implantações Azul/Verde.
  • A instância do aplicativo existente está cheia
    • No Service Fabric, a capacidade do aplicativo é um conceito que você pode usar para controlar a quantidade de recursos disponíveis para instâncias específicas do aplicativo. Por exemplo, você pode decidir que um determinado serviço precisa ter outra instância criada para ser dimensionado. No entanto, essa instância de aplicativo está fora da capacidade para uma determinada métrica. Se esse cliente ou carga de trabalho em particular ainda precisar receber mais recursos, você poderá aumentar a capacidade existente para esse aplicativo ou criar um novo aplicativo.

Dimensionamento no nível da partição

O Service Fabric suporta particionamento. O particionamento divide um serviço em várias seções lógicas e físicas, cada uma das quais opera de forma independente. Isso é útil com serviços com monitoração de estado, já que nenhum conjunto de réplicas precisa lidar com todas as chamadas e manipular todo o estado de uma só vez. A visão geral do particionamento fornece informações sobre os tipos de esquemas de particionamento suportados. As réplicas de cada partição são espalhadas pelos nós em um cluster, distribuindo a carga desse serviço e garantindo que nem o serviço como um todo nem qualquer partição tenha um único ponto de falha.

Considere um serviço que usa um esquema de particionamento variado com uma chave baixa de 0, uma chave alta de 99 e uma contagem de partições de 4. Em um cluster de três nós, o serviço pode ser disposto com quatro réplicas que compartilham os recursos em cada nó, conforme mostrado aqui:

Layout de partição com três nós

Se você aumentar o número de nós, o Service Fabric moverá algumas das réplicas existentes para lá. Por exemplo, digamos que o número de nós aumente para quatro e as réplicas sejam redistribuídas. Agora, o serviço tem três réplicas em execução em cada nó, cada uma pertencente a partições diferentes. Isso permite uma melhor utilização de recursos, uma vez que o novo nó não é frio. Normalmente, ele também melhora o desempenho, pois cada serviço tem mais recursos disponíveis.

Layout de partição com quatro nós

Dimensionamento usando o Gerenciador de Recursos de Cluster do Service Fabric e métricas

As métricas são como os serviços expressam seu consumo de recursos para o Service Fabric. O uso de métricas dá ao Cluster Resource Manager a oportunidade de reorganizar e otimizar o layout do cluster. Por exemplo, pode haver muitos recursos no cluster, mas eles podem não ser alocados para os serviços que estão trabalhando no momento. O uso de métricas permite que o Gerenciador de Recursos de Cluster reorganize o cluster para garantir que os serviços tenham acesso aos recursos disponíveis.

Dimensionamento adicionando e removendo nós do cluster

Outra opção para dimensionamento com o Service Fabric é alterar o tamanho do cluster. Alterar o tamanho do cluster significa adicionar ou remover nós para um ou mais tipos de nó no cluster. Por exemplo, considere um caso em que todos os nós no cluster estão quentes. Isso significa que os recursos do cluster são quase todos consumidos. Nesse caso, adicionar mais nós ao cluster é a melhor maneira de dimensionar. Depois que os novos nós ingressam no cluster, o Gerenciador de Recursos de Cluster do Service Fabric move os serviços para eles, resultando em menos carga total nos nós existentes. Para serviços sem estado com contagem de instâncias = -1, mais instâncias de serviço são criadas automaticamente. Isso permite que algumas chamadas sejam movidas dos nós existentes para os novos nós.

Para obter mais informações, consulte Dimensionamento de cluster.

Escolher uma plataforma

Devido às diferenças de implementação entre sistemas operacionais, optar por usar o Service Fabric com Windows ou Linux pode ser uma parte vital do dimensionamento de seu aplicativo. Uma barreira potencial é como o registro em estágios é realizado. O Service Fabric no Windows usa um driver de kernel para um log de um por máquina, compartilhado entre réplicas de serviço com monitoração de estado. Este log pesa cerca de 8 GB. O Linux, por outro lado, usa um log de preparo de 256 MB para cada réplica, tornando-o menos ideal para aplicativos que desejam maximizar o número de réplicas de serviço leves em execução em um determinado nó. Essas diferenças nos requisitos de armazenamento temporário podem potencialmente informar a plataforma desejada para a implantação do cluster do Service Fabric.

Juntar tudo

Vamos pegar todas as ideias que discutimos aqui e falar através de um exemplo. Considere o seguinte serviço: você está tentando criar um serviço que atua como um catálogo de endereços, mantendo nomes e informações de contato.

Logo de cara, você tem um monte de perguntas relacionadas à escala: Quantos usuários você vai ter? Quantos contatos cada usuário armazenará? Tentar descobrir tudo isso quando você está levantando seu serviço pela primeira vez é difícil. Digamos que você iria com um único serviço estático com uma contagem de partições específica. As consequências de escolher a contagem de partições errada podem fazer com que você tenha problemas de escala mais tarde. Da mesma forma, mesmo que você escolha a contagem certa, você pode não ter todas as informações de que precisa. Por exemplo, você também precisa decidir o tamanho do cluster antecipadamente, tanto em termos do número de nós quanto de seus tamanhos. Geralmente, é difícil prever quantos recursos um serviço consumirá ao longo de sua vida útil. Também pode ser difícil saber com antecedência o padrão de tráfego que o serviço realmente vê. Por exemplo, talvez as pessoas adicionem e removam seus contatos apenas logo pela manhã, ou talvez seja distribuído uniformemente ao longo do dia. Com base nisso, talvez seja necessário expandir e inserir dinamicamente. Talvez você possa aprender a prever quando precisará expandir e aumentar, mas de qualquer maneira provavelmente precisará reagir às mudanças no consumo de recursos do seu serviço. Isso pode envolver a alteração do tamanho do cluster para fornecer mais recursos quando a reorganização do uso dos recursos existentes não for suficiente.

Mas por que tentar escolher um único esquema de partição para todos os usuários? Por que se limitar a um serviço e um cluster estático? A situação real é geralmente mais dinâmica.

Ao construir para escala, considere o seguinte padrão dinâmico. Poderá ter de o adaptar à sua situação:

  1. Em vez de tentar escolher um esquema de particionamento para todos na frente, crie um "serviço de gerente".
  2. O trabalho do serviço de gerente é olhar para as informações do cliente quando ele se inscrever para o seu serviço. Em seguida, dependendo dessas informações, o serviço de gerenciamento cria uma instância do seu serviço real de armazenamento de contatos apenas para esse cliente. Se eles exigirem configuração, isolamento ou atualizações específicas, você também poderá decidir criar uma instância de Aplicativo para esse cliente.

Este padrão de criação dinâmica traz muitos benefícios:

  • Você não está tentando adivinhar a contagem de partições correta para todos os usuários antecipadamente ou criar um único serviço que seja infinitamente escalável por conta própria.
  • Usuários diferentes não precisam ter a mesma contagem de partições, contagem de réplicas, restrições de posicionamento, métricas, cargas padrão, nomes de serviço, configurações de dns ou qualquer uma das outras propriedades especificadas no nível de serviço ou aplicativo.
  • Você ganha segmentação de dados adicional. Cada cliente tem a sua própria cópia do serviço
    • Cada serviço ao cliente pode ser configurado de forma diferente e receber mais ou menos recursos, com mais ou menos partições ou réplicas, conforme necessário, com base na escala esperada.
      • Por exemplo, digamos que o cliente pagou pelo nível "Gold" - ele poderia obter mais réplicas ou maior contagem de partições e, potencialmente, recursos dedicados aos seus serviços por meio de métricas e capacidades de aplicativos.
      • Ou dizer que eles forneceram informações indicando que o número de contatos que eles precisavam era "Pequeno" - eles obteriam apenas algumas partições, ou poderiam até mesmo ser colocados em um pool de serviços compartilhados com outros clientes.
  • Você não está executando um monte de instâncias de serviço ou réplicas enquanto espera que os clientes apareçam
  • Se um cliente sair, remover suas informações do seu serviço é tão simples quanto fazer com que o gerente exclua esse serviço ou aplicativo que ele criou.

Próximos passos

Para obter mais informações sobre conceitos do Service Fabric, consulte os seguintes artigos: