65.9K
CodeProject 正在变化。 阅读更多。
Home

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

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2018年12月27日

CPOL
viewsIcon

8838

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 具有多个实例的场景中,每个实例都将维护自己的静态客户端(实例之间不会共享)。

请继续关注更多方法!

本系列中的其他文章

© . All rights reserved.