用于 JavaScript 的 Batch SDK 入门

了解有关使用 Azure Batch JavaScript SDK 在 JavaScript 中生成 Batch 客户端的基础知识。 我们将循序渐进地了解一个批处理应用程序的方案,然后使用 JavaScript 设置该方案。

必备条件

本文假设你有 JavaScript 的实践知识并熟悉 Linux。 同时还假设你已设置 Azure 帐户并具有创建 Batch 和存储服务所需的访问权限。

我们建议你在完成本文概述的步骤之前,先阅读 Azure Batch 技术概述

了解方案

在这里,我们有一个简单的以 Python 编写的脚本,该脚本从 Azure Blob 存储容器下载所有 csv 文件,并将其转换为 JSON。 若要并行处理多个存储帐户容器,可将脚本部署为 Azure Batch 作业。

Azure Batch 体系结构

下图描绘了如何使用 Azure Batch 和客户端来缩放 Python 脚本。

Diagram showing scenario architecture.

JavaScript 示例使用一个准备任务(稍后将详细介绍),并根据存储帐户中的容器数使用其他一组任务来部署批处理作业。 可以从 GitHub 存储库下载脚本。

提示

指定链接中的 JavaScript 示例不包含要作为 Azure 函数应用部署的特定代码。 如需创建该应用的说明,可参阅以下链接。

构建应用程序

现在,让我们按照过程逐步生成 JavaScript 客户端:

步骤 1:安装 Azure Batch SDK

可以使用 npm install 命令安装用于 JavaScript 的 Azure Batch SDK。

npm install azure-batch

此命令安装最新版本的 azure-batch JavaScript SDK。

提示

在 Azure 函数应用中,若要运行 npm install 命令,可以转到 Azure Function 的“设置”选项卡中的“Kudu 控制台”。 在本例中,目的是安装用于 JavaScript 的 Azure Batch SDK。

步骤 2:创建 Azure Batch 帐户

可以通过 Azure 门户或命令行 (PowerShell /Azure CLI) 创建该帐户。

下面是通过 Azure CLI 创建该帐户的命令。

创建一个资源组。如果你已经有一个需要在其中创建 Batch 帐户的资源组,则请跳过此步骤:

az group create -n "<resource-group-name>" -l "<location>"

接下来,创建 Azure Batch 帐户。

az batch account create -l "<location>" -g "<resource-group-name>" -n "<batch-account-name>"

每个 Batch 帐户都有其相应的访问密钥。 需要使用这些密钥才能在 Azure Batch 帐户中创建更多的资源。 对生产环境有利的做法是使用 Azure Key Vault 来存储这些密钥。 然后即可为应用程序创建服务主体。 应用程序可以使用该服务主体创建一个 OAuth 令牌,以便访问 Key Vault 中的密钥。

az batch account keys list -g "<resource-group-name>" -n "<batch-account-name>"

复制并存储可在后续步骤中使用的密钥。

步骤 3:创建 Azure Batch 服务客户端

以下代码片段首先导入 azure-batch JavaScript 模块,并创建 Batch 服务客户端。 需先使用从前一步骤复制的 Batch 帐户密钥创建 SharedKeyCredentials 对象。

// Initializing Azure Batch variables

import { BatchServiceClient, BatchSharedKeyCredentials } from "@azure/batch";

// Replace values below with Batch Account details 
const batchAccountName = '<batch-account-name>';
const batchAccountKey = '<batch-account-key>';
const batchEndpoint = '<batch-account-url>';

const credentials = new BatchSharedKeyCredentials(batchAccountName, batchAccountKey);
const batchClient = new BatchServiceClient(credentials, batchEndpoint);

Azure Batch URI 可以在 Azure 门户的“概览”选项卡中找到。 它的格式为:

https://accountname.location.batch.chinacloudapi.cn

请参阅屏幕截图:

Azure batch uri

步骤 4:创建 Azure Batch 池

Azure Batch 池包含多个 VM(也称 Batch 节点)。 Azure Batch 服务将任务部署在这些节点上并对其进行管理。 可以为池定义以下配置参数。

  • 虚拟机映像类型
  • 虚拟机节点大小
  • 虚拟机节点数目

提示

虚拟机节点的大小和数目主要取决于需要并行运行的任务数以及任务本身。 建议通过测试来确定理想的数目和大小。

以下代码片段创建配置参数对象。

// Creating Image reference configuration for Ubuntu Linux VM
const imgRef = {
    publisher: "Canonical",
    offer: "UbuntuServer",
    sku: "18.04-LTS",
    version: "latest"
}
// Creating the VM configuration object with the SKUID
const vmConfig = {
    imageReference: imgRef,
    nodeAgentSKUId: "batch.node.ubuntu 18.04"
};
// Number of VMs to create in a pool
const numVms = 4;

// Setting the VM size
const vmSize = "STANDARD_D1_V2";

提示

如需可供 Azure Batch 使用的 Linux VM 映像及其 SKU ID 的列表,请参阅虚拟机映像列表

定义池配置后,可以创建 Azure Batch 池。 Batch 池命令可创建 Azure 虚拟机节点并对其进行准备,使之能够接收要执行的任务。 每个池都应有一个可在后续步骤中引用的唯一 ID。

以下代码片段可创建 Azure Batch 池。

// Create a unique Azure Batch pool ID
const now = new Date();
const poolId = `processcsv_${now.getFullYear()}${now.getMonth()}${now.getDay()}${now.getHours()}${now.getSeconds()}`;

const poolConfig = {
    id: poolId,
    displayName: "Processing csv files",
    vmSize: vmSize,
    virtualMachineConfiguration: vmConfig,
    targetDedicatedNodes: numVms,
    enableAutoScale: false
};

// Creating the Pool
var pool = batchClient.pool.add(poolConfig, function (error, result){
    if(error!=null){console.log(error.response)};
});

你可以检查所创建池的状态,确保状态为“活动”,然后再继续操作,将作业提交到该池。

var cloudPool = batchClient.pool.get(poolId,function(error,result,request,response){
        if(error == null)
        {

            if(result.state == "active")
            {
                console.log("Pool is active");
            }
        }
        else
        {
            if(error.statusCode==404)
            {
                console.log("Pool not found yet returned 404...");

            }
            else
            {
                console.log("Error occurred while retrieving pool data");
            }
        }
        });

下面是由 pool.get 函数返回的结果对象示例。

{
  id: 'processcsv_2022002321',
  displayName: 'Processing csv files',
  url: 'https://<batch-account-name>.chinanorth.batch.chinacloudapi.cn/pools/processcsv_2022002321',
  eTag: '0x8D9D4088BC56FA1',
  lastModified: 2022-01-10T07:12:21.943Z,
  creationTime: 2022-01-10T07:12:21.943Z,
  state: 'active',
  stateTransitionTime: 2022-01-10T07:12:21.943Z,
  allocationState: 'steady',
  allocationStateTransitionTime: 2022-01-10T07:13:35.103Z,
  vmSize: 'standard_d1_v2',
  virtualMachineConfiguration: {
    imageReference: {
      publisher: 'Canonical',
      offer: 'UbuntuServer',
      sku: '18.04-LTS',
      version: 'latest'
    },
    nodeAgentSKUId: 'batch.node.ubuntu 18.04'
  },
  resizeTimeout: 'PT15M',
  currentDedicatedNodes: 4,
  currentLowPriorityNodes: 0,
  targetDedicatedNodes: 4,
  targetLowPriorityNodes: 0,
  enableAutoScale: false,
  enableInterNodeCommunication: false,
  taskSlotsPerNode: 1,
  taskSchedulingPolicy: { nodeFillType: 'Spread' }}

步骤 4:提交 Azure Batch 作业

Azure Batch 作业是包含相似任务的逻辑组。 在我们的方案中,它是“从 CSV 到 JSON 的过程”。这里的每个任务都可能是处理每个 Azure 存储容器中的 CSV 文件。

这些任务会并行运行,并且跨多个节点部署,由 Azure Batch 服务进行协调。

提示

可以使用 taskSlotsPerNode 属性指定能够在单个节点上同时运行的最大任务数。

准备任务

所创建的 VM 节点是空白 Ubuntu 节点。 通常需安装一组程序作为必备组件。 对于 Linux 节点,通常可在实际任务运行之前使用 shell 脚本安装必备组件。 不过,也可通过任何可编程的可执行文件来完成该操作。

在此示例中,shell 脚本安装 Python-pip 以及用于 Python 的 Azure 存储 Blob SDK。

可以将脚本上传到 Azure 存储帐户,并生成用于访问脚本的 SAS URI。 也可以使用 Azure 存储 JavaScript SDK 自动完成此过程。

提示

作业的准备任务仅在需要运行特定任务的 VM 节点上运行。 如果需要在所有节点上安装必备组件,而不管在其上运行的任务是什么,则可在添加池时使用 startTask 属性。 可以使用以下准备任务定义作为参考。

准备任务在提交 Azure Batch 作业时指定。 下面是一些可配置的准备任务参数:

  • ID:准备任务的唯一标识符
  • commandLine:用于执行任务可执行文件的命令行
  • resourceFiles:对象数组,提供运行此任务时需下载的文件的详细信息。 下面是其选项
    • httpUrl:要下载的文件的 URL
    • filePath:下载并保存文件所需的本地路径
    • fileMode:仅适用于 Linux 节点。fileMode 采用八进制格式,默认值为 0770
  • waitForSuccess:如果设置为 true,该任务不会在准备任务失败的情况下运行
  • runElevated:如果需要提升权限才能运行该任务,则设置为 true。

以下代码片段显示了准备任务脚本配置示例:

var jobPrepTaskConfig = {id:"installprereq",commandLine:"sudo sh startup_prereq.sh > startup.log",resourceFiles: [{ 'httpUrl': 'Blob sh url', 'filePath': 'startup_prereq.sh' }],waitForSuccess:true,runElevated:true, userIdentity: {autoUser: {elevationLevel: "admin", scope: "pool"}}}

如果不需安装任何必备组件即可运行任务,则可跳过准备任务。 以下代码创建显示名称为“process csv files”的作业。

// Setting Batch Pool ID
const poolInfo = { poolId: poolId };
// Batch job configuration object
const jobId = "processcsvjob";
const jobConfig = {
   id: jobId,
   displayName: "process csv files",
   jobPreparationTask: jobPrepTaskConfig,
   poolInfo: poolInfo
};
// Adding Azure batch job to the pool
const job = batchClient.job.add(jobConfig, function (error, result) {
       if (error !== null) {
           console.log("An error occurred while creating the job...");
           console.log(error.response);
       }
   });

步骤 5:为作业提交 Azure Batch 任务

创建“process csv”作业以后,让我们创建该作业的任务。 假设我们有四个容器,则必须创建四个任务,一个容器一个任务。

如果我们查看 Python 脚本,可以看到它接受两个参数:

  • 容器名称:要从其中下载文件的存储容器
  • 模式:文件名称模式的可选参数

假设我们有四个容器,分别为“con1”、“con2”、“con3”、“con4”。以下代码显示了如何将这四个任务任务提交到我们此前创建的 Azure 批处理作业“process csv”。

// storing container names in an array
const containerList = ["con1", "con2", "con3", "con4"];      //Replace with list of blob containers within storage account
containerList.forEach(function (val, index) {
    console.log("Submitting task for container : " + val);
    const containerName = val;
    const taskID = containerName + "_process";
    // Task configuration object
    const taskConfig = {
        id: taskID,
        displayName: 'process csv in ' + containerName,
        commandLine: 'python processcsv.py --container ' + containerName,
        resourceFiles: [{ 'httpUrl': 'Blob script url', 'filePath': 'processcsv.py' }]
    };

    const task = batchClient.task.add(jobId, taskConfig, function (error, result) {
        if (error !== null) {
            console.log("Error occurred while creating task for container " + containerName + ". Details : " + error.response);
        }
        else {
            console.log("Task for container : " + containerName + " submitted successfully");
        }
    });
});

该代码将多个任务添加到池。 每个任务在所创建的 VM 池中的一个节点上执行。 如果任务数超出池中的 VM 数或 taskSlotsPerNode 属性,则任务会等待节点可用。 此业务流程由 Azure Batch 自动处理。

门户提供了有关任务和作业状态的详细视图。 也可以使用 Azure JavaScript SDK 中的 list 和 get 函数。 文档链接中提供了详细信息。

后续步骤