Introdução ao Reliable Services

Uma aplicação do Azure Service Fabric contém um ou mais serviços que executam o código. Este guia mostra-lhe como criar aplicações do Service Fabric sem estado e com estado com o Reliable Services.

Veja esta página para obter um vídeo de formação que também lhe mostra como criar um serviço Reliable sem estado.

Conceitos básicos

Para começar a utilizar o Reliable Services, só precisa de compreender alguns conceitos básicos:

  • Tipo de serviço: esta é a implementação do serviço. É definido pela classe que escreve que expande e quaisquer outros códigos StatelessService ou dependências aí utilizados, juntamente com um nome e um número de versão.
  • Instância de serviço nomeada: para executar o seu serviço, pode criar instâncias nomeadas do seu tipo de serviço, tal como cria instâncias de objetos de um tipo de classe. Uma instância de serviço tem um nome na forma de um URI com os "recursos de infraestrutura:/" esquema, como "fabric:/MyApp/MyService".
  • Anfitrião de serviço: as instâncias de serviço nomeadas que criar têm de ser executadas dentro de um processo de anfitrião. O anfitrião de serviços é apenas um processo em que as instâncias do seu serviço podem ser executadas.
  • Registo do serviço: o registo reúne tudo. O tipo de serviço tem de ser registado no runtime do Service Fabric num anfitrião de serviços para permitir que o Service Fabric crie instâncias do mesmo para ser executado.

Criar um serviço sem estado

Um serviço sem estado é um tipo de serviço que é atualmente a norma nas aplicações na cloud. É considerado sem estado porque o próprio serviço não contém dados que precisam de ser armazenados de forma fiável ou disponibilizados de forma elevada. Se uma instância de um serviço sem estado for encerrada, todo o estado interno será perdido. Neste tipo de serviço, o estado tem de ser mantido num arquivo externo, como tabelas do Azure ou Base de Dados SQL, para que seja disponibilizado de forma altamente disponível e fiável.

Inicie o Visual Studio 2017 ou o Visual Studio 2019 como administrador e crie um novo projeto de aplicação do Service Fabric com o nome HelloWorld:

Utilizar a caixa de diálogo Novo Projeto para criar uma nova aplicação do Service Fabric

Em seguida, crie um projeto de serviço sem estado com o .NET Core 2.0 com o nome HelloWorldStateless:

Na segunda caixa de diálogo, crie um projeto de serviço sem estado

A sua solução contém agora dois projetos:

  • HelloWorld. Este é o projeto de aplicação que contém os seus serviços. Também contém o manifesto da aplicação que descreve a aplicação, bem como vários scripts do PowerShell que o ajudam a implementar a sua aplicação.
  • HelloWorldStateless. Este é o projeto de serviço. Contém a implementação do serviço sem estado.

Implementar o serviço

Abra o ficheiro HelloWorldStateless.cs no projeto de serviço. No Service Fabric, um serviço pode executar qualquer lógica de negócio. A API de serviço fornece dois pontos de entrada para o seu código:

  • Um método de ponto de entrada aberto, denominado RunAsync, onde pode começar a executar quaisquer cargas de trabalho, incluindo cargas de trabalho de computação de execução prolongada.
protected override async Task RunAsync(CancellationToken cancellationToken)
{
    ...
}
  • Um ponto de entrada de comunicação onde pode ligar a sua pilha de comunicação à escolha, como ASP.NET Core. É aqui que pode começar a receber pedidos de utilizadores e outros serviços.
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
    ...
}

Neste tutorial, vamos focar-nos no método de RunAsync() ponto de entrada. É aqui que pode começar imediatamente a executar o código. O modelo de projeto inclui uma implementação de exemplo que RunAsync() incrementa uma contagem sem interrupções.

Nota

Para obter detalhes sobre como trabalhar com uma pilha de comunicação, veja Comunicação do serviço com ASP.NET Core

RunAsync

protected override async Task RunAsync(CancellationToken cancellationToken)
{
    // TODO: Replace the following sample code with your own logic
    //       or remove this RunAsync override if it's not needed in your service.

    long iterations = 0;

    while (true)
    {
        cancellationToken.ThrowIfCancellationRequested();

        ServiceEventSource.Current.ServiceMessage(this.Context, "Working-{0}", ++iterations);

        await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
    }
}

A plataforma chama este método quando uma instância de um serviço é colocada e pronta para ser executada. Para um serviço sem estado, isso significa simplesmente quando a instância de serviço é aberta. É fornecido um token de cancelamento para coordenar quando a instância de serviço precisa de ser fechada. No Service Fabric, este ciclo de abertura/fecho de uma instância de serviço pode ocorrer muitas vezes ao longo da duração do serviço como um todo. Isto pode acontecer por vários motivos, incluindo:

  • O sistema move as instâncias de serviço para balanceamento de recursos.
  • As falhas ocorrem no seu código.
  • A aplicação ou o sistema é atualizado.
  • O hardware subjacente tem uma falha.

Esta orquestração é gerida pelo sistema para manter o seu serviço altamente disponível e devidamente equilibrado.

RunAsync() não deve bloquear de forma síncrona. A implementação do RunAsync deve devolver uma Tarefa ou aguardar por quaisquer operações de execução prolongada ou de bloqueio para permitir que o runtime continue. Tenha em atenção que while(true) , no ciclo do exemplo anterior, é utilizada uma Devolução de tarefas await Task.Delay() . Se a carga de trabalho tiver de bloquear de forma síncrona, deve agendar uma nova Tarefa na Task.Run() sua RunAsync implementação.

O cancelamento da carga de trabalho é um esforço cooperativo orquestrado pelo token de cancelamento fornecido. O sistema aguardará que a tarefa termine (por conclusão, cancelamento ou falha com êxito) antes de avançar. É importante respeitar o token de cancelamento, concluir qualquer trabalho e sair RunAsync() o mais rapidamente possível quando o sistema pedir o cancelamento.

Neste exemplo de serviço sem estado, a contagem é armazenada numa variável local. No entanto, como este é um serviço sem estado, o valor armazenado só existe para o ciclo de vida atual da instância de serviço. Quando o serviço é movido ou reiniciado, o valor é perdido.

Criar um serviço com estado

O Service Fabric apresenta um novo tipo de serviço com monitorização de estado. Um serviço com estado pode manter o estado de forma fiável dentro do próprio serviço, co-localizado com o código que o está a utilizar. O Estado é disponibilizado de forma elevada pelo Service Fabric sem a necessidade de manter o estado num arquivo externo.

Para converter um valor de contador sem estado para altamente disponível e persistente, mesmo quando o serviço é movido ou reiniciado, precisa de um serviço com estado.

Na mesma aplicação HelloWorld , pode adicionar um novo serviço ao clicar com o botão direito do rato nas referências dos Serviços no projeto da aplicação e selecionar Adicionar -> Novo Serviço do Service Fabric.

Adicionar um serviço à sua aplicação do Service Fabric

Selecione .NET Core 2.0 -> Serviço com Estado e dê-lhe o nome HelloWorldStateful. Clique em OK.

Utilizar a caixa de diálogo Novo Projeto para criar um novo serviço com estado do Service Fabric

A sua aplicação deverá agora ter dois serviços: o serviço sem estado HelloWorldStateless e o serviço com estado HelloWorldStateful.

Um serviço com estado tem os mesmos pontos de entrada que um serviço sem estado. A principal diferença é a disponibilidade de um fornecedor de estado que pode armazenar o estado de forma fiável. O Service Fabric inclui uma implementação de fornecedor de estado denominada Reliable Collections, que lhe permite criar estruturas de dados replicadas através do Reliable State Manager. Um Reliable Service com estado utiliza este fornecedor de estado por predefinição.

Abra HelloWorldStateful.cs em HelloWorldStateful, que contém o seguinte método RunAsync:

protected override async Task RunAsync(CancellationToken cancellationToken)
{
    // TODO: Replace the following sample code with your own logic
    //       or remove this RunAsync override if it's not needed in your service.

    var myDictionary = await this.StateManager.GetOrAddAsync<IReliableDictionary<string, long>>("myDictionary");

    while (true)
    {
        cancellationToken.ThrowIfCancellationRequested();

        using (var tx = this.StateManager.CreateTransaction())
        {
            var result = await myDictionary.TryGetValueAsync(tx, "Counter");

            ServiceEventSource.Current.ServiceMessage(this.Context, "Current Counter Value: {0}",
                result.HasValue ? result.Value.ToString() : "Value does not exist.");

            await myDictionary.AddOrUpdateAsync(tx, "Counter", 0, (key, value) => ++value);

            // If an exception is thrown before calling CommitAsync, the transaction aborts, all changes are
            // discarded, and nothing is saved to the secondary replicas.
            await tx.CommitAsync();
        }

        await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
    }

RunAsync

RunAsync() funciona de forma semelhante em serviços com estado e sem estado. No entanto, num serviço com estado, a plataforma realiza trabalho adicional em seu nome antes de executar RunAsync(). Este trabalho pode incluir garantir que o Reliable State Manager e as Reliable Collections estão prontos a utilizar.

Reliable Collections e Reliable State Manager

var myDictionary = await this.StateManager.GetOrAddAsync<IReliableDictionary<string, long>>("myDictionary");

IReliableDictionary é uma implementação de dicionário que pode utilizar para armazenar de forma fiável o estado no serviço. Com o Service Fabric e as Coleções Fiáveis, pode armazenar dados diretamente no seu serviço sem a necessidade de um arquivo persistente externo. As Coleções Fiáveis tornam os seus dados altamente disponíveis. O Service Fabric consegue-o ao criar e gerir várias réplicas do seu serviço por si. Também fornece uma API que abstrai as complexidades da gestão dessas réplicas e das respetivas transições de estado.

As Coleções Fiáveis podem armazenar qualquer tipo de .NET, incluindo os seus tipos personalizados, com algumas ressalvas:

  • O Service Fabric torna o seu estado altamente disponível ao replicar o estado entre nós e as Coleções Fiáveis armazenam os seus dados no disco local em cada réplica. Isto significa que tudo o que é armazenado em Coleções Fiáveis tem de ser serializável. Por predefinição, as Coleções Fiáveis utilizam DataContract para serialização, pelo que é importante garantir que os seus tipos são suportados pelo Serializador de Contratos de Dados quando utiliza o serializador predefinido.

  • Os objetos são replicados para elevada disponibilidade quando consolida transações em Coleções Fiáveis. Os objetos armazenados nas Coleções Fiáveis são mantidos na memória local no seu serviço. Isto significa que tem uma referência local ao objeto.

    É importante que não transforme instâncias locais desses objetos sem efetuar uma operação de atualização na coleção fiável numa transação. Isto deve-se ao facto de as alterações às instâncias locais dos objetos não serem replicadas automaticamente. Tem de voltar a inserir o objeto no dicionário ou utilizar um dos métodos de atualização no dicionário.

O Reliable State Manager gere as Coleções Fiáveis por si. Pode simplesmente pedir ao Reliable State Manager uma coleção fiável por nome em qualquer altura e em qualquer local do seu serviço. O Reliable State Manager garante que obtém uma referência de volta. Não recomendamos que guarde referências a instâncias de coleção fiáveis em variáveis ou propriedades de membros da classe. Tem de ter especial cuidado para garantir que a referência está sempre definida como uma instância no ciclo de vida do serviço. O Reliable State Manager processa este trabalho por si e está otimizado para visitas repetidas.

Operações transacionais e assíncronas

using (ITransaction tx = this.StateManager.CreateTransaction())
{
    var result = await myDictionary.TryGetValueAsync(tx, "Counter-1");

    await myDictionary.AddOrUpdateAsync(tx, "Counter-1", 0, (k, v) => ++v);

    await tx.CommitAsync();
}

As Coleções Fiáveis têm muitas das mesmas operações que os respetivos System.Collections.Generic e System.Collections.Concurrent homólogos, exceto a Consulta Integrada de Idioma (LINQ). As operações nas Coleções Fiáveis são assíncronas. Isto deve-se ao facto de as operações de escrita com Coleções Fiáveis efetuarem operações de E/S para replicar e manter os dados no disco.

As operações de Recolha Fiável são transacionais, para que possa manter o estado consistente em várias Coleções e operações fiáveis. Por exemplo, pode desativar um item de trabalho a partir de uma Fila Fiável, executar uma operação no mesmo e guardar o resultado num Dicionário Fiável, tudo numa única transação. Isto é tratado como uma operação atómica e garante que toda a operação será bem-sucedida ou toda a operação será revertida. Se ocorrer um erro depois de desativar o item, mas antes de guardar o resultado, toda a transação é revertida e o item permanece na fila para processamento.

Executar a aplicação

Voltamos agora à aplicação HelloWorld . Agora pode criar e implementar os seus serviços. Quando prime F5, a aplicação será criada e implementada no cluster local.

Após os serviços começarem a ser executados, pode ver os eventos gerados de Rastreio de Eventos para Windows (ETW) numa janela Eventos de Diagnóstico . Tenha em atenção que os eventos apresentados são do serviço sem estado e do serviço com estado na aplicação. Pode colocar o fluxo em pausa clicando no botão Colocar em Pausa . Em seguida, pode examinar os detalhes de uma mensagem ao expandir essa mensagem.

Nota

Antes de executar a aplicação, certifique-se de que tem um cluster de desenvolvimento local em execução. Consulte o guia de introdução para obter informações sobre como configurar o seu ambiente local.

Ver Eventos de Diagnóstico no Visual Studio

Passos seguintes

Depurar a sua aplicação do Service Fabric no Visual Studio

Introdução: Serviços de API Web do Service Fabric com autoalojação OWIN

Saiba mais sobre coleções fiáveis

Implementar uma aplicação

Atualização da aplicação

Referência do programador para o Reliable Services