Azure Functions 和无服务器计算





5.00/5 (3投票s)
开始使用 Azure Functions 和 Azure 中的无服务器计算。我们将了解什么是无服务器计算以及它如何在 Functions 中实现。
“Azure Functions and Serverless Computing” 这篇文章首次出现在 MSDN Azure Development Community。
在我之前的博文 《使用 .NET Core 2.1 在 Azure 中使用 WebJobs》 中,我曾简要提及 Azure Functions。Azure Functions 通常是运行在 Azure 中、由某个事件触发的小型(或稍大型)代码片段。Azure 完全负责 Functions 的整个基础设施,使其成为所谓的无服务器解决方案。您唯一需要担心的就是您的代码。
本文的代码示例可以在 我的 GitHub 个人资料 中找到。您可能真的不需要它,因为我只使用了默认模板,但我包含了它们,因为我需要在 CI/CD 的源代码管理中用到它们。
无服务器计算
在深入了解 Azure Functions 之前,我想稍微解释一下无服务器计算。无服务器计算并不是完全没有服务器,您的代码毕竟还需要运行的地方。但是,服务器完全由您的云提供商(在我们的例子中是 Azure)管理。
对于大多数应用服务(如 Web 应用或 API 应用),您需要一个应用服务计划,它基本上是一个具有 x 个 CPU 核心和 y 个内存的服务器。虽然您可以在应用服务计划上运行 Functions,但更令人兴奋的是在所谓的“消耗计划”中运行它们。使用消耗计划,您的资源是完全动态的,这意味着只有在代码运行时,您才实际使用服务器。
它很便宜
让我再说一遍,只有在代码运行时,您才实际使用服务器。这似乎微不足道,但却有一些巨大的影响!使用应用服务计划,即使没有代码运行,您也始终拥有一个服务器。这意味着您只需支付每月费用来维持服务器的运行。您知道这意味着什么吗?没错,使用消耗计划,您只在代码运行时付费,因为那是您实际使用资源的唯一时间!
有一个相当复杂的公式,使用运行时间、内存使用量和执行次数,但请相信我,Functions 非常便宜。您的前一百万次执行和 400,000 GB/秒(不管那是什么意思)都是免费的。微软有一个 定价示例,这只是验证了它的确便宜。
它是动态的
价格很酷,但我们不廉价!Functions 可能最酷的功能是 Azure 会根据您的函数有多忙来动态地扩展服务器。所以,假设您正在进行一些耗时且资源密集的大量计算,但您需要并行执行 100 次…… Azure 会动态地启动一些额外的服务器(当然,您要支付 x 倍的费用,但这仍然相当便宜)。当您的计算完成时,您的服务器将被释放,您也将停止付费。这种行为是有限制的。Azure 会为每个函数应用启动最多 200 个服务器实例,并且新实例最多每 10 秒才分配一次。不过,一个实例仍然可以处理多个执行,因此 200 台服务器通常不等于 200 次并发执行。
话虽如此,您实际上无法配置动态创建的服务器。您必须相信微软会暂时为您提供满足您需求的服务器。而且,正如您所料,这些需求最好是有限的。基本上,您的需求应该是存在您的语言环境,例如 C# 的 .NET Framework(或 .NET Core)。不过有一点很酷,除了 C# 之外,函数还可以用 F# 和 JavaScript 编写,Java 也将在 v2 中推出。还有一些其他语言目前在 v2 中运行,如 Python、PHP 和 TypeScript,但看起来微软不打算在不久的将来完全支持这些语言。
Azure Portal 中的 Azure Functions
让我们创建第一个 Azure Functions。转到应用服务并创建一个新的。创建应用服务时,您应该会看到一个创建函数应用的选项(除了 Web 应用、API 应用等)。创建屏幕与常规 Web 应用看起来几乎相同,只是函数应用将其托管计划设置为消耗计划(您应该选择这个),并且您还可以选择创建一个存储帐户,Azure 需要它来存储您的 Functions。
这将创建一个新的函数应用、一个新的托管计划和一个新的存储帐户。一旦 Azure 创建了您的资源,就在 Azure 资源中找到您的函数应用。您应该会看到您版本的“myfunctionsblog
”(这应该是一个唯一名称)。现在,将鼠标悬停在“Functions
”上,然后单击大加号添加一个函数。
在下一个窗体中,您可以选择一个场景。我们的选项是“Webhook + API”、“Timer”或“Data processing”。您还可以选择一种语言:“CSharp”、“JavaScript”、“FSharp”或“Java”。保留默认设置,“Webhook + API”和“CSharp”,然后单击“Create this function”按钮。
编辑和运行您的 Azure Functions
现在您会得到您的函数,这是一个默认模板。您可以直接在 Azure 门户中运行它,并且可以看到日志窗口、错误和警告、控制台,以及请求和响应正文。它就像 Azure 中一个非常轻量级的 IDE。我不会详细介绍实际代码,因为它非常基础。如果您愿意,可以自己动手尝试。
在“Save”和“Run”按钮旁边,您会看到一个“</> Get function URL”链接。单击它即可获取当前函数的 URL。有一个或多个函数密钥,它们提供对此函数的访问权限;有一个或多个主机密钥,它们提供对当前主机中所有函数的访问权限;还有一个主密钥,您绝不应与第三方共享。您可以从左侧菜单中的“Manage”项(包含 Functions、Proxies 和 Slots)来管理您的密钥。
使用 Azure Functions
我们创建的函数是 HTTP 触发的,这意味着我们必须自己进行 HTTP 调用。当然,您可以使用 Postman 或 SoapUI 等客户端,但让我们看一些 C# 代码来使用我们的函数。在 Visual Studio 中创建一个(.NET Core)控制台应用程序(或使用 GitHub 上的示例),并将以下代码粘贴到 Program.cs 中。
using System;
using System.Net.Http;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
using (var client = new HttpClient())
{
// Replace with your own URL.
string url = "https://myfunctionsblog.azurewebsites.net/api/
HttpTriggerCSharp1?code=CJnVDV8gELVapT7gNoMexKLI1j7zFNX6FJBOP7lMBC71vkvuAT9J4A==";
var content = new StringContent("{\"name\": \"Function\"}",
Encoding.UTF8, "application/json");
client.PostAsync(url, content).ContinueWith(async t =>
{
var result = await t.Result.Content.ReadAsStringAsync();
Console.WriteLine("The Function result is:");
Console.WriteLine(result);
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}).Wait();
}
}
}
}
如果您的函数因任何原因返回错误,您最好的日志工具是 Application Insights,但这不在本文的讨论范围之内。
当然,如果您有一个由计时器或队列或其他东西触发的函数,您就不需要手动触发它。
Visual Studio 2017 中的 Azure Functions
在 Azure 门户中创建函数很酷,但我们需要 IDE、源代码管理和 CI/CD。所以打开 VS2017,查找“Azure Functions”模板(在 Visual C# -> Cloud 下)。您可以在“Azure Functions v1 (.NET Framework)”和“Azure Functions v2 Preview (.NET Standard)”之间进行选择。我们喜欢 .NET Standard(它是 .NET Framework、.NET Core、UWP、Mono 和 Xamarin 之间的共同点),所以我们选择 v2 Preview。
再次选择 HTTP 触发器并找到您的存储帐户。将访问权限保留为“Function”。生成的函数模板与在 Azure 门户中生成的模板略有不同,但结果相同。这里需要注意的一点是,Functions 实际上使用了 Microsoft.Azure.WebJobs 命名空间
来处理触发器,这再次表明两者(有时)可以互换。
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.IO;
namespace FunctionApp
{
public static class Function1
{
[FunctionName("Function1")]
public static IActionResult Run([HttpTrigger
(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequest req, ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = new StreamReader(req.Body).ReadToEnd();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string
or in the request body");
}
}
}
>
运行模板时,您会看到一个控制台,其中以漂亮的 ASCII 艺术形式显示 Azure Functions 的徽标以及一些启动日志。Windows Defender 可能会要求您允许 Functions 运行,您应该授予此权限。
现在,如果您运行上一节中创建的控制台应用程序,并将函数 URL 更改为“https://:7071/api/Function1”(端口可能会有所不同),您应该会得到与之前相同的结果。
使用 Visual Studio 进行部署
如果您阅读了我之前的博客文章,您应该对此步骤相当熟悉。右键单击您的 Functions 项目,然后从菜单中选择“Publish…” 。选择“Select Existing”,然后启用“Run from ZIP (recommended)”。从 ZIP 部署会将您的 Function 置于只读状态,但这与使用 CI/CD 进行发布最匹配。此外,所有更改都应在 VS2017 中进行,以便它们位于源代码管理中。在下一个窗体中,找到您的 Azure 应用并将其部署到 Azure。
如果您之前选择了 Azure Functions v2,您可能会收到一个对话框,提示您更新 Azure 上的 Functions SDK。这里有一个小警告,这可能会破坏已有的函数(实际上,它只是删除了我之前的函数)。据我所知,这只会影响您当前的函数应用,但仍需自行承担风险。
再次找到您的 Functions URL,将其粘贴到控制台应用程序中,然后检查您是否获得了所需的输出。
使用 VSTS 进行部署
现在是关于持续集成和部署的重点。打开 Visual Studio Team Services 并创建一个新的构建管道。您可以为您的管道选择默认的 .NET Core 模板,但您应该更改“Publish”任务,使其发布“**/FunctionApp.csproj”而不是“Publish Web Projects”。您可以选择在“Triggers”选项卡中启用持续集成。完成后,您可以保存并排队构建。
下一步是创建一个新的发布管道。选择 Azure “App Service deployment”模板。将您的管道命名为一个明显的名称,例如“Function App CD”。您现在必须先添加您的工件,并且可能想要启用持续部署触发器。您还可以将您的环境重命名为“Dev”或类似的名称。
接下来,您需要填写环境任务中的一些参数。您需要设置的第一件事是您的 Azure 订阅并授权它。对于“App type”,选择“Function App”。如果您已成功授权您的订阅,您可以从下拉列表中选择您的应用服务名称。另外,这个有点棘手,在您的“Azure App Service Deploy”任务中,禁用“Take App Offline”,它隐藏在“Additional Deployment Options”下。完成后,并且构建完成后,创建一个新的发布。
一切顺利后,使用控制台应用程序测试您的更改。
如果一切按预期工作,请尝试更改您的函数应用的输出,将其推送到源代码管理,然后查看您的构建和发布管道是否正常工作。再次,使用控制台应用程序测试更改。
解决一些 bug
所以……一个包含 bug 和解决方法标题的标题绝不是好事。出于某种原因,我的发布由于“invalid access to memory location”而一直失败。可能是因为我已经使用 VS2017 部署了该应用程序。我也无法删除我的函数,因为垃圾桶图标被禁用。谷歌搜索显示我不是唯一遇到此问题的人。所以,总之,我目前使用的是 Azure Functions v2 的预览版,我相信微软在它正式发布之前会解决这些问题。
情况是这样的,您可能需要完全删除您的函数应用(您仍然可以通过应用服务删除它)。重新创建它,转到您的函数应用(不是函数本身,而是托管它的应用,也可以参考以下关于“附加设置”的部分),然后找到“Function app settings”。在这里,您可以找到一个开关“~1”和“beta”(分别代表 v1 和 v2)。在这里将其设置为“beta”。现在使用 VSTS 进行部署。从 VSTS 发布将导致您的发布再次失败。
底线:不要使用 VS2017 来部署您的函数应用!
附加设置
我还有最后一件事想告诉您。虽然 Azure Functions 与常规 Web 应用和 Web API 不同,但它们仍然是具有托管计划的应用服务。如果您单击您的函数应用,您将进入“Overview”页面。从这里,您可以转到您的函数应用设置(包括密钥)和您的应用程序设置(看起来很像 Web 应用设置)。您会找到您的应用程序设置,如“APPINSIGHTS_INSTRUMENTATIONKEY
”、“AzureWebJobsDashboard
”、“AzureWebJobsStorage
”和“FUNCTIONS_EXTENSIONS_VERSION
”。
另一个选项卡是“Platform features”选项卡,其中包含属性、设置和代码部署选项(有关部署选项的更多信息,请参阅我的博文 《使用 Visual Studio Team Services (VSTS) 和 .NET Core 进行 Azure 部署》)。
总结
Azure Functions 非常酷,我迫不及待地希望 v2 能够正式发布并完全支持 .NET Standard,同时修复我提到的 bug。现在,虽然 Functions 可以解决一些问题,例如动态扩展,但它也可能带来一些问题。
可以使用 Azure Functions 创建一个完整的 Web 应用程序。至于您是否愿意这样做是另一个问题。您可能听说过微服务。那么,对于 Functions,请考虑“纳米服务”。纳米服务通常被视为一种反模式,其中维护代码的开销超过了代码的效用。不过,如果明智地使用,而明智与否取决于您,Functions 可以成为您工具箱中一个强大、无服务器的资产。如果您想了解更多关于无服务器计算的概念,我推荐我好朋友 Sander Knape 的一篇博文,他写了 AWS 的等效产品 AWS Lambda 《无服务器的隐藏挑战:从 VM 到函数》。
如果您不再使用这些资源,请不要忘记删除它们,否则您的信用卡将被收费。
祝您编码愉快!
文章 《Azure Functions 和无服务器计算》 首次出现在 Sander Rossel。