65.9K
CodeProject 正在变化。 阅读更多。
Home

Azure 存储缓存和压缩 – 缺失的部分

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2023 年 1 月 1 日

Ms-PL

4分钟阅读

viewsIcon

20952

Azure 存储缓存和压缩

我编写并使用了大量的 Azure 存储 服务,用于处理我在云中构建的应用程序。使用起来非常简单,只需将一些文件放入其中,它们就可以在内部提供给其他应用程序,或者您可以让公众远程访问它们。

关于对该服务的公共访问,我一直感到震惊的是,内容从未被缓存,从未被压缩,而且总的来说,感觉就像一个简单的 Web 服务器在提供内容,而没有我们真正喜欢的现代 Web 的一些功能。这将减少对服务器的查询次数以及交付内容所需的带宽。

在本文中,我将向您展示如何为我希望与我的 Web 应用程序 KlipTok 一起使用的 Azure 存储 blob 缓存激活缓存和压缩。

将数据保存到 Azure 存储 - 基本知识

我有一个流程,每 30 分钟在后台运行,以识别 KlipTok 上最受欢迎的剪辑,并将它们的数据缓存在 Azure 存储中,作为 JSON 文件,可以在首次访问网站时下载。保存此数据的代码如下所示:

var blobServiceClient = new BlobServiceClient
    (EnvironmentConfiguration.TableStorageConnectionString);
var containerClient = blobServiceClient.GetBlobContainerClient("cache");
var client = containerClient.GetBlobClient("fileToCache.json");
await client.UploadAsync(myContentToCacheAsStream, true);

这会创建一个 blob 客户端,连接到名为 cache 的容器,定义一个名为 fileToCache.json 的文件,并以上传权限开启的方式上传内容(在最后一行使用 true 参数)。

注意:我将此代码嵌入在 Azure 函数中,并且可以使用 Azure 函数的输出绑定功能来编写此内容。 在使用该配置运行我的应用程序一个月后,我强烈建议您永远不要使用该功能。 触发该函数后,输出绑定会立即删除 blob 的内容。 如果函数中出现错误或函数需要一段时间才能完成,那么依赖该内容的系统的其余部分将难以应对。 相反,构建一个 BlobServiceClient 并以这种方式连接到您的存储,以便您可以正确处理错误并最大限度地减少上传内容时的停机时间。

添加缓存标头

我们可以通过使用 BlobClientHttpHeaders 中添加几行来轻松地为该文件添加缓存标头。 我希望将此文件缓存 30 分钟,并可在任何公共代理或服务器上使用。 让我们在 UploadAsync 调用之后添加这些标头

await client.SetHttpHeadersAsync(new BlobHttpHeaders
{
    CacheControl = "public, max-age=3600, must-revalidate",
    ContentType = "application/json, charset=utf-8"
});

这很容易。 CacheControl 标头 有一个明确的定义,该定义已经存在很长时间了,并且需要一个以秒为单位的 max-age。 must-revalidate 指令规定,当缓存 max-age 过期时,缓存服务器必须请求该文件的新副本,并且不应提供早于 max-age 的文件。

压缩内容

Azure 存储没有像大多数 Web 服务器那样自动压缩或使用 Brotli 压缩内容并提供内容的方法。 在 IIS 上,有一个面板,您只需选中一个复选框即可清楚地激活压缩。 对于其他 Web 服务器,服务器的配置文件中有一个条目将启用 Gzip 压缩。

IIS 压缩设置

使用 Azure 存储,我们需要手动进行压缩,并添加一个适当的标头条目来指示压缩。 .NET BCL 具有一个 GZipStream 对象可用,我们可以使用标准 System.Text.JsonSerializer 通过该对象路由内容,代码如下所示

var MyContent = GetClipsToCache().ToArray();

using var myContentToCacheAsStream = new MemoryStream();
using var compressor = 
      new GZipStream(myContentToCacheAsStream, CompressionLevel.Optimal);
await JsonSerializer.SerializeAsync(compressor, MyContent, options);
compressor.Flush();

myContentToCacheAsStream.Position = 0;

我使用第一行 GetClipsToCache() 获取要缓存的数据,并将其作为一个数组放入 MyContent 变量中。 分配一个 MemoryStream,它将接收压缩内容,并且还分配一个 GZipStream,它将把其压缩输出传递到 myContentToCacheAsStream 中。 最后,我将数据序列化为 JSON 并将其写入压缩器 GZipStream,它将进行压缩并将其传递给 myContentToCacheAsStream 变量。 刷新 GZipStream 以确保所有数据都已压缩,并将目标流的位置重置为 0,以便可以将其写入 blob 存储。

我们需要更新标头以包含一个指示正在提供的内容已进行 GZip 压缩的指示。 很容易更新我们刚刚添加的用于缓存标头的代码以包含此内容

await client.SetHttpHeadersAsync(new BlobHttpHeaders
{
  CacheControl = "public, max-age=3600, must-revalidate",
  ContentType = "application/json, charset=utf-8",
  ContentEncoding = "gzip"
});

额外福利 - 仅使用 Frontdoor

也许您不想编写此代码,而只想将其卸载到另一个服务。 您可以配置 Azure Frontdoor 通过在路由配置面板上选中一个复选框,以压缩和缓存的方式提供此内容,作为另一条路由

Azure Frontdoor 缓存和压缩配置

摘要

通过这额外的代码,我将访问 KlipTok 时初始下载中使用的文件大小从 250k 减少到 60k,带宽使用量减少了 76%。 随着添加了缓存控制标头,我的应用程序和我的用户之间的浏览器和缓存服务器将保留此文件的副本,并减少从我的服务器请求新内容的次数。 随着我网站的用户数量增加,以及我需要交付的数据量增加,这是一个受欢迎的功能,可以减少带宽,从而降低我的托管成本。

© . All rights reserved.