我有一个用于某个项目的简单架构,它有点像这样:
- 用户使用 ASP.NET MVC 请求文件
- 为所述文件检查本地缓存,如果缓存中不存在该文件,则从 Azure Blob 存储中提取该文件。
- 至此,该文件肯定在我的服务器上,并且我知道路径。
- 我使用第三方库打开文件,我为它提供路径,然后它返回一个类结构,我用它来为用户创建一个视图。
这在 99% 的时间里都有效。文件要么在缓存中找到,要么下载,然后使用第三方代码打开,然后以漂亮的视图呈现给用户。
但是,我可以复制一组奇怪的情况,这会导致我的生产服务器彻底崩溃。
它们是:
- 在缓存中找不到文件
- 文件从 Azure 下载
- 打开文件时第三方(不安全)库崩溃
- 带上服务器。
我知道我在使用不安全的库时遇到了一些麻烦,但最奇怪的是,如果我第二次尝试,该文件现在将在缓存中,因为第一次正确使用了 Azure,Azure 没有被命中,该文件将成功打开。
第三方库本质上认为从 Azure 下载的文件已损坏,但是当完全相同的代码尝试在没有 Azure 参与的情况下打开完全相同的文件时,它打开没有问题。
所以我最初责怪 Azure,也许我没有正确关闭文件。我已经检查过了,我用来获取文件的文件流肯定是关闭的(它被包装在 using 语句中)。
代码如下,(forceRefresh 是一个我可以设置为始终跳过本地缓存的标志)。路径设置为我服务器上的某个位置 ~/tmp
if (!File.Exists(path) || forceRefresh)
{
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer blobContainer = blobClient.GetContainerReference("mycontainer");
ICloudBlob blob = blobContainer.GetBlockBlobReference("myblob");
using (var filestream = new FileStream(path,FileMode.Create,FileAccess.ReadWrite,FileShare.Read))
{
blob.DownloadToStream(filestream);
}
}
更奇怪的是,我重复了我的测试,这一次,在崩溃之后,我从缓存中删除了文件,这样 Azure 就会再次被击中。它是,文件打开而不会导致崩溃。
所以它似乎只在第一次打开从 Azure 下载的文件时发生——我可以通过回收应用程序池来按需导致错误。
有人对我如何调试这个有任何建议吗?我无法在我的本地开发机器上复制。
编辑:理查德·特纳对反馈的回答
我不相信 Blob 检索代码是导致异常的原因。这样做的原因是,如果 Web 应用程序确实崩溃,这是在文件下载之后。我什至可以验证文件没有损坏,因为我可以在后续重试时打开它。
关于“不安全”,您所说的完全正确-我有执行 PInvoke 的包装器代码-但是,它没有实现 IDisposable,这是我将立即研究的内容。至于性能,目前我并不担心。
关于重组我的代码,我描述的“缓存”实际上是磁盘上的一组文件,所以本质上我已经有了你推荐的结构。第 3 方库仅接受文件路径作为输入,因此我必须遵循该路线。
回答您的最后问题:
将 blob 作为流读取是我可以看到的唯一可以读取它的方法吗?我没有看到任何 API 方法可以将其作为 byte[] 或其他任何东西。
FileStream 不需要读/写,但改变它并没有改善。