17、Azure Functions 最佳实践全解析

Azure Functions 最佳实践全解析

在云原生应用开发中,Azure Functions 是一个强大的工具。本文将深入探讨 Azure Functions 的一些重要最佳实践,帮助开发者更好地使用 Azure Functions,克服其局限性,并将工作负载从本地迁移到无服务器环境。

1. 使用 IAsyncCollector 函数向队列添加多条消息

在某些场景下,客户端应用(如桌面应用、移动应用或网站)可能会在单个请求中发送多条记录。后端应用需要有机制能一次性异步创建多个队列消息。

准备工作
- 若尚未创建存储账户,可使用 Azure 门户创建。
- 若未安装 Microsoft Storage Explorer,可从 http://storageexplorer.com/ 安装。

操作步骤
1. 创建一个新的 HTTP 触发器,命名为 BulkDeviceRegistrations,并将授权级别设置为匿名。
2. 用以下代码替换默认代码并保存:

#r "Newtonsoft.Json"
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
public static async Task<IActionResult> Run(HttpRequest req, ILogger log )
{
    log.LogInformation("C# HTTP trigger function processed a request.");
    string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
    dynamic data = JsonConvert.DeserializeObject(requestBody);
    string Device = string.Empty;
    for(int nIndex=0;nIndex<data.devices.Count;nIndex++)
    {
        Device = Convert.ToString(data.devices[nIndex]);
        log.LogInformation("devices data" + Device);
    }
    return (ActionResult)new OkObjectResult("Program has been executed Successfully.");
}
  1. 创建 Azure 队列存储输出绑定。点击保存,导航到“集成”选项卡,点击“新建输出”按钮,选择 Azure 队列存储输出绑定,然后点击“选择”按钮。
  2. 在 Azure 队列存储输出步骤中,提供消息参数名称和队列名称,并在存储账户连接下拉列表中选择存储账户,最后点击保存。
  3. 点击保存并导航到 Azure 函数的代码编辑器,添加以下代码以保存消息到队列:
public static async Task<IActionResult> Run(HttpRequest req, ILogger log, IAsyncCollector<string> outputDeviceQueue )
{
    //...
    for(int nIndex=0;nIndex<data.devices.Count;nIndex++)
    {
        Device = Convert.ToString(data.devices[nIndex]);
        outputDeviceQueue.AddAsync(Device);
    }
    //...
}
  1. 从门户的“测试”选项卡运行该函数,使用以下输入请求 JSON:
{
    "devices": [
        {
            "type": "laptop",
            "brand": "lenovo",
            "model": "T440"
        },
        {
            "type": "mobile",
            "brand": "Mi",
            "model": "Red Mi 4"
        }
    ]
}
  1. 点击“运行”按钮测试功能。打开 Azure Storage Explorer,导航到名为 devicequeue 的队列,应能看到两条记录。

补充说明
若想同步存储多条消息,也可使用 ICollector 接口。这两个接口都包含可接受消息集合并将其创建为队列消息的方法。

2. 使用 Azure 函数和队列触发器实现防御性应用

即使应用经过多次不同环境的测试,仍可能因不可预见的原因而失败。因此,确保应用在出现错误或意外问题时发出警报是很好的做法。

准备工作
- 若未创建存储账户,使用 Azure 门户创建。
- 若未安装 Azure Storage Explorer,从 http://storageexplorer.com/ 安装。

操作步骤
1. 开发 C# 控制台应用程序
- 使用 .NET Core C# 语言创建一个新的控制台应用程序,并创建一个名为 StorageConnectionString 的应用设置键,其值为存储账户连接字符串(可从存储账户的“访问密钥”刀片获取)。
- 使用以下命令安装配置和队列存储 NuGet 包:

Install-Package Microsoft.Azure.Storage.Queue
Install-Package System.Configuration.ConfigurationManager
Install-Package Microsoft.Extensions.Configuration
Install-Package Microsoft.Extensions.Configuration.Json
- 在 program.cs 文件中添加以下命名空间:
using Microsoft.Azure.Storage;
using Microsoft.Azure.Storage.Queue; 
using System.Configuration;
using Microsoft.Extensions.Configuration;
using System.IO;
- 添加以下函数并在 Main 方法中调用:
static void CreateQueueMessages()
{
    var builder = new ConfigurationBuilder()
      .SetBasePath(Directory.GetCurrentDirectory())
      .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
    IConfigurationRoot configuration = builder.Build();
    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(configuration.GetConnectionString("StorageConnectionString"));
    CloudQueueClient queueclient = storageAccount.CreateCloudQueueClient();
    CloudQueue queue = queueclient.GetQueueReference("myqueuemessages");
    queue.CreateIfNotExists();
    CloudQueueMessage message = null;
    for(int nQueueMessageIndex = 0; nQueueMessageIndex <= 100; nQueueMessageIndex++)
    {
        message = new CloudQueueMessage(Convert.ToString(nQueueMessageIndex));
        queue.AddMessage(message);
        Console.WriteLine(nQueueMessageIndex);
    }
}
  1. 开发 Azure 函数队列触发器
    • 使用队列触发器模板创建一个名为 ProcessData 的新 Azure 函数,并将队列名称设置为 myqueuemessages。
    • 用以下代码替换默认代码:
using System;
public static void Run(string myQueueItem, ILogger log)
{
    if(Convert.ToInt32(myQueueItem)>50)
    {
        throw new Exception(myQueueItem);
    }
    else
    {
        log.LogInformation($"C# Queue trigger function processed: {myQueueItem}");
    }
}
  1. 运行测试
    • 按 Ctrl + F5 执行控制台应用程序,导航到 Azure Storage Explorer 查看队列内容。
    • 片刻后,应能在 myqueuemessages 队列中看到消息。目前,Azure 门户和 Storage Explorer 显示前 32 条消息,若要查看所有消息,需使用 C# 存储 SDK。
    • 还应看到一个名为 myqueuemessages-poison 的新(毒药)队列,其中包含另外 50 条队列消息。Azure 函数运行时会自动创建新队列并添加未被 Azure Functions 正确读取的消息。

补充说明
在将队列消息推送到毒药队列之前,Azure 函数运行时会尝试拾取并处理该消息 5 次。可通过在 Run 方法中添加一个 int 类型的新 dequecount 参数并记录其值来了解此过程。

3. 通过定期预热应用避免冷启动

Azure Functions 有三种托管计划:应用服务计划、消耗计划和高级计划。使用消耗计划时,开发者面临的一个问题是冷启动,即当一段时间没有请求时,启动 Azure 函数来处理请求。

准备工作
需要一个具有以下触发器的函数应用:
- 一个名为 HttpAlive 的 HTTP 触发器。
- 一个名为 KeepFunctionAppWarm 的定时器触发器,每五分钟运行一次并向 HttpAlive HTTP 触发器发出 HTTP 请求。

操作步骤
1. 创建 HTTP 触发器
创建一个新的 HTTP 触发器,命名为 HttpAlive,并用以下代码替换默认代码:

using System.Net;
using Microsoft.AspNetCore.Mvc;
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
    return (ActionResult)new OkObjectResult($"Hello User! Thanks for keeping me Warm");
}
  1. 创建定时器触发器
    • 点击“+”图标,搜索“定时器”,然后点击“定时器触发器”按钮。
    • 在“新建函数”弹出窗口中提供详细信息,调度使用 CRON 表达式确保定时器触发器每五分钟自动触发。
    • 在代码编辑器中粘贴以下代码并保存更改,确保将 < > 替换为实际的函数应用名称:
using System;
public async static void Run(TimerInfo myTimer, ILogger log)
{
    using (var httpClient = new HttpClient())
    {
        var response = await httpClient.GetAsync("https://<FunctionAppName>>.azurewebsites.net/api/HttpALive");
    }
}
4. 使用类库在 Azure 函数之间共享代码

若已开发了一个通用库,希望在 Azure 函数应用中重用其功能,可按以下步骤操作。

操作步骤
1. 使用 Visual Studio 创建一个新的类库应用程序。
2. 创建一个名为 Helper 的新类,并在新类文件中粘贴以下代码:

namespace Utilities
{
    public class Helper
    {
        public static string GetReusableFunctionOutput()
        {
            return "This is an output from a Reusuable Library across functions";
        }
    }
}
  1. 将构建配置更改为“发布”并构建应用程序,以创建将在 Azure 函数中使用的 .dll 文件。
  2. 点击“应用服务编辑器”按钮(位于“平台功能”选项卡的“开发工具”部分),导航到要使用该库的函数应用的应用服务编辑器。
  3. 在 WWWROOT 下的空白区域右键单击,创建一个新的 bin 文件夹。
  4. 点击“新建文件夹”项后,在出现的文本框中输入“bin”。
  5. 右键单击 bin 文件夹,选择“上传文件”选项,上传在 Visual Studio 中创建的 .dll 文件。
  6. 导航到要使用共享方法的 Azure 函数。例如,有两个 Azure 函数(一个 HTTP 触发器和一个定时器触发器)。
  7. 导航到 ReusableMethodCaller1 函数,进行以下更改:
    • 在 ReusableMethodCaller1 Azure 函数的 run.csx 方法中添加新的 #r 指令:
#r "../bin/Reusability.dll"
- 添加新的命名空间:
using Utilities;

通过以上这些最佳实践,开发者可以更高效地使用 Azure Functions,提升应用的性能和稳定性。

5. 使用 PowerShell 将 C# 控制台应用程序迁移到 Azure Functions

在某些情况下,我们可能需要将现有的 C# 控制台应用程序迁移到 Azure Functions 以利用其无服务器的优势。以下是使用 PowerShell 进行迁移的操作步骤:

准备工作
- 确保已经安装了 Azure PowerShell 模块。可以通过在 PowerShell 中运行 Install-Module -Name Az 来安装。
- 拥有一个 Azure 订阅,并在 Azure 门户中创建一个资源组和一个存储账户。

操作步骤
1. 创建 Azure Functions 项目
- 打开 PowerShell 并导航到要创建项目的目录。
- 运行以下命令创建一个新的 Azure Functions 项目:

func init MyFunctionProj --dotnet
- 这将创建一个名为 `MyFunctionProj` 的新的 .NET 项目。
  1. 导入 C# 控制台应用程序的代码

    • 将 C# 控制台应用程序的相关代码文件复制到 MyFunctionProj 项目的相应目录中。
    • 确保引用的 NuGet 包也在新的项目中正确配置。可以通过在项目根目录下运行 dotnet add package <PackageName> 来添加缺失的包。
  2. 创建 Azure Functions 触发器

    • 根据控制台应用程序的功能,选择合适的触发器类型(如 HTTP 触发器、定时器触发器等)。
    • 例如,创建一个 HTTP 触发器:
func new --name HttpTrigger --template "HTTP trigger"
- 这将在项目中创建一个名为 `HttpTrigger` 的新的 HTTP 触发器函数。
  1. 修改函数代码以调用控制台应用程序逻辑
    • 打开 HttpTrigger 函数的代码文件(通常是 run.csx Function.cs )。
    • 在函数中调用从控制台应用程序复制过来的代码逻辑。例如:
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

namespace MyFunctionProj
{
    public static class HttpTrigger
    {
        [FunctionName("HttpTrigger")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            // 调用控制台应用程序的逻辑
            // 这里假设控制台应用程序有一个名为 MyConsoleLogic 的类和一个名为 DoWork 的方法
            var result = MyConsoleLogic.DoWork();

            return new OkObjectResult(result);
        }
    }
}
  1. 部署到 Azure
    • 使用以下 PowerShell 命令将项目部署到 Azure:
func azure functionapp publish <FunctionAppName>
- 其中 `<FunctionAppName>` 是你在 Azure 门户中创建的函数应用的名称。
6. 使用应用配置服务在 Azure Functions 中实现功能标志

功能标志是一种在运行时控制应用程序功能启用或禁用的技术。在 Azure Functions 中,可以使用应用配置服务来实现功能标志。

准备工作
- 在 Azure 门户中创建一个应用配置服务实例。
- 安装 Microsoft.FeatureManagement.AspNetCore NuGet 包到 Azure Functions 项目中。

操作步骤
1. 配置应用配置服务连接
- 在 Azure Functions 项目的 local.settings.json 文件中添加应用配置服务的连接字符串:

{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "UseDevelopmentStorage=true",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet",
        "AppConfigConnectionString": "<YourAppConfigConnectionString>"
    }
}
- 其中 `<YourAppConfigConnectionString>` 是应用配置服务的连接字符串,可以在 Azure 门户的应用配置服务实例中获取。
  1. 注册功能管理服务
    • Startup.cs 文件中注册功能管理服务:
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.FeatureManagement;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(MyFunctionProj.Startup))]

namespace MyFunctionProj
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            var config = new ConfigurationBuilder()
              .AddAzureAppConfiguration(Configuration.GetValue<string>("AppConfigConnectionString"))
              .Build();

            builder.Services.AddFeatureManagement(config);
        }
    }
}
  1. 使用功能标志
    • 在 Azure Functions 中使用功能标志来控制功能的启用或禁用。例如:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.FeatureManagement;

namespace MyFunctionProj
{
    public class MyFunction
    {
        private readonly IFeatureManager _featureManager;

        public MyFunction(IFeatureManager featureManager)
        {
            _featureManager = featureManager;
        }

        [FunctionName("MyFunction")]
        public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            if (await _featureManager.IsEnabledAsync("MyFeatureFlag"))
            {
                // 执行启用功能的逻辑
                return new OkObjectResult("My feature is enabled!");
            }
            else
            {
                // 执行禁用功能的逻辑
                return new OkObjectResult("My feature is disabled.");
            }
        }
    }
}

总结

通过以上这些最佳实践,我们可以全面提升 Azure Functions 的使用效率和应用的性能。从向队列添加多条消息、实现防御性应用、避免冷启动、共享代码,到迁移 C# 控制台应用程序和实现功能标志,每个实践都针对不同的场景和问题提供了有效的解决方案。开发者可以根据具体的需求选择合适的实践来优化自己的 Azure Functions 应用。

以下是一个总结表格,展示了各个最佳实践的主要信息:
| 最佳实践 | 主要功能 | 关键技术 |
| — | — | — |
| 使用 IAsyncCollector 函数向队列添加多条消息 | 处理客户端单个请求中的多条记录,异步创建多个队列消息 | IAsyncCollector 接口 |
| 使用 Azure 函数和队列触发器实现防御性应用 | 处理应用中的意外错误,自动将未处理消息存入毒药队列 | Azure 函数队列触发器 |
| 通过定期预热应用避免冷启动 | 解决消耗计划中的冷启动问题 | 定时器触发器和 HTTP 触发器 |
| 使用类库在 Azure 函数之间共享代码 | 重用通用库的功能 | 类库和 .dll 文件 |
| 使用 PowerShell 将 C# 控制台应用程序迁移到 Azure Functions | 将现有的 C# 控制台应用迁移到 Azure Functions | PowerShell 和 Azure Functions 工具 |
| 使用应用配置服务在 Azure Functions 中实现功能标志 | 在运行时控制应用功能的启用或禁用 | 应用配置服务和功能管理 |

以下是一个 mermaid 流程图,展示了整个 Azure Functions 最佳实践的流程:

graph LR
    A[创建函数应用] --> B[添加消息到队列]
    A --> C[实现防御性应用]
    A --> D[避免冷启动]
    A --> E[共享代码]
    A --> F[迁移控制台应用]
    A --> G[实现功能标志]
    B --> H[使用 IAsyncCollector]
    C --> I[队列触发器和毒药队列]
    D --> J[定时器和 HTTP 触发器]
    E --> K[类库和 .dll 文件]
    F --> L[PowerShell 迁移]
    G --> M[应用配置服务]

希望这些最佳实践能帮助开发者更好地利用 Azure Functions 的强大功能,构建出更高效、稳定的云原生应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值