ASP.NET Core 中的缓存概述

注意

此版本不是本文的最新版本。 有关当前版本,请参阅 本文的 .NET 10 版本

警告

此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 .NET Core 支持策略。 有关当前版本,请参阅 本文的 .NET 10 版本

作者:Rick AndersonTom Dykstra

本文概述了 ASP.NET Core中的缓存,并介绍了内存中、分布式、混合、响应和输出缓存。

内存中缓存

内存中缓存使用服务器内存来存储缓存的数据。 这种类型的缓存适用于使用会话相关性的单个服务器或多台服务器。 会话亲和性也称为“粘滞会话”。 会话亲和性是指来自客户端的请求总是路由到同一个服务器进行处理。

有关详细信息,请参阅 ASP.NET Core 中的内存中缓存排查 Azure 应用程序网关会话亲和性问题

分布式缓存

当应用托管在云或服务器场中时,使用分布式缓存存储数据。 缓存在处理请求的服务器之间共享。 当客户端的缓存数据可用时,客户端可以提交由组中任何服务器处理的请求。 ASP.NET Core 适用于 SQL Server、 RedisPostgresNCache 分布式缓存。

有关详细信息,请参阅 ASP.NET Core 中的分布式缓存

HybridCache

API HybridCache 弥合了 API 中的IDistributedCacheIMemoryCache差距。 HybridCache 是一个抽象类,其默认实现可处理保存到缓存和从缓存中检索的大多数方面。

HybridCache 的功能

HybridCache 提供其他 API 不可用的以下功能:

  • 用于进程内和进程外缓存的统一 API。

    HybridCache 旨在作为现有 IDistributedCacheIMemoryCache 的即插即用替代品,并且提供了一个简单的 API 用于添加新的缓存代码。 如果应用具有 IDistributedCache 实现,HybridCache 服务将其用于辅助缓存。 此两级缓存策略允许 HybridCache 提供内存中缓存的速度以及分布式或永久性缓存的持久性。

  • 踩踏防护。

    当经常使用的缓存条目被撤销,并且过多的请求尝试同时重新填充同一缓存条目时,会发生缓存踩踏。 HybridCache 合并使用同 HybridCache 一实例的并发操作,这可确保给定响应的所有请求等待第一个请求填充缓存。 此协调不会扩展到其他 HybridCache 实例。

  • 可配置的序列化。

    会在注册服务过程中配置序列化,支持通过 WithSerializerWithSerializerFactory 方法进行特定于类型的通用序列化程序(通过 AddHybridCache 调用链接)。 默认情况下,服务在内部处理 stringbyte[] 键入,并将 System.Text.Json 命名空间用于其他所有内容。 HybridCache 可以为其他类型的序列化程序(例如 protobuf 或 XML)配置。

要了解 HybridCache API 的相对简单性,请将使用它的代码与使用 IDistributedCache 的代码进行比较。 下面是使用 IDistributedCache 的示例:

public class SomeService(IDistributedCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        var key = $"someinfo:{name}:{id}"; // Unique key for this combination.
        var bytes = await cache.GetAsync(key, token); // Try to get from cache.
        SomeInformation info;
        if (bytes is null)
        {
            // Cache miss; get the data from the real source.
            info = await SomeExpensiveOperationAsync(name, id, token);

            // Serialize and cache it.
            bytes = SomeSerializer.Serialize(info);
            await cache.SetAsync(key, bytes, token);
        }
        else
        {
            // Cache hit; deserialize it.
            info = SomeSerializer.Deserialize<SomeInformation>(bytes);
        }
        return info;
    }

    // This is the work we're trying to cache.
    private async Task<SomeInformation> SomeExpensiveOperationAsync(string name, int id,
        CancellationToken token = default)
    { /* ... */ }
}

该代码展示了为确保每次都能正确处理而进行的大量工作,包括序列化等。 此外,在“缓存失误”应用场景中,可能最终会出现多个并发线程。 这些线程都有可能遇到缓存未命中现象,都提取基础数据,都对其进行序列化,并都将数据发送到缓存。

下面是使用 HybridCache API 的等效代码:

public class SomeService(HybridCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        return await cache.GetOrCreateAsync(
            $"someinfo:{name}:{id}", // Unique key for this entry.
            async cancel => await SomeExpensiveOperationAsync(name, id, cancel),
            token: token
        );
    }
}

代码更简单,并且库提供踩踏保护以及 IDistributedCache 接口未提供的其他功能。

兼容性

HybridCache 库支持较旧的.NET运行时,包括 .NET Framework 4.7.2 和 .NET Standard 2.0。

详细信息

有关更多信息,请参见以下资源:

响应缓存

响应缓存中间件允许基于 HTTP Cache-Control 标头缓存服务器响应。

  • 缓存行为实现标准 HTTP 缓存语义。

  • 缓存基于类似于代理使用的方法的 HTTP 缓存标头。

  • 这种形式的缓存对于满足 缓存条件 的客户端的公共 GET 或 HEAD API 请求非常有用。

  • 对于页面等 Razor UI 应用,响应缓存通常不是有益的。 浏览器通常设置阻止缓存的请求标头。

    Output 缓存(.NET 7 及更高版本中提供)是 UI 应用的更好方法。 在此方案中,配置确定要缓存哪些内容,而不依赖于 HTTP 标头。

若要测试响应缓存,请使用 Fiddler 或其他可以显式设置请求标头的工具。 显式设置标头是测试缓存的首选项。 有关详细信息,请参阅 响应缓存中间件 > 故障排除

有关详细信息,请参阅 ASP.NET Core 中的响应缓存

输出缓存

输出缓存中间件支持 HTTP 响应的缓存。 输出缓存与响应缓存的不同之处包括以下方面:

  • 缓存行为在服务器上可配置。

    使用 HTTP 标头定义响应缓存行为。 例如,使用 Chrome 或Microsoft Edge浏览网站时,浏览器会自动发送 Cache-control: max-age=0 标头。 此标头实际上禁用响应缓存,因为服务器遵循客户端提供的说明。 即使服务器有新的缓存响应,也会为每个请求返回新的响应。 使用输出缓存时,客户端不会替代在服务器上配置的缓存行为。

  • 缓存存储介质是可扩展的。

    默认情况下使用内存。 响应缓存仅限于内存。

  • 可以通过编程方式使选定的缓存条目无效。

    响应缓存依赖于 HTTP 标头,这使你几乎没有用于使缓存条目失效的选项。

  • 资源锁定可降低缓存踩踏和惊群的风险。

    当经常使用的缓存条目被撤销,并且过多的请求尝试同时重新填充同一缓存条目时,会发生缓存踩踏。 惊群类似于:针对缓存条目中尚未存在的相同响应的突发请求。 资源锁定可确保给定响应的所有请求都等待第一个请求填充缓存。 响应缓存没有资源锁定功能。

  • 缓存重新验证可最大程度地减少带宽使用。

    缓存重新验证 意味着服务器可以返回 304 未修改的 HTTP 状态代码,而不是缓存的响应正文。 此状态代码通知客户端,对请求的响应与之前接收的内容相同。 响应缓存不执行缓存重新验证。

有关详细信息,请参阅 ASP.NET Core 中的输出缓存中间件

缓存标记助手

使用 Cache Tag Helper 将内容缓存自 MVC 视图或Razor页面。 缓存标记帮助程序使用以内存缓存用于存储数据。

有关详细信息,请参阅 ASP.NET Core MVC 中的缓存标记帮助程序

分布式缓存标记帮助程序

使用分布式缓存标签助手在分布式云环境或 Web 场景中缓存来自 MVC 视图或 Razor 页面的内容。 分布式缓存标记帮助程序使用 SQL Server、RedisNCache 来存储数据。

有关详细信息,请参阅 ASP.NET Core 中的分布式缓存标记帮助程序

内存中缓存

内存中缓存使用服务器内存来存储缓存的数据。 这种类型的缓存适用于使用会话亲和性的单个服务器或多个服务器。 会话亲和性也称为“粘滞会话”。 会话亲和性是指来自客户端的请求总是路由到同一个服务器进行处理。

有关详细信息,请参阅 ASP.NET Core 中的内存中缓存排查 Azure 应用程序网关会话亲和性问题

分布式缓存

当应用托管在云或服务器场中时,使用分布式缓存存储数据。 缓存在处理请求的服务器之间共享。 如果客户端的缓存数据可用,则客户端可以提交由组中的任何服务器处理的请求。 ASP.NET Core 适用于 SQL Server、 RedisPostgresNCache 分布式缓存。

有关详细信息,请参阅 ASP.NET Core 中的分布式缓存

HybridCache

API HybridCache 弥合了 API 中的IDistributedCacheIMemoryCache差距。 HybridCache 是一个抽象类,其默认实现可处理保存到缓存和从缓存中检索的大多数方面。

HybridCache 的功能

HybridCache 提供其他 API 不可用的以下功能:

  • 用于进程内和进程外缓存的统一 API。

    HybridCache 旨在作为现有 IDistributedCacheIMemoryCache 的即插即用替代品,并且提供了一个简单的 API 用于添加新的缓存代码。 如果应用具有 IDistributedCache 实现,HybridCache 服务将其用于辅助缓存。 此两级缓存策略允许 HybridCache 提供内存中缓存的速度以及分布式或永久性缓存的持久性。

  • 踩踏防护。

    当经常使用的缓存条目被撤销,并且过多的请求尝试同时重新填充同一缓存条目时,会发生缓存踩踏。 HybridCache 合并使用同 HybridCache 一实例的并发操作,这可确保给定响应的所有请求等待第一个请求填充缓存。 此协调不会扩展到其他 HybridCache 实例。

  • 可配置的序列化。

    会在注册服务过程中配置序列化,支持通过 WithSerializerWithSerializerFactory 方法进行特定于类型的通用序列化程序(通过 AddHybridCache 调用链接)。 默认情况下,服务在内部处理 stringbyte[] 键入,并将 System.Text.Json 命名空间用于其他所有内容。 HybridCache 可以为其他类型的序列化程序(例如 protobuf 或 XML)配置。

要了解 HybridCache API 的相对简单性,请将使用它的代码与使用 IDistributedCache 的代码进行比较。 下面是使用 IDistributedCache 的示例:

public class SomeService(IDistributedCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        var key = $"someinfo:{name}:{id}"; // Unique key for this combination.
        var bytes = await cache.GetAsync(key, token); // Try to get from cache.
        SomeInformation info;
        if (bytes is null)
        {
            // Cache miss; get the data from the real source.
            info = await SomeExpensiveOperationAsync(name, id, token);

            // Serialize and cache it.
            bytes = SomeSerializer.Serialize(info);
            await cache.SetAsync(key, bytes, token);
        }
        else
        {
            // Cache hit; deserialize it.
            info = SomeSerializer.Deserialize<SomeInformation>(bytes);
        }
        return info;
    }

    // This is the work we're trying to cache.
    private async Task<SomeInformation> SomeExpensiveOperationAsync(string name, int id,
        CancellationToken token = default)
    { /* ... */ }
}

该代码展示了为确保每次都能正确处理而进行的大量工作,包括序列化等。 此外,在“缓存失误”应用场景中,可能最终会出现多个并发线程。 这些线程都有可能遇到缓存未命中现象,都提取基础数据,都对其进行序列化,并都将数据发送到缓存。

下面是使用 HybridCache API 的等效代码:

public class SomeService(HybridCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        return await cache.GetOrCreateAsync(
            $"someinfo:{name}:{id}", // Unique key for this entry.
            async cancel => await SomeExpensiveOperationAsync(name, id, cancel),
            token: token
        );
    }
}

代码更简单,并且库提供踩踏保护以及 IDistributedCache 接口未提供的其他功能。

兼容性

HybridCache 库支持较旧的.NET运行时,包括 .NET Framework 4.7.2 和 .NET Standard 2.0。

详细信息

有关更多信息,请参见以下资源:

缓存标记助手

使用 Cache Tag Helper 将内容缓存自 MVC 视图或Razor页面。 缓存标记帮助程序使用以内存缓存用于存储数据。

有关详细信息,请参阅 ASP.NET Core MVC 中的缓存标记帮助程序

分布式缓存标记帮助程序

使用分布式缓存标签助手在分布式云环境或 Web 场景中缓存来自 MVC 视图或 Razor 页面的内容。 分布式缓存标记帮助程序使用 SQL Server、RedisNCache 来存储数据。

有关详细信息,请参阅 ASP.NET Core 中的分布式缓存标记帮助程序

响应缓存

响应缓存中间件允许基于 HTTP Cache-Control 标头缓存服务器响应。

  • 缓存行为实现标准 HTTP 缓存语义。

  • 缓存基于类似于代理使用的方法的 HTTP 缓存标头。

  • 这种形式的缓存对于满足 缓存条件 的客户端的公共 GET 或 HEAD API 请求非常有用。

  • 对于页面等 Razor UI 应用,响应缓存通常不是有益的。 浏览器通常设置阻止缓存的请求标头。

    Output 缓存(.NET 7 及更高版本中提供)是 UI 应用的更好方法。 在此方案中,配置确定要缓存哪些内容,而不依赖于 HTTP 标头。

若要测试响应缓存,请使用 Fiddler 或其他可以显式设置请求标头的工具。 显式设置标头是测试缓存的首选项。 有关详细信息,请参阅 响应缓存中间件 > 故障排除

输出缓存

输出缓存中间件支持 HTTP 响应的缓存。 输出缓存与响应缓存的不同之处包括以下方面:

  • 缓存行为可在服务器上配置。

    响应缓存行为由 HTTP 标头定义。 例如,使用 Chrome 或 Edge 访问网站时,浏览器会自动发送 Cache-control: max-age=0 标头。 此标头将有效地禁用响应缓存,因为服务器遵循客户端提供的说明。 即使服务器有新的缓存响应,也会为每个请求返回新的响应。 使用输出缓存时,客户端不会替代你在服务器上配置的缓存行为。

  • 缓存存储介质是可扩展的。

    默认情况下使用内存。 响应缓存仅限于内存。

  • 可以通过编程方式使选定的缓存条目无效。

    响应缓存对 HTTP 标头的依赖导致只有几个选项可以使缓存条目失效。

  • 资源锁定可降低缓存踩踏和惊群的风险。

    当经常使用的缓存条目被撤销,并且过多的请求尝试同时重新填充同一缓存条目时,会发生缓存踩踏。 惊群类似于:针对缓存条目中尚未存在的相同响应的突发请求。 资源锁定可确保给定响应的所有请求都等待第一个请求填充缓存。 响应缓存没有资源锁定功能。

  • 缓存重新验证可最大程度地减少带宽使用。

    缓存重新验证意味着服务器可以返回 HTTP 状态代码,而不是缓存的响应正文。 此状态代码通知客户端,对请求的响应与之前接收的内容相同。 响应缓存不执行缓存重新验证。

内存中缓存

内存中缓存使用服务器内存来存储缓存的数据。 这种类型的缓存适用于使用会话亲和性的单个服务器或多个服务器。 会话亲和性也称为“粘滞会话”。 会话亲和性是指来自客户端的请求总是路由到同一个服务器进行处理。

有关详细信息,请参阅 ASP.NET Core 中的内存中缓存排查 Azure 应用程序网关会话亲和性问题

分布式缓存

当应用托管在云或服务器场中时,使用分布式缓存存储数据。 缓存在处理请求的服务器之间共享。 如果客户端的缓存数据可用,则客户端可以提交由组中的任何服务器处理的请求。 ASP.NET Core 适用于 SQL Server、 RedisPostgresNCache 分布式缓存。

有关详细信息,请参阅 ASP.NET Core 中的分布式缓存

HybridCache

API HybridCache 弥合了 API 中的IDistributedCacheIMemoryCache差距。 HybridCache 是一个抽象类,其默认实现可处理保存到缓存和从缓存中检索的大多数方面。

HybridCache 的功能

HybridCache 提供其他 API 不可用的以下功能:

  • 用于进程内和进程外缓存的统一 API。

    HybridCache 旨在作为现有 IDistributedCacheIMemoryCache 的即插即用替代品,并且提供了一个简单的 API 用于添加新的缓存代码。 如果应用具有 IDistributedCache 实现,HybridCache 服务将其用于辅助缓存。 此两级缓存策略允许 HybridCache 提供内存中缓存的速度以及分布式或永久性缓存的持久性。

  • 踩踏防护。

    当经常使用的缓存条目被撤销,并且过多的请求尝试同时重新填充同一缓存条目时,会发生缓存踩踏。 HybridCache 合并使用同 HybridCache 一实例的并发操作,这可确保给定响应的所有请求等待第一个请求填充缓存。 此协调不会扩展到其他 HybridCache 实例。

  • 可配置的序列化。

    会在注册服务过程中配置序列化,支持通过 WithSerializerWithSerializerFactory 方法进行特定于类型的通用序列化程序(通过 AddHybridCache 调用链接)。 默认情况下,服务在内部处理 stringbyte[] 键入,并将 System.Text.Json 命名空间用于其他所有内容。 HybridCache 可以为其他类型的序列化程序(例如 protobuf 或 XML)配置。

要了解 HybridCache API 的相对简单性,请将使用它的代码与使用 IDistributedCache 的代码进行比较。 下面是使用 IDistributedCache 的示例:

public class SomeService(IDistributedCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        var key = $"someinfo:{name}:{id}"; // Unique key for this combination.
        var bytes = await cache.GetAsync(key, token); // Try to get from cache.
        SomeInformation info;
        if (bytes is null)
        {
            // Cache miss; get the data from the real source.
            info = await SomeExpensiveOperationAsync(name, id, token);

            // Serialize and cache it.
            bytes = SomeSerializer.Serialize(info);
            await cache.SetAsync(key, bytes, token);
        }
        else
        {
            // Cache hit; deserialize it.
            info = SomeSerializer.Deserialize<SomeInformation>(bytes);
        }
        return info;
    }

    // This is the work we're trying to cache.
    private async Task<SomeInformation> SomeExpensiveOperationAsync(string name, int id,
        CancellationToken token = default)
    { /* ... */ }
}

该代码展示了为确保每次都能正确处理而进行的大量工作,包括序列化等。 此外,在“缓存失误”应用场景中,可能最终会出现多个并发线程。 这些线程都有可能遇到缓存未命中现象,都提取基础数据,都对其进行序列化,并都将数据发送到缓存。

下面是使用 HybridCache API 的等效代码:

public class SomeService(HybridCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        return await cache.GetOrCreateAsync(
            $"someinfo:{name}:{id}", // Unique key for this entry.
            async cancel => await SomeExpensiveOperationAsync(name, id, cancel),
            token: token
        );
    }
}

代码更简单,并且库提供踩踏保护以及 IDistributedCache 接口未提供的其他功能。

兼容性

HybridCache 库支持较旧的.NET运行时,包括 .NET Framework 4.7.2 和 .NET Standard 2.0。

详细信息

有关更多信息,请参见以下资源:

缓存标记助手

使用 Cache Tag Helper 将内容缓存自 MVC 视图或Razor页面。 缓存标记帮助程序使用以内存缓存用于存储数据。

有关详细信息,请参阅 ASP.NET Core MVC 中的缓存标记帮助程序

分布式缓存标记帮助程序

使用分布式缓存标签助手在分布式云环境或 Web 场景中缓存来自 MVC 视图或 Razor 页面的内容。 分布式缓存标记帮助程序使用 SQL Server、RedisNCache 来存储数据。

有关详细信息,请参阅 ASP.NET Core 中的分布式缓存标记帮助程序

响应缓存

响应缓存中间件允许基于 HTTP Cache-Control 标头缓存服务器响应。

  • 缓存行为实现标准 HTTP 缓存语义。

  • 缓存基于类似于代理使用的方法的 HTTP 缓存标头。

  • 这种形式的缓存对于满足 缓存条件 的客户端的公共 GET 或 HEAD API 请求非常有用。

  • 对于页面等 Razor UI 应用,响应缓存通常不是有益的。 浏览器通常设置阻止缓存的请求标头。

    Output 缓存(.NET 7 及更高版本中提供)是 UI 应用的更好方法。 在此方案中,配置确定要缓存哪些内容,而不依赖于 HTTP 标头。

若要测试响应缓存,请使用 Fiddler 或其他可以显式设置请求标头的工具。 显式设置标头是测试缓存的首选项。 有关详细信息,请参阅 响应缓存中间件 > 故障排除

输出缓存

输出缓存 在 .NET 7 或更高版本中可用。