Cosmos SDK3 Container 可以单例吗?

Can Cosmos SDK3 Container be a singleton?

我想减少 Azure Cosmos DB SQL-API 上的负载,这是从具有依赖项注入的 .NET Core Web API 调用的。

在 App Insights 中,我注意到每次调用 Web API 都会导致对 Cosmos 的 GetDatabase 和 GetCollection 调用,当 Cosmos 负载很重时,这可能需要 5 秒到 运行。

我已将 CosmosClient 设为单例(例如此处的建议 - https://docs.microsoft.com/en-us/azure/cosmos-db/performance-tips-dotnet-sdk-v3-sql

但是我找不到任何关于 DatabaseContainer 对象是否也可以是单例的建议,所以这些是为每个 Web 请求创建的 API.

我检查数据库和集合是否存在(例如,遵循此处的建议 - https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.cosmos.cosmosclient.getdatabase?view=azure-dotnet#remarks and https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.cosmos.cosmosclient.getcontainer?view=azure-dotnet#remarks

这意味着对于网络的每个请求API,下面的代码是运行

var databaseResponse = await this.cosmosClient.CreateDatabaseIfNotExistsAsync(
    this.databaseConfiguration.DatabaseName,
    throughput: this.databaseConfiguration.DatabaseLevelThroughput);
var database = databaseResponse.Database;
var containerResponse = await database.CreateContainerIfNotExistsAsync(containerId, partitionKey);
var container = containerResponse.Container;

我可以创建 DatabaseContainer 单例并将它们添加到要像 CosmosClient 一样注入的 DI 以减少在 App 中看到的对 GetDatabase 和 GetCollection 的调用次数见解?

CreateDatabaseIfNotExistsAsync 只应调用一次,因为它只是数据库配置的设置步骤。

您最好创建一个 DbService 来持久化容器对象。并将 DbService 注入每个服务而不是数据库客户端

你不需要每次都调用CreateIfNotExistsAsync,如果你知道它们可用,你可以使用CosmosClient.GetContainer(dbName, containerName),这是一个轻量级代理class.

除非您希望数据库和容器在某个时候被动态删除?

根据最新的 Microsoft documentation,您创建了一个 CosmosClient 服务单例,它拥有您将使用的容器。也影响使容器成为单例。

首先,让你的界面收缩:

public interface ICosmosDbService
{
    // identify the database CRUD operations you need
}

其次,根据合同定义您的服务:

public class CosmosDbService : ICosmosDbService
{
    private Container _container;

    public CosmosDbService(CosmosClient dbClient, string databaseName, string containerName)
    {
        this._container = dbClient.GetContainer(databaseName, containerName);
    }
    
    // your database CRUD operations go here using the Container field(s)
}

第三,在你的Startup中创建一个方法class到return一个CosmosClient:

private static async Task<CosmosDbService> InitializeCosmosClientAsync(IConfigurationSection cosmosConfig)
{
    var databaseName = cosmosConfig.GetSection("DatabaseName").Value;
    var containerName = cosmosConfig.GetSection("ContainerName").Value;
    var account = cosmosConfig.GetSection("Account").Value;
    var key = cosmosConfig.GetSection("Key").Value;
    var client = new Microsoft.Azure.Cosmos.CosmosClient(account, key);
    var database = await client.CreateDatabaseIfNotExistsAsync(databaseName);
    await database.Database.CreateContainerIfNotExistsAsync(containerName, "/id");
    return new CosmosDbService(client, databaseName, containerName);
}

最后,将您的 CosmosClient 添加到 ServiceCollection:

public void ConfigureServices(IServiceCollection services)
{
    var cosmosConfig = this.Configuration.GetSection("CosmosDb");
    var cosmosClient = InitializeCosmosClientAsync(cosmosConfig).GetAwaiter().GetResult();
    services.AddSingleton<ICosmosDbService>(cosmosClient);
}

现在您的 CosmosClient 只创建了一次(包含所有容器),每次通过依赖注入获取它时都会重复使用它。