Cenários de testabilidade

Grandes sistemas distribuídos, como infraestruturas em nuvem, são inerentemente não confiáveis. O Azure Service Fabric oferece aos desenvolvedores a capacidade de escrever serviços para serem executados em cima de infraestruturas não confiáveis. Para escrever serviços de alta qualidade, os desenvolvedores precisam ser capazes de induzir essa infraestrutura não confiável para testar a estabilidade de seus serviços.

O Serviço de Análise de Falhas oferece aos desenvolvedores a capacidade de induzir ações de falha para testar serviços na presença de falhas. No entanto, falhas simuladas direcionadas o levarão apenas até agora. Para levar o teste adiante, você pode usar os cenários de teste no Service Fabric: um teste de caos e um teste de failover. Esses cenários simulam falhas intercaladas contínuas, graciosas e desgraçadas, em todo o cluster durante longos períodos de tempo. Depois que um teste é configurado com a taxa e o tipo de falhas, ele pode ser iniciado por meio de APIs C# ou PowerShell, para gerar falhas no cluster e no seu serviço.

Aviso

ChaosTestScenario está sendo substituído por um Chaos mais resiliente e baseado em serviços. Consulte o novo artigo Caos controlado para obter mais detalhes.

Teste do caos

O cenário de caos gera falhas em todo o cluster do Service Fabric. O cenário comprime falhas geralmente vistas em meses ou anos para algumas horas. A combinação de falhas intercaladas com a alta taxa de falhas encontra casos de esquina que, de outra forma, seriam perdidos. Isso leva a uma melhoria significativa na qualidade do código do serviço.

Falhas simuladas no teste de caos

  • Reiniciar um nó
  • Reiniciar um pacote de código implantado
  • Remover uma réplica
  • Reiniciar uma réplica
  • Mover uma réplica primária (opcional)
  • Mover uma réplica secundária (opcional)

O teste de caos executa várias iterações de falhas e validações de cluster pelo período de tempo especificado. O tempo gasto para que o cluster se estabilize e para que a validação seja bem-sucedida também é configurável. O cenário falha quando você atinge uma única falha na validação de cluster.

Por exemplo, considere um conjunto de testes para ser executado por uma hora com um máximo de três falhas simultâneas. O teste induzirá três falhas e, em seguida, validará a integridade do cluster. O teste irá iterar através da etapa anterior até que o cluster se torne insalubre ou uma hora passe. Se o cluster não estiver íntegro em qualquer iteração, ou seja, não estabilizar dentro de um tempo configurado, o teste falhará com uma exceção. Esta exceção indica que algo correu mal e necessita de uma investigação mais aprofundada.

Na sua forma atual, o motor de geração de falhas no teste de caos induz apenas falhas seguras. Isso significa que, na ausência de falhas externas, um quórum ou perda de dados nunca ocorrerá.

Opções de configuração importantes

  • TimeToRun: Tempo total que o teste será executado antes de terminar com sucesso. O teste pode terminar mais cedo em vez de uma falha de validação.
  • MaxClusterStabilizationTimeout: Tempo máximo de espera para que o cluster se torne íntegro antes de falhar no teste. As verificações realizadas são se a integridade do cluster está OK, se a integridade do serviço está OK, se o tamanho do conjunto de réplicas de destino foi atingido para a partição de serviço e se não existem réplicas do InBuild.
  • MaxConcurrentFaults: Número máximo de falhas simultâneas induzidas em cada iteração. Quanto maior o número, mais agressivo é o teste, resultando em failovers e combinações de transição mais complexos. O teste garante que, na ausência de falhas externas, não haverá quórum ou perda de dados, independentemente de quão alta seja essa configuração.
  • EnableMoveReplicaFaults: habilita ou desabilita as falhas que estão causando a movimentação das réplicas primárias ou secundárias. Essas falhas são desabilitadas por padrão.
  • WaitTimeBetweenIterations: Quantidade de tempo para esperar entre iterações, ou seja, após uma rodada de falhas e validação correspondente.

Como executar o teste de caos

Exemplo C#

using System;
using System.Fabric;
using System.Fabric.Testability.Scenario;
using System.Threading;
using System.Threading.Tasks;

class Test
{
    public static int Main(string[] args)
    {
        string clusterConnection = "localhost:19000";

        Console.WriteLine("Starting Chaos Test Scenario...");
        try
        {
            RunChaosTestScenarioAsync(clusterConnection).Wait();
        }
        catch (AggregateException ae)
        {
            Console.WriteLine("Chaos Test Scenario did not complete: ");
            foreach (Exception ex in ae.InnerExceptions)
            {
                if (ex is FabricException)
                {
                    Console.WriteLine("HResult: {0} Message: {1}", ex.HResult, ex.Message);
                }
            }
            return -1;
        }

        Console.WriteLine("Chaos Test Scenario completed.");
        return 0;
    }

    static async Task RunChaosTestScenarioAsync(string clusterConnection)
    {
        TimeSpan maxClusterStabilizationTimeout = TimeSpan.FromSeconds(180);
        uint maxConcurrentFaults = 3;
        bool enableMoveReplicaFaults = true;

        // Create FabricClient with connection and security information here.
        FabricClient fabricClient = new FabricClient(clusterConnection);

        // The chaos test scenario should run at least 60 minutes or until it fails.
        TimeSpan timeToRun = TimeSpan.FromMinutes(60);
        ChaosTestScenarioParameters scenarioParameters = new ChaosTestScenarioParameters(
          maxClusterStabilizationTimeout,
          maxConcurrentFaults,
          enableMoveReplicaFaults,
          timeToRun);

        // Other related parameters:
        // Pause between two iterations for a random duration bound by this value.
        // scenarioParameters.WaitTimeBetweenIterations = TimeSpan.FromSeconds(30);
        // Pause between concurrent actions for a random duration bound by this value.
        // scenarioParameters.WaitTimeBetweenFaults = TimeSpan.FromSeconds(10);

        // Create the scenario class and execute it asynchronously.
        ChaosTestScenario chaosScenario = new ChaosTestScenario(fabricClient, scenarioParameters);

        try
        {
            await chaosScenario.ExecuteAsync(CancellationToken.None);
        }
        catch (AggregateException ae)
        {
            throw ae.InnerException;
        }
    }
}

PowerShell

O módulo PowerShell do Service Fabric inclui duas maneiras de iniciar um cenário de caos. Invoke-ServiceFabricChaosTestScenario é baseado no cliente e, se a máquina cliente for desligada no meio do teste, nenhuma outra falha será introduzida. Como alternativa, há um conjunto de comandos destinados a manter o teste em execução no caso de desligamento da máquina. Start-ServiceFabricChaos usa um serviço de sistema stateful e confiável chamado FaultAnalysisService, garantindo que as falhas permaneçam introduzidas até que o TimeToRun termine. Stop-ServiceFabricChaos pode ser usado para parar manualmente o cenário e Get-ServiceFabricChaosReport obterá um relatório. Para obter mais informações, consulte a referência do PowerShell do Azure Service Fabric e Induzindo o caos controlado em clusters do Service Fabric.

$connection = "localhost:19000"
$timeToRun = 60
$maxStabilizationTimeSecs = 180
$concurrentFaults = 3
$waitTimeBetweenIterationsSec = 60

Connect-ServiceFabricCluster $connection

Invoke-ServiceFabricChaosTestScenario -TimeToRunMinute $timeToRun -MaxClusterStabilizationTimeoutSec $maxStabilizationTimeSecs -MaxConcurrentFaults $concurrentFaults -EnableMoveReplicaFaults -WaitTimeBetweenIterationsSec $waitTimeBetweenIterationsSec

Teste de failover

O cenário de teste de failover é uma versão do cenário de teste de caos que tem como alvo uma partição de serviço específica. Ele testa o efeito do failover em uma partição de serviço específica, deixando os outros serviços inalterados. Depois de configurado com as informações da partição de destino e outros parâmetros, ele é executado como uma ferramenta do lado do cliente que usa APIs C# ou PowerShell para gerar falhas para uma partição de serviço. O cenário itera por meio de uma sequência de falhas simuladas e validação de serviço enquanto sua lógica de negócios é executada ao lado para fornecer uma carga de trabalho. Uma falha na validação do serviço indica um problema que precisa de mais investigação.

Falhas simuladas no teste de failover

  • Reiniciar um pacote de código implantado onde a partição está hospedada
  • Remover uma réplica primária/secundária ou instância sem monitoração de estado
  • Reiniciar uma réplica secundária primária (se um serviço persistir)
  • Mover uma réplica principal
  • Mover uma réplica secundária
  • Reinicie a partição

O teste de failover induz uma falha escolhida e, em seguida, executa a validação no serviço para garantir sua estabilidade. O teste de failover induz apenas uma falha de cada vez, em oposição a possíveis falhas múltiplas no teste de caos. Se a partição de serviço não estabilizar dentro do tempo limite configurado após cada falha, o teste falhará. O teste induz apenas falhas seguras. Isso significa que, na ausência de falhas externas, não ocorrerá quórum ou perda de dados.

Opções de configuração importantes

  • PartitionSelector: objeto seletor que especifica a partição que precisa ser direcionada.
  • TimeToRun: Tempo total que o teste será executado antes de terminar.
  • MaxServiceStabilizationTimeout: Tempo máximo de espera para que o cluster se torne íntegro antes de falhar no teste. As verificações realizadas são se a integridade do serviço está OK, se o tamanho do conjunto de réplicas de destino foi atingido para todas as partições e se não existem réplicas do InBuild.
  • WaitTimeBetweenFaults: Quantidade de tempo de espera entre cada falha e ciclo de validação.

Como executar o teste de failover

C#

using System;
using System.Fabric;
using System.Fabric.Testability.Scenario;
using System.Threading;
using System.Threading.Tasks;

class Test
{
    public static int Main(string[] args)
    {
        string clusterConnection = "localhost:19000";
        Uri serviceName = new Uri("fabric:/samples/PersistentToDoListApp/PersistentToDoListService");

        Console.WriteLine("Starting Chaos Test Scenario...");
        try
        {
            RunFailoverTestScenarioAsync(clusterConnection, serviceName).Wait();
        }
        catch (AggregateException ae)
        {
            Console.WriteLine("Chaos Test Scenario did not complete: ");
            foreach (Exception ex in ae.InnerExceptions)
            {
                if (ex is FabricException)
                {
                    Console.WriteLine("HResult: {0} Message: {1}", ex.HResult, ex.Message);
                }
            }
            return -1;
        }

        Console.WriteLine("Chaos Test Scenario completed.");
        return 0;
    }

    static async Task RunFailoverTestScenarioAsync(string clusterConnection, Uri serviceName)
    {
        TimeSpan maxServiceStabilizationTimeout = TimeSpan.FromSeconds(180);
        PartitionSelector randomPartitionSelector = PartitionSelector.RandomOf(serviceName);

        // Create FabricClient with connection and security information here.
        FabricClient fabricClient = new FabricClient(clusterConnection);

        // The chaos test scenario should run at least 60 minutes or until it fails.
        TimeSpan timeToRun = TimeSpan.FromMinutes(60);
        FailoverTestScenarioParameters scenarioParameters = new FailoverTestScenarioParameters(
          randomPartitionSelector,
          timeToRun,
          maxServiceStabilizationTimeout);

        // Other related parameters:
        // Pause between two iterations for a random duration bound by this value.
        // scenarioParameters.WaitTimeBetweenIterations = TimeSpan.FromSeconds(30);
        // Pause between concurrent actions for a random duration bound by this value.
        // scenarioParameters.WaitTimeBetweenFaults = TimeSpan.FromSeconds(10);

        // Create the scenario class and execute it asynchronously.
        FailoverTestScenario failoverScenario = new FailoverTestScenario(fabricClient, scenarioParameters);

        try
        {
            await failoverScenario.ExecuteAsync(CancellationToken.None);
        }
        catch (AggregateException ae)
        {
            throw ae.InnerException;
        }
    }
}

PowerShell

$connection = "localhost:19000"
$timeToRun = 60
$maxStabilizationTimeSecs = 180
$waitTimeBetweenFaultsSec = 10
$serviceName = "fabric:/SampleApp/SampleService"

Connect-ServiceFabricCluster $connection

Invoke-ServiceFabricFailoverTestScenario -TimeToRunMinute $timeToRun -MaxServiceStabilizationTimeoutSec $maxStabilizationTimeSecs -WaitTimeBetweenFaultsSec $waitTimeBetweenFaultsSec -ServiceName $serviceName -PartitionKindSingleton