阶段 3:将工作负载从 AWS Lambda 迁移到 Azure Functions

在此阶段,完成将工作负荷从 AWS Lambda 迁移到 Azure Functions。 目标是调整函数代码以实现兼容性和最佳做法、迁移工作负载、测试性能、优化作,以及实现对可靠性和效率的监视。

将函数代码、配置文件和基础结构调整为代码文件

需要调整函数代码、配置文件和基础结构即代码(IaC)文件,以遵循 Azure Functions 编程模型和最佳做法。 此步骤有助于确保工作负荷与 Azure Functions 兼容。

更新 Azure Functions 运行时要求的代码:

以下代码片段是常见 SDK 代码的示例。 AWS Lambda 代码映射到 Azure Functions 中的相应触发器、绑定或 SDK 代码片段。

从 Amazon S3 与 Azure Blob 存储读取数据

AWS Lambda 代码 (SDK)

const AWS = require('aws-sdk');
const s3 = new AWS.S3();

exports.handler = async (event) => {
const params = {
Bucket: 'my-bucket',
Key: 'my-object.txt',
};
const data = await
s3.getObject(params).promise();
console.log('File content:',
data.Body.toString());
};       

Azure Functions 代码(触发器)

import { app } from '@azure/functions';

app.storageblob('blobTrigger', { 
path: 'my-container/{blobName}',
connection: 'AzureWebJobsStorage',
}, async (context, myBlob) => { 
context.log(`Blob content:
${myBlob.toString()}`);
});

写入 Amazon Simple Queue Service (SQS) 与 Azure 队列存储

AWS Lambda 代码 (SDK)

const AWS = require('aws-sdk');
const sqs = new AWS.SQS(); 

exports.handler = async (event) => {
const params = {
QueueUrl:
'https://sqs.amazonaws.com/123456789012/MyQueue',
MessageBody: 'Hello, world!',
};
await
sqs.sendMessage(params).promise();
};

Azure Functions 代码(触发器)

import { app } from '@azure/functions';

app.queue('queueTrigger', { 
queueName: 'myqueue-items',
connection: 'AzureWebJobsStorage',
}, async (context, queueMessage) => {
context.log(`Queue message: 
${queueMessage}`);
}); 

将数据写入 DynamoDB 与 Azure Cosmos DB 的比较

AWS Lambda 代码 (SDK)

const AWS = require('aws-sdk'); 
const dynamoDb = new AWS.DynamoDB.DocumentClient();   

exports.handler = async (event) => { 
const params = { 
TableName: 'my-table', 
Key: { id: '123' }, 
}; 
const data = await dynamoDb.get(params).promise(); 
console.log('DynamoDB record:', data.Item); 
}; 

Azure Functions 代码(触发器)

import { app } from '@azure/functions';  

app.cosmosDB('cosmosTrigger', { 
connectionStringSetting: 'CosmosDBConnection', 
databaseName: 'my-database', 
containerName: 'my-container', 
leaseContainerName: 'leases', 
}, async (context, documents) => { 
documents.forEach(doc => { 
context.log(`Cosmos DB document: ${JSON.stringify(doc)}`); 
}); 
}); 

Amazon CloudWatch 事件与 Azure 计时器触发器

AWS Lambda 代码 (SDK)

exports.handler = async (event) => {
console.log('Scheduled event:', event); 
}; 

Azure Functions 代码(触发器)

import { app } from '@azure/functions'; 

app.timer('timerTrigger', { schedule: '0 */5 * * * *', // Runs every 5 minutes }, async (context, myTimer) => { if (myTimer.isPastDue) { context.log('Timer is running late!'); } context.log(Timer function executed at: ${new Date().toISOString()}); });

Amazon Simple Notification Service (SNS) 与 Azure 事件网格触发器

AWS Lambda 代码 (SDK)

const AWS = require('aws-sdk'); 
const sns = new AWS.SNS();   

exports.handler = async (event) => { 
const params = { 
Message: 'Hello, Event Grid!', 
TopicArn: 'arn:aws:sns:us-east-1:123456789012:MyTopic', 
}; 
await sns.publish(params).promise(); 
}; 

Azure Functions 代码(触发器)

import { app } from '@azure/functions'; 

app.eventGrid('eventGridTrigger', {}, 
async (context, eventGridEvent) => { 

context.log(`Event Grid event: 
${JSON.stringify(eventGridEvent)}`); 

}); 

Amazon Kinesis 与 Azure 事件中心触发器

AWS Lambda 代码 (SDK)

const AWS = require('aws-sdk'); 
const kinesis = new AWS.Kinesis();   

exports.handler = async (event) => { 
const records = 
event.Records.map(record => 
Buffer.from(record.kinesis.data, 
'base64').toString()); 
console.log('Kinesis records:', records); 
}; 

Azure Functions 代码(触发器)

import { app } from '@azure/functions'; 
app.eventHub('eventHubTrigger', {  
connection: 'EventHubConnection',  
eventHubName: 'my-event-hub',  
}, async (context, eventHubMessages) => 
{  
eventHubMessages.forEach(message => 
{  
context.log(`Event Hub message: 
${message}`);  
});  
});

请参阅以下 GitHub 存储库来比较 AWS Lambda 代码和 Azure Functions 代码:

调整配置设置

确保函数的超时和 内存 设置与 Azure Functions 兼容。 有关可配置设置的详细信息,请参阅 Azure Functionshost.json 参考

遵循有关权限、访问、网络和部署配置的建议最佳做法。

配置权限

在为函数应用设置权限时,请遵循最佳做法。 有关详细信息,请参阅 使用托管身份验证配置存储帐户和函数应用

main.bicep

// User-assigned managed identity that the function app uses to reach Storage and Service Bus
module processorUserAssignedIdentity './core/identity/userAssignedIdentity.bicep' = {
  name: 'processorUserAssignedIdentity'
  scope: rg
  params: {
    location: location
    tags: tags
    identityName: !empty(processorUserAssignedIdentityName) ? processorUserAssignedIdentityName : '${abbrs.managedIdentityUserAssignedIdentities}processor-${resourceToken}'
  }
}

有关详细信息,请参阅 userAssignedIdentity.bicep

配置网络访问

Azure Functions 支持 虚拟网络集成,使函数应用能够访问虚拟网络中的资源。 集成后,应用通过虚拟网络路由出站流量。 然后,应用可以使用仅允许来自特定子网的流量的规则访问专用终结点或资源。 如果目标是虚拟网络外部的 IP 地址,则源 IP 地址是应用属性中列出的地址之一,除非配置 NAT 网关。

为函数应用启用 虚拟网络集成 时,请遵循 TSG 中的最佳做法,实现 Web 应用和函数应用的虚拟网络集成

main.bicep

// Virtual network and private endpoint
module serviceVirtualNetwork 'app/vnet.bicep' = {
  name: 'serviceVirtualNetwork'
  scope: rg
  params: {
    location: location
    tags: tags
    vNetName: !empty(vNetName) ? vNetName : '${abbrs.networkVirtualNetworks}${resourceToken}'
  }
}  

module servicePrivateEndpoint 'app/storage-PrivateEndpoint.bicep' = {
  name: 'servicePrivateEndpoint'
  scope: rg
  params: {
    location: location
    tags: tags
    virtualNetworkName: !empty(vNetName) ? vNetName : '${abbrs.networkVirtualNetworks}${resourceToken}'
    subnetName: serviceVirtualNetwork.outputs.peSubnetName
    resourceName: storage.outputs.name
  }
}

有关详细信息,请参阅 VNet.bicepstorage-PrivateEndpoint.bicep

配置部署设置

部署遵循单个路径。 生成项目代码并将其压缩到应用程序包后,将其部署到 Blob 存储容器。 启动后,应用会获取包,并从中运行函数代码。 默认情况下,存储内部主机元数据的同一存储帐户(例如 AzureWebJobsStorage)也用作部署容器。 但是,可以使用备用存储帐户,也可以通过配置应用的部署设置来选择首选的身份验证方法。 有关详细信息,请参阅 部署技术详细信息配置部署设置

生成 IaC 文件

  • 使用 Bicep、Azure 资源管理器模板或 Terraform 等工具创建 IaC 文件来部署 Azure 资源。

  • 在 IaC 文件中定义 Azure Functions、存储帐户和网络组件等资源。

  • 请使用此 IaC 示例存储库获取有关 Azure Functions 建议和最佳实践的示例。

使用重构工具

使用 Visual Studio Code 中的 GitHub Copilot 等工具来帮助进行代码重构、手动重构特定更改或其他迁移帮助。

有关每个步骤的详细信息,请参阅:

这些资源提供特定的示例和详细步骤,以帮助迁移过程。

部署并测试应用程序

执行工作负荷到 Azure Functions 的引导迁移,并测试部署的函数以验证其性能和正确性。

部署到 Azure 云

使用 VS Code 发布功能部署工作负载。 还可以使用 Azure Functions Core ToolsAzure CLI 从命令行部署工作负荷。 GitHub Actions 也使用 One Deploy。

  • Azure Functions Core Tools:使用 Azure Functions Core Tools 通过 命令 func azure functionapp publish <FunctionAppName>

执行端到端测试

  • 验证功能

    • 彻底测试每个函数,以确保其按预期工作。 这些测试应包括输入/输出、事件触发器和绑定验证。

    • 使用 VS Code 上的 curl 或 REST 客户端 扩展等工具发送 HTTP 触发的函数的 HTTP 请求。

    • 对于其他触发器(如计时器或队列),请确保触发器正确触发,并且函数按预期运行。

  • 验证性能

    • 执行性能测试,将新的 Azure Functions 部署与以前的 AWS Lambda 部署进行比较。

    • 监视响应时间、运行时和资源消耗等指标。

    • 在测试阶段使用 Application Insights 进行 监视、日志分析和故障排除

优化和监视应用程序的性能

按照以下步骤有效地监视、排除故障并优化函数应用的性能和成本。

使用 Application Insights 进行监视和故障排除

为函数应用启用 Application Insights 以收集详细的遥测数据,以便进行监视和故障排除。 可以通过 Azure 门户或在函数应用的 host.json 配置文件中启用 Application Insights。 启用 Application Insights 后,可以:

  • 收集遥测数据。 Application Insights 提供各种遥测数据,例如请求日志、性能指标、异常和依赖项。

  • 分析日志和指标。 从 Azure 门户访问 Application Insights 仪表板,以可视化和分析日志、指标和其他遥测数据。 使用内置工具创建自定义查询并可视化数据,以便深入了解函数应用的性能和行为。

  • 设置警报。 在 Application Insights 中配置警报,以通知严重问题、性能下降或特定事件。 这些警报可帮助你主动监视并快速响应问题。

针对成本和性能进行优化

  • 缩放和性能优化:

    • 使用自动缩放功能高效处理不同的工作负荷。

    • 通过减少运行时、优化依赖项和使用高效的编码做法来优化函数代码以提高性能。

    • 实现缓存策略,以减少频繁访问数据的重复处理和延迟。

  • 成本管理:

    • 使用 Microsoft成本管理工具 监视和分析 Azure Functions 成本。

    • 设置预算和成本警报,以有效管理和预测费用。

开始吧

使用 MigrationGetStarted 存储库 作为模板开始概念验证。 此存储库包括一个现成部署的 Azure Functions 项目,其中包含基础结构和源代码文件,可帮助你入门。

如果希望使用 Terraform,请改用 MigrationGetStarted-Terraform