Descrever um cluster do Service Fabric usando o Gerenciador de Recursos de Cluster

O recurso Gerenciador de Recursos de Cluster do Azure Service Fabric fornece vários mecanismos para descrever um cluster:

  • Domínios de falha
  • Atualizar domínios
  • Propriedades do nó
  • Capacidade do nó

Durante o tempo de execução, o Gerenciador de Recursos de Cluster usa essas informações para garantir a alta disponibilidade dos serviços em execução no cluster. Ao mesmo tempo em que aplica essas regras importantes, ele também tenta otimizar o consumo de recursos dentro do cluster.

Domínios de falha

Um domínio de falha é qualquer área de falha coordenada. Uma única máquina é um domínio de falha. Ele pode falhar por conta própria por vários motivos, desde falhas na fonte de alimentação até falhas na unidade e firmware NIC incorreto.

As máquinas conectadas ao mesmo switch Ethernet estão no mesmo domínio de falha. O mesmo acontece com as máquinas que partilham uma única fonte de energia ou num único local.

Como é natural que as falhas de hardware se sobreponham, os domínios de falha são inerentemente hierárquicos. Eles são representados como URIs no Service Fabric.

É importante que os domínios de falha sejam configurados corretamente porque o Service Fabric usa essas informações para colocar serviços com segurança. O Service Fabric não deseja colocar serviços de forma que a perda de um domínio de falha (causada pela falha de algum componente) faça com que um serviço fique inativo.

No ambiente do Azure, o Service Fabric usa as informações de domínio de falha fornecidas pelo ambiente para configurar corretamente os nós no cluster em seu nome. Para instâncias autônomas do Service Fabric, os domínios de falha são definidos no momento em que o cluster é configurado.

Aviso

É importante que as informações de domínio de falha fornecidas ao Service Fabric sejam precisas. Por exemplo, digamos que os nós do cluster do Service Fabric estejam sendo executados dentro de 10 máquinas virtuais, executados em 5 hosts físicos. Neste caso, embora existam 10 máquinas virtuais, existem apenas 5 domínios de falha diferentes (nível superior). Compartilhar o mesmo host físico faz com que as VMs compartilhem o mesmo domínio de falha raiz, porque as VMs experimentam falha coordenada se seu host físico falhar.

O Service Fabric espera que o domínio de falha de um nó não seja alterado. Outros mecanismos para garantir a alta disponibilidade das VMs, como HA-VMs, podem causar conflitos com o Service Fabric. Esses mecanismos usam migração transparente de VMs de um host para outro. Eles não reconfiguram nem notificam o código em execução dentro da VM. Como tal, eles não são suportados como ambientes para executar clusters do Service Fabric.

O Service Fabric deve ser a única tecnologia de alta disponibilidade empregada. Mecanismos como migração de VM ao vivo e SANs não são necessários. Se esses mecanismos forem usados em conjunto com o Service Fabric, eles reduzirão a disponibilidade e a confiabilidade do aplicativo. O motivo é que eles introduzem complexidade adicional, adicionam fontes centralizadas de falha e usam estratégias de confiabilidade e disponibilidade que entram em conflito com as do Service Fabric.

No gráfico a seguir, colorimos todas as entidades que contribuem para domínios de falha e listamos todos os diferentes domínios de falha resultantes. Neste exemplo, temos datacenters ("DC"), racks ("R") e blades ("B"). Se cada lâmina contiver mais de uma máquina virtual, pode haver outra camada na hierarquia de domínio de falha.

Nodes organized via fault domains

Durante o tempo de execução, o Service Fabric Cluster Resource Manager considera os domínios de falha no cluster e planeja layouts. As réplicas com monitoração de estado ou instâncias sem monitoração de estado para um serviço são distribuídas para que fiquem em domínios de falha separados. A distribuição do serviço entre domínios de falha garante que a disponibilidade do serviço não seja comprometida quando um domínio de falha falhar em qualquer nível da hierarquia.

O Gerenciador de Recursos de Cluster não se importa com quantas camadas existem na hierarquia de domínio de falha. Ele tenta garantir que a perda de qualquer parte da hierarquia não afete os serviços em execução nela.

É melhor se o mesmo número de nós estiver em cada nível de profundidade na hierarquia de domínio de falha. Se a "árvore" de domínios de falha estiver desequilibrada no cluster, será mais difícil para o Cluster Resource Manager descobrir a melhor alocação de serviços. Layouts de domínio de falha desequilibrados significam que a perda de alguns domínios afeta a disponibilidade de serviços mais do que outros domínios. Como resultado, o Gerenciador de Recursos de Cluster é dividido entre duas metas:

  • Ele quer usar as máquinas nesse domínio "pesado", colocando serviços nelas.
  • Ele quer colocar serviços em outros domínios para que a perda de um domínio não cause problemas.

Como são os domínios desequilibrados? O diagrama a seguir mostra dois layouts de cluster diferentes. No primeiro exemplo, os nós são distribuídos uniformemente entre os domínios de falha. No segundo exemplo, um domínio de falha tem muito mais nós do que os outros domínios de falha.

Two different cluster layouts

No Azure, a escolha de qual domínio de falha contém um nó é gerenciada para você. Mas, dependendo do número de nós provisionados, você ainda pode acabar com domínios de falha que têm mais nós neles do que em outros.

Por exemplo, digamos que você tenha cinco domínios de falha no cluster, mas provisione sete nós para um tipo de nó (NodeType). Neste caso, os dois primeiros domínios de falha acabam com mais nós. Se você continuar a implantar mais instâncias NodeType com apenas algumas instâncias, o problema se agravará. Por esse motivo, recomendamos que o número de nós em cada tipo de nó seja um múltiplo do número de domínios de falha.

Atualizar domínios

Os domínios de atualização são outro recurso que ajuda o Service Fabric Cluster Resource Manager a entender o layout do cluster. Os domínios de atualização definem conjuntos de nós que são atualizados ao mesmo tempo. Os domínios de atualização ajudam o Cluster Resource Manager a entender e orquestrar operações de gerenciamento, como atualizações.

Os domínios de atualização são muito parecidos com os domínios de falha, mas com algumas diferenças importantes. Primeiro, áreas de falhas coordenadas de hardware definem domínios de falha. Os domínios de atualização, por outro lado, são definidos pela política. Você pode decidir quantos você quer, em vez de deixar o ambiente ditar o número. Você pode ter tantos domínios de atualização quanto nós. Outra diferença entre domínios de falha e domínios de atualização é que os domínios de atualização não são hierárquicos. Em vez disso, eles são mais como uma simples tag.

O diagrama a seguir mostra três domínios de atualização distribuídos em três domínios de falha. Ele também mostra um possível posicionamento para três réplicas diferentes de um serviço com monitoração de estado, onde cada um termina em domínios de falha e atualização diferentes. Esse posicionamento permite a perda de um domínio de falha enquanto estiver no meio de uma atualização de serviço e ainda ter uma cópia do código e dos dados.

Placement With fault and upgrade domains

Há prós e contras em ter um grande número de domínios de atualização. Mais domínios de atualização significam que cada etapa da atualização é mais granular e afeta um número menor de nós ou serviços. Menos serviços têm de se mover de cada vez, introduzindo menos rotatividade no sistema. Isso tende a melhorar a confiabilidade, porque menos do serviço é afetado por qualquer problema introduzido durante a atualização. Mais domínios de atualização também significam que você precisa de menos buffer disponível em outros nós para lidar com o impacto da atualização.

Por exemplo, se você tiver cinco domínios de atualização, os nós em cada um estão lidando com cerca de 20% do seu tráfego. Se você precisar derrubar esse domínio de atualização para uma atualização, a carga geralmente precisa ir para algum lugar. Como você tem quatro domínios de atualização restantes, cada um deve ter espaço para cerca de 25% do tráfego total. Mais domínios de atualização significam que você precisa de menos buffer nos nós no cluster.

Considere se você tinha 10 domínios de atualização. Nesse caso, cada domínio de atualização estaria lidando com apenas cerca de 10% do tráfego total. Quando uma atualização passa pelo cluster, cada domínio precisa ter espaço para apenas cerca de 11% do tráfego total. Mais domínios de atualização geralmente permitem que você execute seus nós com maior utilização, porque você precisa de menos capacidade reservada. O mesmo se aplica aos domínios de falha.

A desvantagem de ter muitos domínios de atualização é que as atualizações tendem a levar mais tempo. O Service Fabric aguarda um curto período após a conclusão de um domínio de atualização e executa verificações antes de começar a atualizar o próximo. Esses atrasos permitem detetar problemas introduzidos pela atualização antes que ela prossiga. A compensação é aceitável porque evita que alterações ruins afetem muito do serviço de cada vez.

A presença de poucos domínios de atualização tem muitos efeitos colaterais negativos. Embora cada domínio de atualização esteja inativo e sendo atualizado, uma grande parte da sua capacidade geral não está disponível. Por exemplo, se você tiver apenas três domínios de atualização, estará removendo cerca de um terço da capacidade geral de serviço ou cluster de cada vez. Ter grande parte do seu serviço inativo ao mesmo tempo não é desejável porque você precisa de capacidade suficiente no restante do cluster para lidar com a carga de trabalho. Manter esse buffer significa que, durante a operação normal, esses nós são menos carregados do que estariam de outra forma. Isso aumenta o custo de execução do serviço.

Não há limite real para o número total de domínios de falha ou atualização em um ambiente, ou restrições sobre como eles se sobrepõem. Mas há padrões comuns:

  • Domínios de falha e domínios de atualização mapeados 1:1
  • Um domínio de atualização por nó (instância física ou virtual do sistema operacional)
  • Um modelo "listrado" ou "matriz" onde os domínios de falha e os domínios de atualização formam uma matriz com máquinas geralmente correndo pelas diagonais

Layouts of fault and upgrade domains

Não há melhor resposta para qual layout escolher. Cada um tem prós e contras. Por exemplo, o modelo 1FD:1UD é simples de configurar. O modelo de um domínio de atualização por modelo de nó é mais parecido com o que as pessoas estão acostumadas. Durante as atualizações, cada nó é atualizado independentemente. Isto é semelhante à forma como pequenos conjuntos de máquinas eram atualizados manualmente no passado.

O modelo mais comum é a matriz FD/UD, onde os domínios de falha e os domínios de atualização formam uma tabela e os nós são colocados começando ao longo da diagonal. Este é o modelo usado por padrão em clusters do Service Fabric no Azure. Para clusters com muitos nós, tudo acaba parecendo um padrão de matriz densa.

Nota

Os clusters do Service Fabric hospedados no Azure não oferecem suporte à alteração da estratégia padrão. Somente clusters autônomos oferecem essa personalização.

Restrições de domínio de falha e atualização e comportamento resultante

Abordagem por defeito

Por padrão, o Gerenciador de Recursos de Cluster mantém os serviços equilibrados entre domínios de falha e atualização. Isso é modelado como uma restrição. A restrição para domínios de falha e atualização afirma: "Para uma determinada partição de serviço, nunca deve haver uma diferença maior que uma no número de objetos de serviço (instâncias de serviço sem estado ou réplicas de serviço com monitoração de estado) entre quaisquer dois domínios no mesmo nível de hierarquia."

Digamos que esta restrição fornece uma garantia de "diferença máxima". A restrição para domínios de falha e atualização impede certos movimentos ou arranjos que violam a regra.

Por exemplo, digamos que temos um cluster com seis nós, configurado com cinco domínios de falha e cinco domínios de atualização.

FD0 FD1 FD2 FD3 FD4
UD0 N1
UD1 N 6 N 2
UD2 N 3
UD3 N 4
UD4 N 5

Agora, digamos que criamos um serviço com um valor TargetReplicaSetSize (ou, para um serviço sem estado, InstanceCount) de cinco. As réplicas pousam na N1-N5. Na verdade, o N6 nunca é usado, não importa quantos serviços como este você crie. Mas porquê? Vejamos a diferença entre o layout atual e o que aconteceria se o N6 fosse escolhido.

Aqui está o layout que obtivemos e o número total de réplicas por domínio de falha e atualização:

FD0 FD1 FD2 FD3 FD4 UDTotal
UD0 R1 5
UD1 R2 5
UD2 R3 5
UD3 R4 5
UD4 R5 5
FDTotal 1 1 1 1 1 -

Esse layout é balanceado em termos de nós por domínio de falha e domínio de atualização. Também é equilibrado em termos do número de réplicas por domínio de falha e atualização. Cada domínio tem o mesmo número de nós e o mesmo número de réplicas.

Agora, vamos ver o que aconteceria se tivéssemos usado N6 em vez de N2. Como as réplicas seriam distribuídas então?

FD0 FD1 FD2 FD3 FD4 UDTotal
UD0 R1 5
UD1 R5 5
UD2 R2 5
UD3 R3 5
UD4 R4 5
FDTotal 2 0 1 1 1 -

Este layout viola nossa definição da garantia de "diferença máxima" para a restrição de domínio de falha. FD0 tem duas réplicas, enquanto FD1 tem zero. A diferença entre FD0 e FD1 é um total de dois, que é maior do que a diferença máxima de um. Como a restrição é violada, o Gerenciador de Recursos de Cluster não permite essa organização.

Da mesma forma, se escolhêssemos N2 e N6 (em vez de N1 e N2), teríamos:

FD0 FD1 FD2 FD3 FD4 UDTotal
UD0 0
UD1 R5 R1 2
UD2 R2 5
UD3 R3 5
UD4 R4 5
FDTotal 1 1 1 1 1 -

Este layout é equilibrado em termos de domínios de falha. Mas agora está violando a restrição de domínio de atualização, porque UD0 tem zero réplicas e UD1 tem duas. Esse layout também é inválido e não será escolhido pelo Gerenciador de Recursos de Cluster.

Essa abordagem para a distribuição de réplicas com monitoração de estado ou instâncias sem monitoração de estado fornece a melhor tolerância a falhas possível. Se um domínio ficar inativo, o número mínimo de réplicas/instâncias será perdido.

Por outro lado, essa abordagem pode ser muito rigorosa e não permitir que o cluster utilize todos os recursos. Para determinadas configurações de cluster, determinados nós não podem ser usados. Isso pode fazer com que o Service Fabric não coloque seus serviços, resultando em mensagens de aviso. No exemplo anterior, alguns dos nós de cluster não podem ser usados (N6 no exemplo). Mesmo se você adicionasse nós a esse cluster (N7-N10), as réplicas/instâncias seriam colocadas apenas em N1–N5 devido a restrições em domínios de falha e atualização.

FD0 FD1 FD2 FD3 FD4
UD0 N1 N 10
UD1 N 6 N 2
UD2 N 7 N 3
UD3 N 8 N 4
UD4 N 9 N 5

Abordagem alternativa

O Gerenciador de Recursos de Cluster oferece suporte a outra versão da restrição para domínios de falha e atualização. Permite a colocação ao mesmo tempo que garante um nível mínimo de segurança. A restrição alternativa pode ser declarada da seguinte forma: "Para uma determinada partição de serviço, a distribuição de réplica entre domínios deve garantir que a partição não sofra uma perda de quórum." Digamos que esta restrição fornece uma garantia de "quórum seguro".

Nota

Para um serviço com monitoração de estado, definimos perda de quórum em uma situação em que a maioria das réplicas de partição está inativa ao mesmo tempo. Por exemplo, se TargetReplicaSetSize for cinco, um conjunto de três réplicas representará o quorum. Da mesma forma, se TargetReplicaSetSize for seis, quatro réplicas serão necessárias para quorum. Em ambos os casos, não mais do que duas réplicas podem estar inativas ao mesmo tempo se a partição quiser continuar funcionando normalmente.

Para um serviço apátrida, não existe perda de quórum. Os serviços apátridas continuam a funcionar normalmente, mesmo que a maioria das instâncias diminua ao mesmo tempo. Portanto, vamos nos concentrar em serviços com estado no restante deste artigo.

Voltemos ao exemplo anterior. Com a versão "quorum safe" da restrição, todos os três layouts seriam válidos. Mesmo se FD0 falhasse no segundo layout ou UD1 falhasse no terceiro layout, a partição ainda teria quórum. (A maioria das réplicas ainda estaria em alta.) Com esta versão da restrição, N6 quase sempre pode ser utilizado.

A abordagem "quorum safe" proporciona mais flexibilidade do que a abordagem da "diferença máxima". O motivo é que é mais fácil encontrar distribuições de réplica válidas em praticamente qualquer topologia de cluster. No entanto, essa abordagem não pode garantir as melhores características de tolerância a falhas, porque algumas falhas são piores do que outras.

Na pior das hipóteses, a maioria das réplicas pode ser perdida com a falha de um domínio e uma réplica adicional. Por exemplo, em vez de três falhas serem necessárias para perder quórum com cinco réplicas ou instâncias, agora você pode perder a maioria com apenas duas falhas.

Abordagem adaptativa

Como ambas as abordagens têm pontos fortes e fracos, introduzimos uma abordagem adaptativa que combina essas duas estratégias.

Nota

Esse é o comportamento padrão que começa com o Service Fabric versão 6.2.

A abordagem adaptativa usa a lógica de "diferença máxima" por padrão e muda para a lógica "quorum safe" apenas quando necessário. O Cluster Resource Manager descobre automaticamente qual estratégia é necessária, observando como o cluster e os serviços estão configurados.

O Gerenciador de Recursos de Cluster deve usar a lógica "baseada em quorum" para um serviço Ambas as condições são verdadeiras:

  • TargetReplicaSetSize para o serviço é uniformemente divisível pelo número de domínios de falha e pelo número de domínios de atualização.
  • O número de nós é menor ou igual ao número de domínios de falha multiplicado pelo número de domínios de atualização.

Lembre-se de que o Gerenciador de Recursos de Cluster usará essa abordagem para serviços sem monitoração de estado e com monitoração de estado, mesmo que a perda de quórum não seja relevante para serviços sem monitoração de estado.

Vamos voltar ao exemplo anterior e assumir que um cluster agora tem oito nós. O cluster ainda está configurado com cinco domínios de falha e cinco domínios de atualização, e o valor TargetReplicaSetSize de um serviço hospedado nesse cluster permanece cinco.

FD0 FD1 FD2 FD3 FD4
UD0 N1
UD1 N 6 N 2
UD2 N 7 N 3
UD3 N 8 N 4
UD4 N 5

Como todas as condições necessárias são satisfeitas, o Gerenciador de Recursos de Cluster usará a lógica "baseada em quórum" na distribuição do serviço. Isso permite o uso de N6-N8. Uma possível distribuição de serviço neste caso pode ter esta aparência:

FD0 FD1 FD2 FD3 FD4 UDTotal
UD0 R1 5
UD1 R2 5
UD2 R3 R4 2
UD3 0
UD4 R5 5
FDTotal 2 1 1 0 5 -

Se o valor TargetReplicaSetSize do seu serviço for reduzido para quatro (por exemplo), o Gerenciador de Recursos de Cluster notará essa alteração. Ele continuará usando a lógica de "diferença máxima" porque TargetReplicaSetSize não é mais dividível pelo número de domínios de falha e domínios de atualização. Como resultado, certos movimentos de réplica ocorrerão para distribuir as quatro réplicas restantes nos nós N1-N5. Dessa forma, a versão de "diferença máxima" do domínio de falha e a lógica do domínio de atualização não são violadas.

No layout anterior, se o valor TargetReplicaSetSize for cinco e N1 for removido do cluster, o número de domínios de atualização se tornará igual a quatro. Novamente, o Gerenciador de Recursos de Cluster começa a usar a lógica de "diferença máxima" porque o número de domínios de atualização não divide mais uniformemente o valor TargetReplicaSetSize do serviço. Como resultado, a réplica R1, quando construída novamente, tem que pousar no N4 para que a restrição para o domínio de falha e atualização não seja violada.

FD0 FD1 FD2 FD3 FD4 UDTotal
UD0 N/A N/D N/D N/D N/D N/A
UD1 R2 5
UD2 R3 R4 2
UD3 R1 5
UD4 R5 5
FDTotal 1 1 1 1 1 -

Configurando domínios de falha e atualização

Nas implantações do Service Fabric hospedadas no Azure, os domínios de falha e os domínios de atualização são definidos automaticamente. O Service Fabric pega e usa as informações de ambiente do Azure.

Se você estiver criando seu próprio cluster (ou quiser executar uma topologia específica em desenvolvimento), poderá fornecer o domínio de falha e atualizar as informações do domínio por conta própria. Neste exemplo, definimos um cluster de desenvolvimento local de nove nós que abrange três datacenters (cada um com três racks). Esse cluster também tem três domínios de atualização distribuídos nesses três datacenters. Aqui está um exemplo da configuração em ClusterManifest.xml:

  <Infrastructure>
    <!-- IsScaleMin indicates that this cluster runs on one box/one single server -->
    <WindowsServer IsScaleMin="true">
      <NodeList>
        <Node NodeName="Node01" IPAddressOrFQDN="localhost" NodeTypeRef="NodeType01" FaultDomain="fd:/DC01/Rack01" UpgradeDomain="UpgradeDomain1" IsSeedNode="true" />
        <Node NodeName="Node02" IPAddressOrFQDN="localhost" NodeTypeRef="NodeType02" FaultDomain="fd:/DC01/Rack02" UpgradeDomain="UpgradeDomain2" IsSeedNode="true" />
        <Node NodeName="Node03" IPAddressOrFQDN="localhost" NodeTypeRef="NodeType03" FaultDomain="fd:/DC01/Rack03" UpgradeDomain="UpgradeDomain3" IsSeedNode="true" />
        <Node NodeName="Node04" IPAddressOrFQDN="localhost" NodeTypeRef="NodeType04" FaultDomain="fd:/DC02/Rack01" UpgradeDomain="UpgradeDomain1" IsSeedNode="true" />
        <Node NodeName="Node05" IPAddressOrFQDN="localhost" NodeTypeRef="NodeType05" FaultDomain="fd:/DC02/Rack02" UpgradeDomain="UpgradeDomain2" IsSeedNode="true" />
        <Node NodeName="Node06" IPAddressOrFQDN="localhost" NodeTypeRef="NodeType06" FaultDomain="fd:/DC02/Rack03" UpgradeDomain="UpgradeDomain3" IsSeedNode="true" />
        <Node NodeName="Node07" IPAddressOrFQDN="localhost" NodeTypeRef="NodeType07" FaultDomain="fd:/DC03/Rack01" UpgradeDomain="UpgradeDomain1" IsSeedNode="true" />
        <Node NodeName="Node08" IPAddressOrFQDN="localhost" NodeTypeRef="NodeType08" FaultDomain="fd:/DC03/Rack02" UpgradeDomain="UpgradeDomain2" IsSeedNode="true" />
        <Node NodeName="Node09" IPAddressOrFQDN="localhost" NodeTypeRef="NodeType09" FaultDomain="fd:/DC03/Rack03" UpgradeDomain="UpgradeDomain3" IsSeedNode="true" />
      </NodeList>
    </WindowsServer>
  </Infrastructure>

Este exemplo usa ClusterConfig.json para implantações autônomas:

"nodes": [
  {
    "nodeName": "vm1",
    "iPAddress": "localhost",
    "nodeTypeRef": "NodeType0",
    "faultDomain": "fd:/dc1/r0",
    "upgradeDomain": "UD1"
  },
  {
    "nodeName": "vm2",
    "iPAddress": "localhost",
    "nodeTypeRef": "NodeType0",
    "faultDomain": "fd:/dc1/r0",
    "upgradeDomain": "UD2"
  },
  {
    "nodeName": "vm3",
    "iPAddress": "localhost",
    "nodeTypeRef": "NodeType0",
    "faultDomain": "fd:/dc1/r0",
    "upgradeDomain": "UD3"
  },
  {
    "nodeName": "vm4",
    "iPAddress": "localhost",
    "nodeTypeRef": "NodeType0",
    "faultDomain": "fd:/dc2/r0",
    "upgradeDomain": "UD1"
  },
  {
    "nodeName": "vm5",
    "iPAddress": "localhost",
    "nodeTypeRef": "NodeType0",
    "faultDomain": "fd:/dc2/r0",
    "upgradeDomain": "UD2"
  },
  {
    "nodeName": "vm6",
    "iPAddress": "localhost",
    "nodeTypeRef": "NodeType0",
    "faultDomain": "fd:/dc2/r0",
    "upgradeDomain": "UD3"
  },
  {
    "nodeName": "vm7",
    "iPAddress": "localhost",
    "nodeTypeRef": "NodeType0",
    "faultDomain": "fd:/dc3/r0",
    "upgradeDomain": "UD1"
  },
  {
    "nodeName": "vm8",
    "iPAddress": "localhost",
    "nodeTypeRef": "NodeType0",
    "faultDomain": "fd:/dc3/r0",
    "upgradeDomain": "UD2"
  },
  {
    "nodeName": "vm9",
    "iPAddress": "localhost",
    "nodeTypeRef": "NodeType0",
    "faultDomain": "fd:/dc3/r0",
    "upgradeDomain": "UD3"
  }
],

Nota

Quando você define clusters por meio do Gerenciador de Recursos do Azure, o Azure atribui domínios de falha e domínios de atualização. Portanto, a definição de seus tipos de nó e conjuntos de escala de máquina virtual em seu modelo do Azure Resource Manager não inclui informações sobre domínio de falha ou domínio de atualização.

Propriedades do nó e restrições de posicionamento

Às vezes (na verdade, na maioria das vezes) você vai querer garantir que determinadas cargas de trabalho sejam executadas apenas em determinados tipos de nós no cluster. Por exemplo, algumas cargas de trabalho podem exigir GPUs ou SSDs, e outras não.

Um ótimo exemplo de direcionamento de hardware para cargas de trabalho específicas é quase todas as arquiteturas de n camadas. Certas máquinas servem como o lado front-end ou de serviço de API do aplicativo e são expostas aos clientes ou à Internet. Máquinas diferentes, muitas vezes com recursos de hardware diferentes, lidam com o trabalho das camadas de computação ou armazenamento. Estes geralmente não estão diretamente expostos aos clientes ou à internet.

O Service Fabric espera que, em alguns casos, cargas de trabalho específicas precisem ser executadas em configurações de hardware específicas. Por exemplo:

  • Um aplicativo de n camadas existente foi "levantado e deslocado" para um ambiente do Service Fabric.
  • Uma carga de trabalho deve ser executada em hardware específico por motivos de desempenho, escala ou isolamento de segurança.
  • Uma carga de trabalho deve ser isolada de outras cargas de trabalho por motivos de política ou consumo de recursos.

Para dar suporte a esses tipos de configurações, o Service Fabric inclui marcas que você pode aplicar aos nós. Essas tags são chamadas de propriedades do nó. As restrições de posicionamento são as instruções anexadas a serviços individuais que você seleciona para uma ou mais propriedades de nó. As restrições de posicionamento definem onde os serviços devem ser executados. O conjunto de restrições é extensível. Qualquer par chave/valor pode funcionar.

Different workloads for a cluster layout

Propriedades do nó interno

O Service Fabric define algumas propriedades de nó padrão que podem ser usadas automaticamente para que você não precise defini-las. As propriedades padrão definidas em cada nó são NodeType e NodeName.

Por exemplo, você pode escrever uma restrição de posicionamento como "(NodeType == NodeType03)". NodeType é uma propriedade comumente usada. É útil porque corresponde 1:1 a um tipo de máquina. Cada tipo de máquina corresponde a um tipo de carga de trabalho em um aplicativo tradicional de n camadas.

Placement constraints and node properties

Restrições de posicionamento e sintaxe de propriedade do nó

O valor especificado na propriedade node pode ser uma cadeia de caracteres, booleano ou assinado longo. A instrução no serviço é chamada de restrição de posicionamento porque restringe onde o serviço pode ser executado no cluster. A restrição pode ser qualquer instrução booleana que opere nas propriedades do nó no cluster. Os seletores válidos nestas instruções booleanas são:

  • Verificações condicionais para a criação de instruções específicas:

    Declaração Sintaxe
    "igual a" "=="
    "não é igual a" "!="
    "maior que" ">"
    "maior ou igual a" "=">
    "menos que" "<"
    "inferior ou igual a" "="<
  • Instruções booleanas para agrupamento e operações lógicas:

    Declaração Sintaxe
    "e" "&&"
    "ou" "||"
    "não" "!"
    "grupo como declaração única" "()"

Aqui estão alguns exemplos de instruções básicas de restrição:

  • "Value >= 5"
  • "NodeColor != green"
  • "((OneProperty < 100) || ((AnotherProperty == false) && (OneProperty >= 100)))"

Somente os nós em que a instrução geral de restrição de posicionamento é avaliada como "True" podem ter o serviço colocado nele. Os nós que não têm uma propriedade definida não correspondem a nenhuma restrição de posicionamento que contenha a propriedade.

Digamos que as seguintes propriedades de nó foram definidas para um tipo de nó em ClusterManifest.xml:

    <NodeType Name="NodeType01">
      <PlacementProperties>
        <Property Name="HasSSD" Value="true"/>
        <Property Name="NodeColor" Value="green"/>
        <Property Name="SomeProperty" Value="5"/>
      </PlacementProperties>
    </NodeType>

O exemplo a seguir mostra as propriedades do nó definidas por meio de ClusterConfig.json para implantações autônomas ou Template.json para clusters hospedados no Azure.

Nota

No seu modelo do Azure Resource Manager, o tipo de nó geralmente é parametrizado. Seria parecido em "[parameters('vmNodeType1Name')]" vez de NodeType01.

"nodeTypes": [
    {
        "name": "NodeType01",
        "placementProperties": {
            "HasSSD": "true",
            "NodeColor": "green",
            "SomeProperty": "5"
        },
    }
],

Você pode criar restrições de posicionamento de serviço para um serviço da seguinte maneira:

FabricClient fabricClient = new FabricClient();
StatefulServiceDescription serviceDescription = new StatefulServiceDescription();
serviceDescription.PlacementConstraints = "(HasSSD == true && SomeProperty >= 4)";
// Add other required ServiceDescription fields
//...
await fabricClient.ServiceManager.CreateServiceAsync(serviceDescription);
New-ServiceFabricService -ApplicationName $applicationName -ServiceName $serviceName -ServiceTypeName $serviceType -Stateful -MinReplicaSetSize 3 -TargetReplicaSetSize 3 -PartitionSchemeSingleton -PlacementConstraint "HasSSD == true && SomeProperty >= 4"

Se todos os nós de NodeType01 forem válidos, você também poderá selecionar esse tipo de nó com a restrição "(NodeType == NodeType01)".

As restrições de posicionamento de um serviço podem ser atualizadas dinamicamente durante o tempo de execução. Se precisar, você pode mover um serviço no cluster, adicionar e remover requisitos e assim por diante. O Service Fabric garante que o serviço permaneça ativo e disponível mesmo quando esses tipos de alterações são feitos.

StatefulServiceUpdateDescription updateDescription = new StatefulServiceUpdateDescription();
updateDescription.PlacementConstraints = "NodeType == NodeType01";
await fabricClient.ServiceManager.UpdateServiceAsync(new Uri("fabric:/app/service"), updateDescription);
Update-ServiceFabricService -Stateful -ServiceName $serviceName -PlacementConstraints "NodeType == NodeType01"

As restrições de posicionamento são especificadas para cada instância de serviço nomeada. As atualizações sempre substituem (substituim) o que foi especificado anteriormente.

A definição de cluster define as propriedades em um nó. A alteração das propriedades de um nó requer uma atualização para a configuração do cluster. A atualização das propriedades de um nó requer que cada nó afetado reinicie para relatar suas novas propriedades. O Service Fabric gerencia essas atualizações contínuas.

Descrevendo e gerenciando recursos de cluster

Um dos trabalhos mais importantes de qualquer orquestrador é ajudar a gerenciar o consumo de recursos no cluster. Gerenciar recursos de cluster pode significar algumas coisas diferentes.

Primeiro, há garantir que as máquinas não estejam sobrecarregadas. Isso significa garantir que as máquinas não estejam executando mais serviços do que aqueles com que podem lidar.

Em segundo lugar, há o equilíbrio e a otimização, que são essenciais para executar serviços de forma eficiente. As ofertas de serviço econômicas ou sensíveis ao desempenho não podem permitir que alguns nós estejam quentes enquanto outros estão frios. Os nós quentes levam à contenção de recursos e ao baixo desempenho. Os nós frios representam recursos desperdiçados e custos acrescidos.

O Service Fabric representa recursos como métricas. As métricas são qualquer recurso lógico ou físico que você deseja descrever para o Service Fabric. Exemplos de métricas são "WorkQueueDepth" ou "MemoryInMb". Para obter informações sobre os recursos físicos que o Service Fabric pode governar nos nós, consulte Governança de recursos. Para obter informações sobre as métricas padrão usadas pelo Gerenciador de Recursos de Cluster e como configurar métricas personalizadas, consulte este artigo.

As métricas são diferentes das restrições de posicionamento e das propriedades do nó. As propriedades do nó são descritores estáticos dos próprios nós. As métricas descrevem os recursos que os nós têm e que os serviços consomem quando são executados em um nó. Uma propriedade de nó pode ser HasSSD e pode ser definida como true ou false. A quantidade de espaço disponível nesse SSD e quanto é consumido pelos serviços seria uma métrica como "DriveSpaceInMb".

Assim como para restrições de posicionamento e propriedades de nó, o Service Fabric Cluster Resource Manager não entende o significado dos nomes das métricas. Os nomes das métricas são apenas cadeias de caracteres. É uma boa prática declarar unidades como parte dos nomes de métricas que você cria quando elas podem ser ambíguas.

Capacidade

Se você desativou todo o balanceamento de recursos, o Gerenciador de Recursos de Cluster do Service Fabric ainda garantirá que nenhum nó ultrapasse sua capacidade. O gerenciamento de saturações de capacidade é possível, a menos que o cluster esteja muito cheio ou a carga de trabalho seja maior do que qualquer nó. A capacidade é outra restrição que o Gerenciador de Recursos de Cluster usa para entender a quantidade de um recurso que um nó tem. A capacidade restante também é rastreada para o cluster como um todo.

Tanto a capacidade como o consumo ao nível do serviço são expressos em termos de métricas. Por exemplo, a métrica pode ser "ClientConnections" e um nó pode ter uma capacidade para "ClientConnections" de 32.768. Outros nós podem ter outros limites. Um serviço em execução nesse nó pode dizer que está consumindo atualmente 32.256 da métrica "ClientConnections".

Durante o tempo de execução, o Gerenciador de Recursos de Cluster rastreia a capacidade restante no cluster e nos nós. Para controlar a capacidade, o Gerenciador de Recursos de Cluster subtrai o uso de cada serviço da capacidade de um nó onde o serviço é executado. Com essas informações, o Gerenciador de Recursos de Cluster pode descobrir onde colocar ou mover réplicas para que os nós não ultrapassem a capacidade.

Cluster nodes and capacity

StatefulServiceDescription serviceDescription = new StatefulServiceDescription();
ServiceLoadMetricDescription metric = new ServiceLoadMetricDescription();
metric.Name = "ClientConnections";
metric.PrimaryDefaultLoad = 1024;
metric.SecondaryDefaultLoad = 0;
metric.Weight = ServiceLoadMetricWeight.High;
serviceDescription.Metrics.Add(metric);
await fabricClient.ServiceManager.CreateServiceAsync(serviceDescription);
New-ServiceFabricService -ApplicationName $applicationName -ServiceName $serviceName -ServiceTypeName $serviceTypeName –Stateful -MinReplicaSetSize 3 -TargetReplicaSetSize 3 -PartitionSchemeSingleton –Metric @("ClientConnections,High,1024,0)

Você pode ver as capacidades definidas no manifesto do cluster. Aqui está um exemplo para ClusterManifest.xml:

    <NodeType Name="NodeType03">
      <Capacities>
        <Capacity Name="ClientConnections" Value="65536"/>
      </Capacities>
    </NodeType>

Aqui está um exemplo de capacidades definidas via ClusterConfig.json para implantações autônomas ou Template.json para clusters hospedados no Azure:

"nodeTypes": [
    {
        "name": "NodeType03",
        "capacities": {
            "ClientConnections": "65536",
        }
    }
],

A carga de um serviço geralmente muda dinamicamente. Digamos que a carga de "ClientConnections" de uma réplica foi alterada de 1.024 para 2.048. O nó em que ele estava sendo executado na época tinha uma capacidade de apenas 512 restantes para essa métrica. Agora, o posicionamento dessa réplica ou instância é inválido, porque não há espaço suficiente nesse nó. O Cluster Resource Manager tem de recuperar o nó abaixo da capacidade. Ele reduz a carga no nó que está acima da capacidade, movendo uma ou mais das réplicas ou instâncias desse nó para outros nós.

O Gerenciador de Recursos de Cluster tenta minimizar o custo de mover réplicas. Você pode aprender mais sobre o custo do movimento e sobre estratégias e regras de reequilíbrio.

Capacidade do cluster

Como o Gerenciador de Recursos de Cluster do Service Fabric evita que o cluster geral fique muito cheio? Com carga dinâmica, não há muito que possa fazer. Os serviços podem ter seu pico de carga independentemente das ações tomadas pelo Gerenciador de Recursos de Cluster. Como resultado, seu cluster com muito espaço livre hoje pode estar subalimentado se houver um pico amanhã.

Os controles no Gerenciador de Recursos de Cluster ajudam a evitar problemas. A primeira coisa que você pode fazer é impedir a criação de novas cargas de trabalho que fariam com que o cluster ficasse cheio.

Digamos que você crie um serviço sem monitoração de estado e ele tenha alguma carga associada a ele. O serviço se preocupa com a métrica "DiskSpaceInMb". O serviço consumirá cinco unidades de "DiskSpaceInMb" para cada instância do serviço. Você deseja criar três instâncias do serviço. Isso significa que você precisa de 15 unidades de "DiskSpaceInMb" para estar presente no cluster para que você possa criar essas instâncias de serviço.

O Cluster Resource Manager calcula continuamente a capacidade e o consumo de cada métrica para que possa determinar a capacidade restante no cluster. Se não houver espaço suficiente, o Gerenciador de Recursos de Cluster rejeitará a chamada para criar um serviço.

Como o requisito é apenas que 15 unidades estejam disponíveis, você pode alocar esse espaço de muitas maneiras diferentes. Por exemplo, pode haver uma unidade de capacidade restante em 15 nós diferentes ou três unidades restantes de capacidade em cinco nós diferentes. Se o Gerenciador de Recursos de Cluster puder reorganizar as coisas para que haja cinco unidades disponíveis em três nós, ele colocará o serviço. Reorganizar o cluster geralmente é possível, a menos que o cluster esteja quase cheio ou os serviços existentes não possam ser consolidados por algum motivo.

Buffer de nó e capacidade de overbooking

Se uma capacidade de nó para uma métrica for especificada, o Gerenciador de Recursos de Cluster nunca colocará ou moverá réplicas para um nó se a carga total exceder a capacidade do nó especificado. Às vezes, isso pode impedir a colocação de novas réplicas ou a substituição de réplicas com falha se o cluster estiver perto da capacidade total e uma réplica com uma grande carga precisar ser colocada, substituída ou movida.

Para fornecer mais flexibilidade, você pode especificar buffer de nó ou capacidade de overbooking. Quando o buffer de nó ou a capacidade de overbooking são especificados para uma métrica, o Gerenciador de Recursos de Cluster tentará colocar ou mover réplicas de tal forma que a capacidade de buffer ou overbooking permaneça não utilizada, mas permita que a capacidade de buffer ou overbooking seja usada, se necessário, para ações que aumentem a disponibilidade do serviço, como:

  • Novo posicionamento de réplica ou substituição de réplicas com falha
  • Posicionamento durante upgrades
  • Correção de violações de restrições suaves e rígidas
  • Desfragmentação

A capacidade do buffer do nó representa uma parte reservada da capacidade abaixo da capacidade do nó especificada e a capacidade de overbooking representa uma parte da capacidade extra acima da capacidade do nó especificada. Em ambos os casos, o Cluster Resource Manager tentará manter essa capacidade livre.

Por exemplo, se um nó tiver uma capacidade especificada para a métrica CpuUtilization de 100 e a porcentagem do buffer do nó para essa métrica for definida como 20%, as capacidades totais e sem buffer serão 100 e 80, respectivamente, e o Gerenciador de Recursos de Cluster não colocará mais de 80 unidades de carga no nó durante circunstâncias normais.

Total capacity equals node capacity (Node buffer + Unbuffered)

O buffer de nó deve ser usado quando você deseja reservar uma parte da capacidade do nó que só será usada para ações que aumentem a disponibilidade do serviço mencionado acima.

Por outro lado, se a porcentagem de overbooking de nó for usada e definida como 20%, as capacidades totais e sem buffer serão 120 e 100, respectivamente.

Total capacity equals overbooking capacity plus node capacity (Overbooking + Unbuffered)

A capacidade de overbooking deve ser usada quando você quiser permitir que o Gerenciador de Recursos de Cluster coloque réplicas em um nó, mesmo que o uso total de recursos exceda a capacidade. Isso pode ser usado para fornecer disponibilidade adicional para serviços em detrimento do desempenho. Se o overbooking for usado, a lógica do aplicativo do usuário precisará ser capaz de funcionar com menos recursos físicos do que o necessário.

Se o buffer do nó ou as capacidades de overbooking forem especificados, o Gerenciador de Recursos de Cluster não moverá nem colocará réplicas se a carga total no nó de destino ultrapassar a capacidade total (capacidade do nó no caso de buffer do nó e capacidade do nó + capacidade de overbooking em caso de overbooking).

A capacidade de overbooking também pode ser especificada como infinita. Nesse caso, o Gerenciador de Recursos de Cluster tentará manter a carga total no nó abaixo da capacidade do nó especificado, mas terá permissão para colocar potencialmente uma carga muito maior no nó, o que pode levar a uma grave degradação do desempenho.

Uma métrica não pode ter o buffer de nó e a capacidade de overbooking especificados para ela ao mesmo tempo.

Veja um exemplo de como especificar o buffer de nó ou capacidades de overbooking no ClusterManifest.xml:

<Section Name="NodeBufferPercentage">
    <Parameter Name="SomeMetric" Value="0.15" />
</Section>
<Section Name="NodeOverbookingPercentage">
    <Parameter Name="SomeOtherMetric" Value="0.2" />
    <Parameter Name=”MetricWithInfiniteOverbooking” Value=”-1.0” />
</Section>

Veja um exemplo de como especificar buffer de nó ou capacidades de overbooking por meio de ClusterConfig.json para implantações autônomas ou Template.json para clusters hospedados no Azure:

"fabricSettings": [
  {
    "name": "NodeBufferPercentage",
    "parameters": [
      {
          "name": "SomeMetric",
          "value": "0.15"
      }
    ]
  },
  {
    "name": "NodeOverbookingPercentage",
    "parameters": [
      {
          "name": "SomeOtherMetric",
          "value": "0.20"
      },
      {
          "name": "MetricWithInfiniteOverbooking",
          "value": "-1.0"
      }
    ]
  }
]

Próximos passos