如何快速获取Azure Storage容器的文件数量与大小?
优化方案
核心性能瓶颈分析
原代码的慢速度主要来自以下几个问题:
- 重复枚举
GetBlobs()集合,触发两次Azure存储服务请求 - 每个Blob单独调用
GetProperties(),产生数万次独立HTTP请求,这是最大的性能消耗点 - 每次循环单独执行
SaveChangesAsync(),频繁触发数据库IO操作 - 同步处理容器,未利用并行计算能力
具体优化措施
1. 直接从BlobItem获取大小,避免额外请求
BlobItem本身就包含ContentLength属性,不需要再调用GetProperties()去单独请求每个Blob的属性,这能减少99%的HTTP请求量。
2. 单次枚举Blob集合
不要先调用Count()再遍历,改为一次枚举同时统计数量和总大小,减少一次存储服务请求。
3. 批量提交数据库操作
积累所有容器的统计结果后,一次性提交到数据库,避免频繁的数据库写入操作。
4. 并行处理多个容器
利用并行异步处理来同时处理多个容器,提升整体效率,注意控制并发数避免触发Azure存储的请求限制。
优化后的代码示例
var blobServiceClient = new BlobServiceClient(connectionStr); var containers = blobServiceClient.GetBlobContainers(); var storageInfos = new List<StorageInformation>(); // 控制并发数,根据Azure存储配额调整,建议设置为5-15 var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = 10 }; await Parallel.ForEachAsync(containers, parallelOptions, async (container, cancellationToken) => { var containerClient = blobServiceClient.GetBlobContainerClient(container.Name); // 一次性获取Blob列表,包含ContentLength属性 var blobItems = containerClient.GetBlobs(cancellationToken: cancellationToken); long totalSize = 0; int fileCount = 0; await foreach (var blobItem in blobItems.WithCancellation(cancellationToken)) { fileCount++; if (blobItem.Properties.ContentLength.HasValue) { totalSize += blobItem.Properties.ContentLength.Value; } } var storageInfo = new StorageInformation() { Customer_GUID = new Guid(container.Name), FileCount = fileCount, StorageSize = totalSize }; // 线程安全地添加到集合 lock (storageInfos) { storageInfos.Add(storageInfo); } }); // 批量写入数据库 dbContext.StorageInformation.AddRange(storageInfos); await dbContext.SaveChangesAsync();
额外优化建议
- 分页查询Blob:如果单容器Blob数量极大,可指定
MaxResultsPerPage参数分页获取,避免内存占用过高 - 监控请求节流:查看Azure存储的指标,若出现请求被节流,适当降低并行数
- 缓存容器列表:若容器列表不会频繁变动,可缓存容器名称集合,避免重复请求获取容器列表
内容的提问来源于stack exchange,提问作者Jonathan
相关产品推荐
相关产品推荐

