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)
但是我找不到任何关于 Database
或 Container
对象是否也可以是单例的建议,所以这些是为每个 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;
我可以创建 Database
和 Container
单例并将它们添加到要像 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 只创建了一次(包含所有容器),每次通过依赖注入获取它时都会重复使用它。
我想减少 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)
但是我找不到任何关于 Database
或 Container
对象是否也可以是单例的建议,所以这些是为每个 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;
我可以创建 Database
和 Container
单例并将它们添加到要像 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 只创建了一次(包含所有容器),每次通过依赖注入获取它时都会重复使用它。