Compartilhar via


Manter os dados de tarefa para o Armazenamento do Azure com a API de serviço de lote

Uma tarefa em execução no Lote do Azure pode produzir dados de saída quando é executada. Os dados de saída da tarefa geralmente precisam ser armazenados para recuperação por outras tarefas no trabalho, pelo aplicativo cliente que executou o trabalho ou ambos. As tarefas gravam dados de saída no sistema de arquivos de um nó de computação do Lote, mas todos os dados no nó serão perdidos quando ele for reimaginado ou quando o nó deixar o pool. As tarefas também podem ter um período de retenção de arquivo, após o qual os arquivos criados pela tarefa são excluídos. Por esses motivos, é importante manter a saída da tarefa que você vai precisar posteriormente para um repositório de dados, como o Armazenamento do Azure.

Para opções de conta de armazenamento do Lote, confira Contas do Lote e contas do Armazenamento do Azure.

A API de serviço de Lote dá suporte a dados de saída persistentes para o Armazenamento do Azure em tarefas e tarefas do gerenciador de trabalho que são executadas em pools com Configuração de Máquina Virtual. Ao adicionar uma tarefa, você pode especificar um contêiner no Armazenamento do Azure como o destino para a saída da tarefa. Em seguida, o serviço de lote grava quaisquer dados de saída nesse contêiner quando a tarefa é concluída.

Ao usar a API de serviço do Batch para persistir a saída da tarefa, você não precisa modificar o aplicativo onde a tarefa está sendo executada. Em vez disso, com algumas modificações em seu aplicativo cliente, você pode armazenar a saída da tarefa no mesmo trecho de código que cria a tarefa.

Importante

A persistência de dados de tarefa para o Armazenamento do Microsoft Azure usando a API do serviço de Lote não funciona com pools criados antes de 1º de fevereiro de 2018.

Quando devo usar a API do serviço Batch para salvar os resultados da tarefa?

O Azure Batch fornece mais de uma forma de armazenar a saída da tarefa. Usar a API de serviço de lote é uma abordagem conveniente que é mais adequada para esses cenários:

  • Você deseja escrever código para manter a saída da tarefa de dentro de seu aplicativo cliente, sem modificar o aplicativo em que sua tarefa está sendo executada.
  • Você deseja manter a saída das tarefas em Lote e as tarefas do gerenciador de trabalho em pools criados com a configuração de máquina virtual.
  • Você quer armazenar a saída em um container de Armazenamento do Azure com um nome arbitrário.
  • Você deseja manter a saída a um contêiner de Armazenamento do Azure nomeado de acordo com o padrão de Convenções de Arquivo em Lotes.

Se o cenário for diferente daqueles listados acima, talvez seja necessário considerar uma abordagem diferente. Por exemplo, a API do serviço Batch atualmente não suporta streaming de saída para o Armazenamento do Azure enquanto a tarefa está em execução. Para fazer streaming da saída, considere usar a biblioteca Batch File Conventions, disponível para .NET. Para outros idiomas, você precisará implementar sua própria solução. Para obter mais informações sobre outras opções, confira Manter trabalho e saída de tarefa no Armazenamento do Azure.

Criar um contêiner no Armazenamento do Azure

Para persistir a saída da tarefa no Armazenamento do Azure, você precisará criar um contêiner que serve como destino para seus arquivos de saída. Crie o contêiner antes de executar sua tarefa, preferencialmente antes de enviar seu trabalho, usando a biblioteca de clientes ou o SDK do Armazenamento do Azure apropriado. Para obter mais informações sobre AS APIs de Armazenamento do Azure, consulte a documentação do Armazenamento do Azure.

Por exemplo, se você estiver escrevendo seu aplicativo em C#, use a biblioteca cliente do Azure Storage para .NET. O exemplo a seguir mostra como criar um contêiner:

CloudBlobContainer container = storageAccount.CreateCloudBlobClient().GetContainerReference(containerName);
await container.CreateIfNotExists();

Especificar arquivos de saída para a saída da tarefa

Para especificar arquivos de saída para uma tarefa, crie uma coleção de objetos OutputFile e atribua-os à propriedade CloudTask.OutputFiles ao criar a tarefa. Você pode usar uma SAS (Assinatura de Acesso Compartilhado) ou uma identidade gerenciada para autenticar o acesso ao contêiner.

Usando uma assinatura de acesso compartilhado

Depois de criar o contêiner, obtenha uma SAS (assinatura de acesso compartilhado) com acesso de gravação ao contêiner. Uma SAS fornece acesso delegado ao contêiner. A SAS concede acesso com um conjunto especificado de permissões e em um intervalo de tempo especificado. O serviço de Lote precisa de uma SAS com permissões de gravação para gravar a saída da tarefa no contêiner. Para obter mais informações sobre SAS, consulte Usando SAS (assinaturas de acesso compartilhado) no Armazenamento do Azure.

Quando você obtém uma SAS usando as APIs de Armazenamento do Azure, a API retorna uma cadeia de caracteres de token SAS. Essa cadeia de caracteres de token inclui todos os parâmetros da SAS, incluindo as permissões e o intervalo sobre o qual a SAS é válida. Para usar a SAS para acessar um contêiner no Armazenamento do Azure, você precisa acrescentar a cadeia de caracteres de token SAS ao URI do recurso. O URI do recurso, juntamente com o token SAS acrescentado, fornece acesso autenticado ao Armazenamento do Azure.

O exemplo a seguir mostra como obter uma string de token SAS somente para gravação para o contêiner e acrescentar o SAS ao URI do contêiner:

string containerSasToken = container.GetSharedAccessSignature(new SharedAccessBlobPolicy()
{
    SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddDays(1),
    Permissions = SharedAccessBlobPermissions.Write
});

string containerSasUrl = container.Uri.AbsoluteUri + containerSasToken;

O exemplo de código C# a seguir cria uma tarefa que grava números aleatórios em um arquivo chamado output.txt. O exemplo cria um arquivo de saída para ser gravado no contêiner output.txt. O exemplo também cria arquivos de saída para todos os arquivos de log que correspondem ao padrão std*.txt de arquivo (por exemplo, stdout.txt e stderr.txt). A URL do contêiner requer a SAS que foi criada anteriormente para o contêiner. O serviço de Lote usa o SAS para autenticar o acesso ao contêiner.

new CloudTask(taskId, "cmd /v:ON /c \"echo off && set && (FOR /L %i IN (1,1,100000) DO (ECHO !RANDOM!)) > output.txt\"")
{
    OutputFiles = new List<OutputFile>
    {
        new OutputFile(
            filePattern: @"..\std*.txt",
            destination: new OutputFileDestination(
         new OutputFileBlobContainerDestination(
                    containerUrl: containerSasUrl,
                    path: taskId)),
            uploadOptions: new OutputFileUploadOptions(
            uploadCondition: OutputFileUploadCondition.TaskCompletion)),
        new OutputFile(
            filePattern: @"output.txt",
            destination: 
         new OutputFileDestination(new OutputFileBlobContainerDestination(
                    containerUrl: containerSasUrl,
                    path: taskId + @"\output.txt")),
            uploadOptions: new OutputFileUploadOptions(
            uploadCondition: OutputFileUploadCondition.TaskCompletion)),
}

Observação

Se estiver usando este exemplo com o Linux, altere as barras invertidas (\) para barras comuns (/).

Usando a Identidade Gerenciada

Em vez de gerar e passar uma SAS com acesso de gravação ao contêiner para o Lote, uma identidade gerenciada pode ser usada para autenticar com o Armazenamento do Microsoft Azure. A identidade deve ser atribuída ao Pool do Lote e também ter a atribuição de função Storage Blob Data Contributor para o contêiner a ser gravado. Em seguida, o serviço Batch pode ser orientado a usar a identidade gerenciada em vez de uma SAS para autenticar o acesso ao contêiner.

CloudBlobContainer container = storageAccount.CreateCloudBlobClient().GetContainerReference(containerName);
await container.CreateIfNotExists();

new CloudTask(taskId, "cmd /v:ON /c \"echo off && set && (FOR /L %i IN (1,1,100000) DO (ECHO !RANDOM!)) > output.txt\"")
{
    OutputFiles = new List<OutputFile>
    {
        new OutputFile(
            filePattern: @"..\std*.txt",
            destination: new OutputFileDestination(
         new OutputFileBlobContainerDestination(
                    containerUrl: container.Uri,
                    path: taskId,
                    identityReference: new ComputeNodeIdentityReference() { ResourceId = "/subscriptions/SUB/resourceGroups/RG/providers/Microsoft.ManagedIdentity/userAssignedIdentities/identity-name"} })),
            uploadOptions: new OutputFileUploadOptions(
            uploadCondition: OutputFileUploadCondition.TaskCompletion))
    }
}

Especificar um padrão de arquivo para correspondência

Ao especificar um arquivo de saída, você pode usar a propriedade OutputFile.FilePattern para especificar um padrão de arquivo para correspondência. O padrão de arquivo pode corresponder a zero arquivos, um único arquivo ou um conjunto de arquivos criados pela tarefa.

A propriedade FilePattern dá suporte a curingas do sistema de arquivos padrão, como * (para correspondências não recursivas) e ** (para correspondências recursivas). Por exemplo, o exemplo de código acima especifica o padrão de arquivo para corresponder std*.txt não recursiva:

filePattern: @"..\std*.txt"

Para carregar um único arquivo, especifique um padrão de arquivo sem curingas. Por exemplo, o exemplo de código acima especifica o padrão de arquivo para corresponder output.txt:

filePattern: @"output.txt"

Especificar uma condição de upload

A propriedade OutputFileUploadOptions.UploadCondition permite o carregamento condicional de arquivos de saída. Um cenário comum é carregar um conjunto de arquivos se a tarefa for bem-sucedida e um conjunto diferente de arquivos se falhar. Por exemplo, talvez você queira carregar arquivos de log detalhados somente quando a tarefa falhar e sair com um código de saída diferente de zero. Da mesma forma, talvez você queira carregar arquivos de resultados somente se a tarefa for bem-sucedida, pois esses arquivos poderão estar ausentes ou incompletos se a tarefa falhar.

O exemplo de código acima define a propriedade UploadCondition como TaskCompletion. Essa configuração especifica que o arquivo deve ser carregado após a conclusão das tarefas, independentemente do valor do código de saída.

uploadCondition: OutputFileUploadCondition.TaskCompletion

Para outras configurações, consulte a enum OutputFileUploadCondition.

Desambiguar arquivos com o mesmo nome

As tarefas em um trabalho podem produzir arquivos com o mesmo nome. Por exemplo, stdout.txt e stderr.txt são criados para cada tarefa executada em um trabalho. Como cada tarefa é executada em seu próprio contexto, esses arquivos não estão em conflito no sistema de arquivos do nó. No entanto, ao carregar arquivos de várias tarefas para um contêiner compartilhado, você precisará desambiguar arquivos com o mesmo nome.

A propriedade OutputFileBlobContainerDestination.Path especifica o blob de destino ou o diretório virtual como arquivos de saída. Você pode usar a propriedade Path para nomear o blob ou o diretório virtual de forma que os arquivos de saída com o mesmo nome sejam nomeados exclusivamente no Armazenamento do Azure. Usar a ID da tarefa no caminho é uma boa maneira de garantir nomes exclusivos e identificar arquivos facilmente.

Se a propriedade FilePattern for definida como uma expressão curinga, todos os arquivos que correspondem ao padrão serão carregados no diretório virtual especificado pela propriedade Path . Por exemplo, se o contêiner for mycontainer, a ID da tarefa for mytaske o padrão de arquivo for ..\std*.txt, as URIs absolutas para os arquivos de saída no Armazenamento do Azure serão semelhantes a:

https://myaccount.blob.core.windows.net/mycontainer/mytask/stderr.txt
https://myaccount.blob.core.windows.net/mycontainer/mytask/stdout.txt

Se a propriedade FilePattern estiver definida para corresponder a um único nome de arquivo, o que significa que não contém caracteres curinga, o valor da propriedade Path especifica o nome de blob totalmente qualificado. Se você prever conflitos de nomenclatura com um único arquivo de várias tarefas, inclua o nome do diretório virtual como parte do nome do arquivo para desambiguar esses arquivos. Por exemplo, defina a propriedade Path para incluir a ID da tarefa, o caractere delimitador (normalmente uma barra de avanço) e o nome do arquivo:

path: taskId + @"/output.txt"

As URIs absolutas para os arquivos de saída de um conjunto de tarefas serão semelhantes a:

https://myaccount.blob.core.windows.net/mycontainer/task1/output.txt
https://myaccount.blob.core.windows.net/mycontainer/task2/output.txt

Para obter mais informações sobre diretórios virtuais no Armazenamento do Azure, consulte Listar os blobs em um contêiner.

Muitos arquivos de saída

Quando uma tarefa especifica vários arquivos de saída, você pode se deparar com limites impostos pela Azure Batch API. É aconselhável manter suas tarefas pequenas e manter o número de arquivos de saída baixo.

Se você encontrar limites, considere reduzir o número de arquivos de saída empregando padrões de arquivo ou usando contêineres de arquivos, como tar ou zip, para consolidar os arquivos de saída. Como alternativa, utilize a montagem ou outras abordagens para persistir os dados de saída (consulte Persistir saída de tarefa e de trabalho).

Diagnosticar erros de upload de arquivo

Se o carregamento de arquivos de saída no Armazenamento do Azure falhar, a tarefa é movida para o estado Concluído e a propriedade TaskExecutionInformation.FailureInformation é definida. Examine a propriedade FailureInformation para determinar qual erro ocorreu. Por exemplo, aqui está um erro que ocorre no upload de arquivo se o contêiner não puder ser encontrado:

Category: UserError
Code: FileUploadContainerNotFound
Message: One of the specified Azure container(s) was not found while attempting to upload an output file

Em cada upload de arquivo, o lote grava dois arquivos de log para o nó de computação, fileuploadout.txt e fileuploaderr.txt. Você pode analisar esses arquivos de log para saber mais sobre uma falha específica. Nos casos em que o upload de arquivo nunca foi tentado, por exemplo, porque a tarefa em si não pôde ser executada, esses arquivos de log não existirão.

Diagnosticar o desempenho de upload de arquivo

O arquivo fileuploadout.txt registra o progresso do upload. Você pode examinar esse arquivo para saber mais sobre quanto tempo seus uploads de arquivo estão demorando. Tenha em mente que há muitos fatores que contribuem para o desempenho de upload, incluindo o tamanho do nó, outra atividade no nó no momento do upload, se o contêiner de destino está na mesma região que o pool de lote, quantos nós estão carregando a conta de armazenamento ao mesmo tempo, e assim por diante.

Usar a API de serviço de lote com o padrão de convenções de arquivo em lotes

Quando você mantém a saída da tarefa com a API de serviço de lote, você pode nomear o contêiner de destino e os blobs como desejar. Você também pode optar por nomeá-los de acordo com o padrão de Convenções de Arquivo em Lotes. O padrão Convenções de Arquivo determina os nomes do contêiner de destino e do blob no Armazenamento do Azure para um determinado arquivo de saída com base nos nomes do trabalho e da tarefa. Se você usar o padrão convenções de arquivo para nomear arquivos de saída, os arquivos de saída estarão disponíveis para exibição no portal do Azure.

Se você estiver desenvolvendo em C#, poderá usar os métodos incorporados à biblioteca de Convenções de Arquivo Batch para .NET. Essa biblioteca cria os contêineres corretamente nomeados e os caminhos de blob para você. Por exemplo, você pode chamar a API para obter o nome correto para o contêiner, com base no nome do trabalho:

string containerName = job.OutputStorageContainerName();

Você pode usar o método CloudJobExtensions.GetOutputStorageContainerUrl para retornar uma URL sas (assinatura de acesso compartilhado) usada para gravar no contêiner. Você pode passar esse SAS ao construtor Output​File​Blob​Container​Destination.

Se você estiver desenvolvendo em um idioma diferente de C#, precisará implementar o padrão convenções de arquivo por conta própria.

Exemplo de código

O projeto de exemplo PersistOutputs é um dos exemplos de código do Lote do Azure no GitHub. Esta solução do Visual Studio demonstra como usar a biblioteca cliente do Batch para .NET para persistir o resultado da tarefa em armazenamento durável. Para executar o exemplo, siga estas etapas:

  1. Abra o projeto no Visual Studio 2019.
  2. Adicione suas credenciais de conta de Lote e Armazenamento a AccountSettings.settings no projeto Microsoft.Azure.Batch.Samples.Common.
  3. Compile (mas não execute) a solução. Restaure todos os pacotes NuGet, se solicitado.
  4. Use o portal do Azure para carregar um pacote de aplicativos para PersistOutputsTask. Inclua o PersistOutputsTask.exe e seus assemblies dependentes no pacote .zip, defina a ID do aplicativo como "PersistOutputsTask" e a versão do pacote de aplicativos como "1.0".
  5. Inicie (execute) o projeto PersistOutputs .
  6. Quando solicitado a escolher a tecnologia de persistência a ser usada para executar o exemplo, insira 2 para executar o exemplo usando a API de serviço Batch para persistir a saída da tarefa.
  7. Se desejado, execute o exemplo novamente, inserindo 3 para manter a saída com a API de serviço de lote e também para nomear o contêiner de destino e o caminho de blob de acordo com o padrão de Convenções de Arquivo.

Próximas etapas