快速入门:使用 .NET 创建 Batch 池并运行作业

本快速入门通过运行一个使用 Azure Batch .NET API 的 C# 应用,展示了如何开始使用 Azure Batch。 .NET 应用会:

  • 将多个输入数据文件上传到 Azure 存储 Blob 容器,以供用于 Batch 任务处理。
  • 创建一个池,其中包含两个虚拟机 (VM) 或计算节点(均运行 Windows Server)。
  • 创建一个作业,该作业在节点上运行任务,使用 Windows 命令行处理每个输入文件。
  • 显示各个任务返回的输出文件。

完成本快速入门后,你将了解 Batch 服务的关键概念,并准备好将 Batch 用于更现实、更大规模的工作负载。

先决条件

运行应用

为了完成本快速入门,请下载或克隆应用、提供帐户值、构建和运行应用,并验证输出内容。

下载或克隆该应用

从 GitHub 下载或克隆 Azure Batch .NET 快速入门应用。 若要使用 Git 客户端克隆应用存储库,请使用以下命令:

git clone https://github.com/Azure-Samples/batch-dotnet-quickstart.git

提供帐户信息

该应用需要使用 Batch 和存储帐户名称、帐户密钥值以及 Batch 帐户终结点。 你可以通过 Azure 门户、Azure API 或命令行工具获取这些信息。

若要从 Azure 门户获取帐户信息,请执行以下操作:

  1. 在 Azure 搜索栏中,搜索并选择你的 Batch 帐户名称。
  2. 在 Batch 帐户页面上,从左侧导航栏中选择“密钥”。
  3. 在“密钥”页面上,复制以下值:
  • 批处理帐户
  • 帐户终结点
  • 主访问密钥
  • 存储帐户名称
  • Key1

导航到所下载的 batch-dotnet-quickstart 文件夹,并在 Program.cs 中编辑凭据字符串,以提供复制的值:

// Batch account credentials
private const string BatchAccountName = "<batch account>";
private const string BatchAccountKey  = "<primary access key>";
private const string BatchAccountUrl  = "<account endpoint>";

// Storage account credentials
private const string StorageAccountName = "<storage account name>";
private const string StorageAccountKey  = "<key1>

重要

在实际使用时,不建议在应用源代码中公开帐户密钥。 正确的做法是限制对这些凭据的访问权限,通过使用变量或配置文件来在代码中引用它们。 最好是将 Batch 和存储帐户密钥存储在 Azure 密钥保管库中。

构建和运行应用并查看输出内容

若要 Batch 工作流的操作情况,请在 Visual Studio 中构建并运行应用程序。 还可使用命令行 dotnet builddotnet run 命令。

在 Visual Studio 中:

  1. 打开 BatchDotNetQuickstart.sln 文件,右键单击解决方案资源管理器中的解决方案,然后选择“生成”。 如果出现提示,请使用 NuGet 包管理器来更新或还原 NuGet 包。

  2. 生成完成后,在顶部菜单栏中选择 BatchDotNetQuickstart 来运行应用。

采用默认配置的典型运行时间约为 5 分钟。 初始池节点设置花费的时间最多。 若要重新运行作业,请从以前的运行中删除作业,但不要删除池。 在预配置的池中,该作业数秒即可完成。

该应用将返回类似于以下示例的输出:

Sample start: 11/16/2022 4:02:54 PM

Container [input] created.
Uploading file taskdata0.txt to container [input]...
Uploading file taskdata1.txt to container [input]...
Uploading file taskdata2.txt to container [input]...
Creating pool [DotNetQuickstartPool]...
Creating job [DotNetQuickstartJob]...
Adding 3 tasks to job [DotNetQuickstartJob]...
Monitoring all tasks for 'Completed' state, timeout in 00:30:00...

当池的计算节点启动时,会在 Monitoring all tasks for 'Completed' state, timeout in 00:30:00... 出现暂停。 创建任务后,Batch 会将要在池中运行的任务排队。 在第一个计算节点可用后,第一个任务将在该节点上运行。 你可以从 Azure 门户中的 Batch 帐户页面监视节点、任务和作业状态。

每个任务完成后,都会显示类似于以下示例的输出:

Printing task output.
Task: Task0
Node: tvm-2850684224_3-20171205t000401z
Standard out:
Batch processing began with mainframe computers and punch cards. Today it still plays a central role...
stderr:
...

查看代码

请查看代码,了解 Azure Batch .NET 快速入门中的步骤。

创建服务客户端并上传资源文件

  1. 为了与存储帐户交互,应用会使用适用于 .NET 的 Azure 存储 Blob 客户端库来创建 BlobServiceClient

    var sharedKeyCredential = new StorageSharedKeyCredential(storageAccountName, storageAccountKey);
    string blobUri = "https://" + storageAccountName + ".blob.core.chinacloudapi.cn";
    
    var blobServiceClient = new BlobServiceClient(new Uri(blobUri), sharedKeyCredential);
    return blobServiceClient;
    
  2. 该应用使用 blobServiceClient 引用在存储帐户中创建容器,然后将数据文件上传到该容器。 存储中的文件定义为 Batch ResourceFile 对象,Batch 随后可将这些对象下载到计算节点。

    List<string> inputFilePaths = new()
    {
        "taskdata0.txt",
        "taskdata1.txt",
        "taskdata2.txt"
    };
    
    var inputFiles = new List<ResourceFile>();
    
    foreach (var filePath in inputFilePaths)
    {
        inputFiles.Add(UploadFileToContainer(containerClient, inputContainerName, filePath));
    }
    
  3. 该应用会创建一个 BatchClient 对象,用来创建和管理 Batch 池、作业和任务。 该 Batch 客户端将使用共享密钥身份验证。 Batch 还支持 Microsoft Entra 身份验证。

    var cred = new BatchSharedKeyCredentials(BatchAccountUrl, BatchAccountName, BatchAccountKey);
    
     using BatchClient batchClient = BatchClient.Open(cred);
    ...
    

创建计算节点池

为了创建 Batch 池,应用使用 BatchClient.PoolOperations.CreatePool 方法设置节点数、VM 大小和池配置。 下面的 VirtualMachineConfiguration 对象指定了对 Windows Server 市场映像的 ImageReference。 Batch 支持广泛的 Windows Server 和 Linux 市场 OS 映像,还支持自定义 VM 映像。

PoolNodeCount 和 VM 大小 PoolVMSize 是定义的常量。 该应用会创建一个池包含 2 个 Standard_A1_v2 节点的池。 就此快速入门而言,此节点大小在性能与成本之间达成了很好的平衡。

Commit 方法将池提交到 Batch 服务。


private static VirtualMachineConfiguration CreateVirtualMachineConfiguration(ImageReference imageReference)
{
    return new VirtualMachineConfiguration(
        imageReference: imageReference,
        nodeAgentSkuId: "batch.node.windows amd64");
}

private static ImageReference CreateImageReference()
{
    return new ImageReference(
        publisher: "MicrosoftWindowsServer",
        offer: "WindowsServer",
        sku: "2016-datacenter-smalldisk",
        version: "latest");
}

private static void CreateBatchPool(BatchClient batchClient, VirtualMachineConfiguration vmConfiguration)
{
    try
    {
        CloudPool pool = batchClient.PoolOperations.CreatePool(
            poolId: PoolId,
            targetDedicatedComputeNodes: PoolNodeCount,
            virtualMachineSize: PoolVMSize,
            virtualMachineConfiguration: vmConfiguration);

        pool.Commit();
    }
...

创建 Batch 作业

Batch 作业是对一个或多个任务进行逻辑分组。 该作业包含这些任务的公用设置,例如优先级以及运行任务的池。

应用使用 BatchClient.JobOperations.CreateJob 方法在池中创建作业。 Commit 方法将作业提交到 Batch 服务。 作业一开始没有任务。

try
{
    CloudJob job = batchClient.JobOperations.CreateJob();
    job.Id = JobId;
    job.PoolInformation = new PoolInformation { PoolId = PoolId };

    job.Commit();
}
...

创建任务

Batch 提供了多种将应用和脚本部署到计算节点的方式。 该应用创建 CloudTask 输入 ResourceFile 对象的列表。 每个任务使用 CommandLine 属性来处理输入文件。 可在 Batch 命令行中指定应用或脚本。

以下代码中的命令行运行 Windows type 命令来显示输入文件。 然后,应用使用 AddTask 方法将每个任务添加到作业,使任务按顺序在计算节点上运行。

for (int i = 0; i < inputFiles.Count; i++)
{
    string taskId = String.Format("Task{0}", i);
    string inputFilename = inputFiles[i].FilePath;
    string taskCommandLine = String.Format("cmd /c type {0}", inputFilename);

    var task = new CloudTask(taskId, taskCommandLine)
    {
        ResourceFiles = new List<ResourceFile> { inputFiles[i] }
    };
    tasks.Add(task);
}

batchClient.JobOperations.AddTask(JobId, tasks);

查看任务输出

该应用会创建一个 TaskStateMonitor 来监视任务并确保任务完成。 当每个任务成功运行时,其输出将写入 stdout.txt。 然后,应用使用 CloudTask.ComputeNodeInformation 属性来显示每个已完成的任务的 stdout.txt 文件。

foreach (CloudTask task in completedtasks)
{
    string nodeId = String.Format(task.ComputeNodeInformation.ComputeNodeId);
    Console.WriteLine("Task: {0}", task.Id);
    Console.WriteLine("Node: {0}", nodeId);
    Console.WriteLine("Standard out:");
    Console.WriteLine(task.GetNodeFile(Constants.StandardOutFileName).ReadAsString());
}

清理资源

应用自动删除所创建的存储容器,并允许你选择是否删除 Batch 池和作业。 池和节点会在节点运行时产生费用,即使它们未运行作业也是如此。 不再需要相应池时,请将其删除。

不再需要 Batch 帐户和存储帐户时,可删除包含这些帐户的资源组。 在 Azure 门户,选择资源组页面顶部的“删除资源组”。 在“删除资源组”屏幕上,输入资源组名称,然后选择“删除”。

后续步骤

在本快速入门中,你运行了一个应用,该应用使用 Batch .NET API 来创建 Batch 池、节点、作业和任务。 作业将资源文件上传到存储容器,在节点上运行任务,并显示来自节点的输出。

现在你已经了解了 Batch 服务的关键概念,可以将 Batch 用于更现实、更大规模的工作负载了。 若要详细了解 Azure Batch 并使用实际的应用程序演练并行工作负载,请继续学习 Batch .NET 教程。