Azure Cosmos DB + Functions 食谱 - 静态客户端





0/5 (0投票)
Azure Cosmos DB 是微软的全球分布式多模型数据库,当它与 Azure Functions(Azure 的无服务器计算服务)结合时,就成为了无服务器时代的理想数据库。
前言
从定义上来说,当两个要素之间的互动产生的影响**大于单个**要素贡献的总和时,就会发生**协同效应**。
Azure Cosmos DB 是微软的全球分布式多模型数据库,当它与 Azure Functions(Azure 的无服务器计算服务)结合时,就成为了 无服务器时代的理想数据库。
在这个**系列文章**中,我将探索针对特定场景的不同**方法、陷阱和示例**,并作为您架构的构建块。
使用和扩展
使用 Azure Functions,我们可以创建基于事件(时间、HTTP 调用、消息队列、数据库操作,仅举几例)运行的小段代码,并且可以独立 扩展以适应您的计算需求。 虽然我们在技术上看不到也不用担心托管 Functions 的服务器(毕竟是无服务器的!),但有一个 **Runtime**(或 ScriptHost)维护着我们的 Functions 运行所在的内存空间(以及其他东西)。
在使用 Azure Cosmos DB 时,我们可能已经看到过使用 using 语句和 DocumentClient
的代码(毕竟,它实现了 IDisposable 接口),因此我们可能很想在 Function 的代码中这样做
#r "Microsoft.Azure.Documents.Client" using Microsoft.Azure.Documents; using Microsoft.Azure.Documents.Client; using System.Net; private static string endpointUrl = ConfigurationManager.AppSettings["cosmosDBAccountEndpoint"]; private static string authorizationKey = ConfigurationManager.AppSettings["cosmosDBAccountKey"]; public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log) { // Avoid doing this! using (DocumentClient client = new DocumentClient(new Uri(endpointUrl), authorizationKey)){ string id = req.GetQueryNameValuePairs() .FirstOrDefault(q => string.Compare(q.Key, "id", true) == 0) .Value; if (string.IsNullOrEmpty(id)){ return req.CreateResponse(HttpStatusCode.BadRequest); } Uri documentUri = UriFactory.CreateDocumentUri("name of database","name of collection",id); Document doc = await client.ReadDocumentAsync(documentUri); if (doc == null){ return req.CreateResponse(HttpStatusCode.NotFound); } return req.CreateResponse(HttpStatusCode.OK, doc); } }
这种方法的问题在于,它在**每次执行**时都会创建一个 DocumentClient
的实例。 我们都知道这种方法对于 HttpClient
的弊端(如果你不知道,请在阅读完这篇文章后立即 阅读它!),并且它在这里也有完全相同的效果:如果 Function 获得了大量的触发器,我们不仅会因为初始化**开销**而**降低**数据库调用的**性能**,而且**内存消耗**也会增加,我们甚至可能会遇到**套接字耗尽**的情况。
静态客户端
在使用 Azure Cosmos DB 时,我们可以实现的第一个也是最容易实现的 **性能改进** 之一是,为所有服务调用使用单个 DocumentClient 实例(请参阅完整的 性能文章以获取更多信息)。 在构建应用程序时,我们可以通过 依赖注入框架来维护一个 单例实例,但是我们如何在 Functions 的代码中实现这一点呢? 事实证明这很容易! 只需在 Function 的 Run 代码**之外**将 DocumentClient
声明为 **static** 即可
#r "Microsoft.Azure.Documents.Client" using Microsoft.Azure.Documents; using Microsoft.Azure.Documents.Client; using System.Net; using System.Configuration; private static string endpointUrl = ConfigurationManager.AppSettings["cosmosDBAccountEndpoint"]; private static string authorizationKey = ConfigurationManager.AppSettings["cosmosDBAccountKey"]; private static DocumentClient client = new DocumentClient(new Uri(endpointUrl), authorizationKey); public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log) { string id = req.GetQueryNameValuePairs() .FirstOrDefault(q => string.Compare(q.Key, "id", true) == 0) .Value; if (string.IsNullOrEmpty(id)){ return req.CreateResponse(HttpStatusCode.BadRequest); } Uri documentUri = UriFactory.CreateDocumentUri("name of database","name of collection",id); Document doc = await client.ReadDocumentAsync(documentUri); if (doc == null){ return req.CreateResponse(HttpStatusCode.NotFound); } return req.CreateResponse(HttpStatusCode.OK, doc); }
出于安全目的,代码正在从应用程序设置中读取 Azure Cosmos DB 终结点和密钥。 或者,您也可以使用 Azure Key Vault 来存储和检索此信息。 有关更多信息,请参阅我的 其他相关文章。
这将有效地为同一 ScriptHost(实例)中的所有 Function 执行**维护一个实例**的 DocumentClient
,并通过为所有服务调用重用同一客户端来提高整体性能。
在 Function App 具有多个实例的场景中,每个实例都将维护自己的静态客户端(实例之间不会共享)。
请继续关注更多方法!
本系列中的其他文章
- Azure Cosmos DB + Functions Cookbook - HTTP 查询
- Azure Cosmos DB + Functions Cookbook - 输出收集器
- Azure Cosmos DB + Functions Cookbook - 实时迁移
- Azure Cosmos DB + Functions Cookbook - 搜索索引
- Azure Cosmos DB + Functions Cookbook - 安全客户端
- Azure Cosmos DB + Functions Cookbook - 多重触发
- Azure Cosmos DB + Functions Cookbook - 连接模式
- Azure Cosmos DB + Functions Cookbook - 多主节点 & 首选区域