如何将CosmosClient.CreateAndInitializeAsync()与Build()结合预热缓存?
问题背景与代码咨询
在某视频的27分20秒处提到,可通过填充路由信息缓存避免Cosmos DB冷启动延迟,具体方式有两种:读取已知不存在的文档,或使用CosmosClient.CreateAndInitializeAsync()。
我现有如下创建容器的代码:
private async Task<Container> CreateContainerAsync(string endpoint, string authKey) { var cosmosClientBuilder = new CosmosClientBuilder( accountEndpoint: endpoint, authKeyOrResourceToken: authKey) .WithConnectionModeDirect(portReuseMode: PortReuseMode.PrivatePortPool, idleTcpConnectionTimeout: TimeSpan.FromHours(1)) .WithApplicationName(UserAgentSuffix) .WithConsistencyLevel(ConsistencyLevel.Session) .WithApplicationRegion(Regions.AustraliaEast) .WithRequestTimeout(TimeSpan.FromSeconds(DatabaseRequestTimeoutInSeconds)) .WithThrottlingRetryOptions(TimeSpan.FromSeconds(DatabaseMaxRetryWaitTimeInSeconds), DatabaseMaxRetryAttemptsOnThrottledRequests); var client = cosmosClientBuilder.Build(); var databaseResponse = await CreateDatabaseIfNotExistsAsync(client).ConfigureAwait(false); var containerResponse = await CreateContainerIfNotExistsAsync(databaseResponse.Database).ConfigureAwait(false); return containerResponse; }
想咨询两个问题:
- 能否将
CosmosClient.CreateAndInitializeAsync()整合到现有代码中,实现路由缓存填充? - 若上述方式不可行,以下通过读取不存在文档填充缓存的实现方式是否可行?
public class CosmosClientWrapper { public CosmosClientWrapper(IKeyVaultFacade keyVaultFacade) { var container = CreateContainerAsync(endpoint, authenticationKey).GetAwaiter().GetResult(); // Get a document that doesn't exist to populate the routing info: container.ReadItemAsync<object>(Guid.NewGuid().ToString(), PartitionKey.None).GetAwaiter().GetResult(); } }
解答
1. 整合CosmosClient.CreateAndInitializeAsync()的可行方案
完全可以整合,这也是官方推荐的更优雅的冷启动优化方式。CreateAndInitializeAsync()会预先获取容器的路由信息并填充缓存,避免后续请求的冷启动延迟。
你可以修改现有代码,在确认数据库和容器存在后调用该方法完成初始化,修改后的代码示例如下:
private async Task<Container> CreateContainerAsync(string endpoint, string authKey) { var cosmosClientBuilder = new CosmosClientBuilder( accountEndpoint: endpoint, authKeyOrResourceToken: authKey) .WithConnectionModeDirect(portReuseMode: PortReuseMode.PrivatePortPool, idleTcpConnectionTimeout: TimeSpan.FromHours(1)) .WithApplicationName(UserAgentSuffix) .WithConsistencyLevel(ConsistencyLevel.Session) .WithApplicationRegion(Regions.AustraliaEast) .WithRequestTimeout(TimeSpan.FromSeconds(DatabaseRequestTimeoutInSeconds)) .WithThrottlingRetryOptions(TimeSpan.FromSeconds(DatabaseMaxRetryWaitTimeInSeconds), DatabaseMaxRetryAttemptsOnThrottledRequests); var client = cosmosClientBuilder.Build(); // 先确保数据库和容器已存在 var databaseResponse = await CreateDatabaseIfNotExistsAsync(client).ConfigureAwait(false); var containerResponse = await CreateContainerIfNotExistsAsync(databaseResponse.Database).ConfigureAwait(false); // 调用CreateAndInitializeAsync预填充路由缓存 await CosmosClient.CreateAndInitializeAsync( client, new[] { new ContainerProperties(databaseResponse.Database.Id, containerResponse.Container.Id) } ).ConfigureAwait(false); return containerResponse; }
注意:CreateAndInitializeAsync需要传入已存在的数据库和容器ID,因此要先执行资源创建逻辑,避免因资源不存在导致初始化失败。
2. 读取不存在文档的方式是否可行?
这种方式可行,但需要注意几个问题:
- 同步阻塞风险:在构造函数中使用
.GetAwaiter().GetResult()会造成同步阻塞,在ASP.NET等有同步上下文的环境中可能引发死锁。建议改用异步工厂方法:public class CosmosClientWrapper { private readonly Container _container; private CosmosClientWrapper(Container container) { _container = container; } public static async Task<CosmosClientWrapper> CreateAsync(IKeyVaultFacade keyVaultFacade) { // 从密钥库获取Cosmos配置 var endpoint = await keyVaultFacade.GetSecretAsync("CosmosEndpoint").ConfigureAwait(false); var authKey = await keyVaultFacade.GetSecretAsync("CosmosAuthKey").ConfigureAwait(false); var container = await CreateContainerAsync(endpoint, authKey).ConfigureAwait(false); // 读取不存在的文档填充缓存,捕获预期的404异常 try { await container.ReadItemAsync<object>(Guid.NewGuid().ToString(), PartitionKey.None).ConfigureAwait(false); } catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound) { // 忽略预期的资源不存在异常 } return new CosmosClientWrapper(container); } } - 异常处理:读取不存在的文档会返回404异常,必须捕获并忽略,避免程序崩溃。
- 效率问题:相比
CreateAndInitializeAsync,这种方式会多一次无效请求,虽能达到缓存填充目的,但官方推荐优先使用前者。
内容的提问来源于stack exchange,提问作者David Klempfner
相关产品推荐
相关产品推荐

