Persistência de dados e serialização em Durable Functions for Funções do Azure

O runtime do Durable Functions persiste automaticamente os parâmetros de função, valores de retorno e outros estados no hub de tarefas para garantir uma execução fiável. No entanto, a quantidade e a frequência dos dados persistidos para o armazenamento durável podem afetar o desempenho do aplicativo e os custos de transação de armazenamento. Dependendo do tipo de dados que seu aplicativo armazena, as políticas de retenção de dados e privacidade também podem precisar ser consideradas.

Este artigo explica que dados são mantidos, como lidar com grandes cargas úteis e dados sensíveis, e como personalizar a serialização para cada linguagem suportada.

Neste artigo:

Conteúdo do Task Hub

Os hubs de tarefas armazenam o estado atual das instâncias e quaisquer mensagens pendentes:

  • Os estados da instância armazenam o status atual e o histórico de uma instância. Para instâncias de orquestração, esse estado inclui o estado de tempo de execução, o histórico de orquestração, entradas, saídas e status personalizado. Para instâncias de entidade, inclui o estado da entidade.
  • As mensagens armazenam entradas ou saídas de funções, cargas úteis de eventos e metadados que são usados para fins internos, como roteamento e correlação de ponta a ponta.

As mensagens são excluídas depois de processadas, mas os estados da instância persistem, a menos que sejam explicitamente excluídas pelo aplicativo ou por um operador. Em particular, um histórico de orquestração permanece armazenado mesmo depois que a orquestração é concluída.

Para obter um exemplo de como estados e mensagens representam o progresso de uma orquestração, consulte o exemplo de execução do hub de tarefas.

Onde e como os estados e as mensagens são representados no armazenamento dependem do provedor de armazenamento. Utilize o Durable Task Scheduler porque fornece uma infraestrutura de back-end gerida para os centros de tarefas e trata do armazenamento de estado subjacente por si. No entanto, o Armazenamento do Azure continua a ser uma opção sólida para cargas de trabalho existentes e para aplicações que querem gerir os seus próprios recursos de armazenamento.

Provedor de armazenamento Como o estado é armazenado Utilização recomendada
Agendador de tarefas durável A orquestração e o estado da entidade são armazenados na infraestrutura de back-end do agendador gerido subjacente a um recurso de hub de tarefas. Opção preferencial para novas aplicações Durable Functions e implementações geridas.
Armazenamento do Azure O estado e as mensagens são representados em filas, tabelas e blobs numa conta do Armazenamento do Azure. Boa opção para aplicações ou implementações existentes que já dependem do Armazenamento do Azure.

Tipos de dados que são serializados e persistem

A lista seguinte mostra os diferentes tipos de dados que serão serializados e persistirão ao utilizar funcionalidades do Durable Functions:

  • Todas as entradas e saídas das funções de orquestrador, de atividade e de entidade, incluindo quaisquer IDs e exceções não tratadas.
  • Nomes de funções de orquestrador, atividade e entidade
  • Nomes de eventos externos e cargas úteis
  • Cargas úteis de estado de orquestração personalizadas
  • Mensagens de encerramento de orquestração
  • Cargas úteis duráveis do temporizador
  • Solicitações e respostas HTTP duráveis: URLs, cabeçalhos e cargas úteis
  • Cargas úteis de entidades para chamada e sinalização
  • Cargas úteis do estado de entidade

Para orientações sobre a gestão do tamanho da carga útil e proteção de itens sensíveis nesta lista, consulte as secções seguintes.

Mantenha as entradas e saídas das Durable Functions pequenas

Você pode enfrentar problemas de memória se fornecer grandes entradas e saídas para as APIs de Funções Duráveis. As entradas e saídas são serializadas no histórico de orquestração, o que significa que grandes cargas úteis podem, ao longo do tempo, contribuir significativamente para o crescimento ilimitado do histórico. Este crescimento corre o risco de causar exceções de memória durante a repetição.

Para mitigar o impacto de grandes entradas e saídas, pode:

  • Delegar trabalho aos suborquestradores para equilibrar a carga da memória histórica entre múltiplos orquestradores, mantendo a pegada de memória das histórias individuais pequena.
  • Armazene grandes volumes de dados em armazenamento externo (como o Armazenamento de Blobs do Azure) e passe identificadores leves que permitem recuperar esses dados dentro das funções de atividade quando necessário.

Para o Durable Task Scheduler, utilize o suporte para payloads de grande dimensão para descarregar payloads maiores para o Armazenamento de Blobs do Azure. Para novas aplicações, este padrão é recomendado quando uma orquestração tem de passar grandes volumes de dados entre operações duráveis. Se utilizar o provedor de Armazenamento do Azure, pode ainda aplicar o padrão claim-check apresentado na secção seguinte e passar referências simples entre operações.

Tip

A melhor prática para lidar com grandes volumes de dados é mantê-los em armazenamento externo e materializar esses dados apenas dentro das atividades, quando necessário.

Transmitir referências para payloads de grandes dimensões

Escolha o padrão que se adequa ao seu fornecedor de armazenamento.

Agendador de tarefas durável

Se utilizar o Durable Task Scheduler, ative o suporte para payloads grandes para que o runtime grave payloads maiores no Armazenamento de Blobs do Azure e envie uma pequena referência através do scheduler. Uma configuração típica é apresentada na documentação do escalonador:

{
  "version": "2.0",
  "extensions": {
    "durableTask": {
      "storageProvider": {
        "type": "azureManaged",
        "connectionStringName": "DTS_CONNECTION_STRING",
        "payloadStorageEnabled": true,
        "payloadStorageThresholdBytes": 262144
      },
      "hubName": "%TASKHUB_NAME%"
    }
  }
}
Armazenamento do Azure

Com o fornecedor de Armazenamento do Azure, pode utilizar o padrão Claim Check para manter reduzido o histórico de orquestração, continuando a processar payloads de grande dimensão. O orquestrador passa uma referência simples que contém o contentor de blobs e o nome do blob, e a atividade lê ou escreve a carga útil do Armazenamento de Blobs do Azure, conforme necessário.

Os exemplos seguintes assumem que já tem um blob na sua conta de armazenamento. Inicie a orquestração com uma referência como {"container":"large-payloads","blobName":"input/job-123.json"}. A atividade cria o recipiente de saída processed-payloads, se necessário. O passo de processamento do exemplo copia os bytes de entrada sem alterações; substitua-o pela lógica da sua aplicação.

Importante

Nunca inclua credenciais de armazenamento ou uma assinatura de acesso partilhado (SAS) na referência. O sistema mantém a referência na história da orquestração. Estes exemplos usam uma configuração de aplicação nomeada PAYLOAD_STORAGE_CONNECTION_STRING para manter o código de armazenamento conciso. Para cargas de trabalho de produção, use o Microsoft Entra ID para autorizar o acesso a dados de blobs.

Este exemplo requer o Azure. Storage.Blobs pacote NuGet.

using System;
using System.Threading.Tasks;
using Azure.Storage.Blobs;
using Microsoft.Azure.Functions.Worker;
using Microsoft.DurableTask;

public record BlobReference(string Container, string BlobName);

public static class LargePayloadFunctions
{
    [Function("ProcessLargePayload")]
    public static async Task<BlobReference> RunOrchestrator(
        [OrchestrationTrigger] TaskOrchestrationContext context)
    {
        BlobReference inputReference = context.GetInput<BlobReference>()
            ?? throw new InvalidOperationException("A blob reference is required.");

        return await context.CallActivityAsync<BlobReference>(
            nameof(ProcessLargePayloadActivity), inputReference);
    }

    [Function(nameof(ProcessLargePayloadActivity))]
    public static async Task<BlobReference> ProcessLargePayloadActivity(
        [ActivityTrigger] BlobReference inputReference)
    {
        string connectionString =
            Environment.GetEnvironmentVariable("PAYLOAD_STORAGE_CONNECTION_STRING")
            ?? throw new InvalidOperationException("Payload storage is not configured.");
        BlobServiceClient service = new BlobServiceClient(connectionString);

        BlobClient inputBlob = service
            .GetBlobContainerClient(inputReference.Container)
            .GetBlobClient(inputReference.BlobName);
        BinaryData inputData = (await inputBlob.DownloadContentAsync()).Value.Content;

        BlobContainerClient outputContainer =
            service.GetBlobContainerClient("processed-payloads");
        await outputContainer.CreateIfNotExistsAsync();

        string outputName = $"processed/{Guid.NewGuid():N}.json";
        await outputContainer.GetBlobClient(outputName)
            .UploadAsync(inputData, overwrite: true);

        return new BlobReference(outputContainer.Name, outputName);
    }
}

Se atividades paralelas produzirem múltiplos resultados grandes, devolve uma lista de referências e passa essa lista para uma atividade final de agregação. A atividade de agregação deve carregar e combinar as cargas úteis e depois escrever um blob final de saída. Não carregue nem concatene resultados de grande dimensão no orquestrador.

Trabalho com dados sensíveis

As entradas e saídas (incluindo exceções) para e das APIs Durable Functions são mantidas de forma duradoura no seu fornecedor de armazenamento preferência. Se essas entradas, saídas ou exceções contiverem dados sensíveis (como segredos, cadeias de ligação ou informações pessoais identificáveis), qualquer pessoa com acesso de leitura aos recursos do seu fornecedor de armazenamento pode obtê-los.

Para lidar com dados sensíveis de forma segura, obtém esses dados dentro das funções de atividade a partir do Azure Key Vault ou de variáveis de ambiente, e nunca comuniques esses dados diretamente para ou a partir de orquestradores ou entidades. Esta abordagem ajuda a evitar que dados sensíveis escapem para os seus recursos de armazenamento.

De forma semelhante, o acesso de escrita aos recursos de armazenamento deve ser rigidamente controlado, pois dados adulterados no armazenamento podem alterar o comportamento de orquestração. Para mais informações sobre como proteger o armazenamento do seu hub de tarefas, consulte Proteger o armazenamento do seu hub de tarefas.

Tip

Esta orientação aplica-se também à CallHttp API do orquestrador, que mantém os seus payloads de pedido e resposta em armazenamento. Se os seus endpoints HTTP de destino requerem autenticação, implemente a chamada HTTP dentro de uma atividade, ou use o suporte de identidade gerida incorporado oferecido pelo CallHttp, que não mantém as credenciais no armazenamento.

Note

Evite registar dados que contenham segredos, pois qualquer pessoa com acesso de leitura aos seus registos (por exemplo, no Application Insights) poderia obter esses segredos.

Encriptação em repouso

Ao utilizar o fornecedor Armazenamento do Azure, todos os dados são automaticamente encriptados em repouso. No entanto, qualquer pessoa com acesso à conta de armazenamento pode ler os dados em sua forma não criptografada. Se você precisar de uma proteção mais forte para dados confidenciais, considere primeiro criptografar os dados usando suas próprias chaves de criptografia para que os dados persistam em sua forma pré-criptografada.

Como alternativa, os usuários do .NET têm a opção de implementar provedores de serialização personalizados que fornecem criptografia automática. Um exemplo de serialização personalizada com criptografia pode ser encontrado neste exemplo do GitHub.

Note

Se você decidir implementar a criptografia no nível do aplicativo, esteja ciente de que orquestrações e entidades podem existir por períodos indefinidos de tempo. Isso é importante quando for necessário rodar as suas chaves de criptografia, porque uma orquestração ou entidades podem ser executadas por mais tempo do que a sua política de rotação de chaves. Se ocorrer uma rotação de chaves, a chave usada para encriptar os seus dados pode não estar mais disponível para desencriptá-los na próxima vez que a sua orquestração ou entidade seja executada. A encriptação personalizada é, portanto, recomendada apenas quando se espera que orquestrações e entidades corram por períodos relativamente curtos.

Proteja o armazenamento do seu centro de tarefas

O backend de armazenamento que aloja o seu hub de tarefas é uma fronteira de confiança crítica. O Durable Task Framework confia nos dados que lê do armazenamento durante a reprodução de orquestração e o processamento de mensagens. Qualquer pessoa com acesso de escrita ao armazenamento do hub de tarefas pode alterar o estado de orquestração, mensagens pendentes ou cargas úteis armazenadas. Isto pode alterar o comportamento da aplicação, desencadear ações não intencionais ou permitir a execução remota de código no contexto da sua aplicação funcional.

Importante

Não exponha as credenciais de armazenamento do seu Task Hub nem conceda acesso de escrita a partes não confiáveis. O acesso de escrita ao armazenamento do Task Hub pode ser usado para alterar o comportamento da aplicação, incluindo o desencadeamento da execução arbitrária de código.

Responsabilidade partilhada

Proteger o backend de armazenamento é da tua responsabilidade, tal como proteger qualquer base de dados que armazene o estado ou código da aplicação. O Durable Task Framework não realiza verificação de integridade dos dados armazenados, por isso depende dos controlos de acesso da camada de armazenamento para evitar modificações não autorizadas.

Backend Responsabilidade de segurança Orientação
Agendador de tarefas durável A Microsoft gere o backend de armazenamento subjacente. Geres identidades, acesso ao Task Hub e segurança ao nível da aplicação. Padrão preferencial para novas aplicações Durable Functions.
Armazenamento do Azure e outros fornecedores BYO Geres a conta de armazenamento ou base de dados e os seus controlos de segurança. Boa opção para cargas de trabalho ou implementações existentes que já dependem do Armazenamento do Azure.

Note

Não partilhe um único hub de tarefas entre inquilinos não confiáveis. Um hub de tarefas não impõe limites de acesso entre os seus utilizadores, por isso qualquer inquilino que consiga ler ou escrever no hub pode afetar todas as orquestrações e entidades dentro dele. Da mesma forma, não confie em centros de tarefas separados dentro do mesmo backend como um limite de segurança. Enquanto o Durable Task Scheduler suporta RBAC com âmbito para cada task hub, controlos de rede como listas de autorização IP e endpoints privados aplicam-se apenas ao nível do scheduler, pelo que os task hubs dentro de um scheduler não constituem uma fronteira de isolamento de segurança. O mesmo se aplica aos fornecedores de armazenamento BYO — qualquer inquilino com acesso à conta ou base de dados de armazenamento pode aceder a todos os centros de tarefas nesse backend. Quando precisar de isolamento de segurança entre inquilinos, providencie infraestruturas separadas para cada inquilino: contas de armazenamento ou bases de dados separadas para fornecedores BYO, ou instâncias separadas do Durable Task Scheduler.

Lista de verificação do endurecimento de armazenamento

Aplique as seguintes melhores práticas para proteger o armazenamento do seu hub de tarefas:

  • Use ligações baseadas em identidade para o backend que escolher.

    • Com o Durable Task Scheduler, confie em identidades geridas e RBAC para o agendador e os centros de tarefas.
    • Com o Armazenamento do Azure e outros fornecedores BYO, dê preferência a uma identidade gerida em vez de cadeias de ligação, sempre que possível.

    Veja Configurar uma identidade gerida para Durable Functions.

  • Aplique funções RBAC de privilégio mínimo. Conceda apenas as permissões mínimas exigidas. Evite conceder acesso amplo a armazenamento a utilizadores ou serviços que não precisem.

  • Restrinja o acesso à rede à sua conta de armazenamento ou à implementação do Scheduler através de endpoints privados ou endpoints de serviço. Esta restrição ajuda a prevenir o acesso não autorizado a nível de rede aos dados do centro de tarefas.

  • Monitorize o acesso ao armazenamento ativando registos de recursos Azure Monitor para a sua conta de armazenamento, especialmente a categoria de registo StorageWrite. Encaminhe estes registos para um destino fora da conta de armazenamento monitorizada, como o Log Analytics, para que não possam ser adulterados. Consulte Registos de armazenamento.

  • Roda as credenciais regularmente se usares strings de ligação. Trate as chaves de conta de armazenamento com o mesmo cuidado que qualquer outra credencial de alto privilégio.

  • Considere um backend de armazenamento gerido. O Durable Task Scheduler trata automaticamente da segurança do armazenamento, incluindo autenticação, RBAC e isolamento de rede, enquanto o Armazenamento do Azure oferece controlo explícito de armazenamento.

Personalizar serialização e desserialização

As opções de personalização de serialização variam consoante a língua. Selecione o separador de idioma para ver as opções disponíveis.

.NET Isolated e System.Text.Json

As Durable Functions em execução no processo de trabalho isolado do .NET utilizam o mesmo serializador de objetos configurado globalmente na sua aplicação Funções do Azure (consulte WorkerOptions). Este serializador é System.Text.Json por defeito em vez de Newtonsoft.Json. Quaisquer alterações em WorkerOptions.Serializer aplicam-se também transitivamente às Durable Functions.

Para mais informações sobre o suporte incorporado para serialização JSON no .NET, consulte a documentação de visão geral sobre serialização e desserialização JSON no .NET.

Passos seguintes