ASP.NET Core 中的分布式缓存
作者:Mohsin Nasir 和 smandia
说明
此版本不是本文的最新版本。 对于当前版本,请参阅此文的 .NET 8 版本。
警告
此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 .NET Core 支持策略。 对于当前版本,请参阅此文的 .NET 8 版本。
分布式缓存是由多个应用服务器共享的缓存,通常作为访问它的应用服务器的外部服务进行维护。 分布式缓存可以提高 ASP.NET Core 应用的性能和可伸缩性,尤其是当应用由云服务或服务器场托管时。
与其他将缓存数据存储在单个应用服务器上的缓存方案相比,分布式缓存具有多个优势。
当分发缓存数据时,数据:
- 在多个服务器的请求之间保持一致(一致性)。
- 在进行服务器重启和应用部署后仍然有效。
- 不使用本地内存。
分布式缓存配置是特定于实现的。 本文介绍如何配置 SQL Server 和 Redis 分布式缓存。 还提供第三方实现,例如 NCache(GitHub 上的 NCache)。 无论选择哪种实现,应用都将使用 IDistributedCache 接口与缓存进行交互。
警告
本文使用不需要对用户进行身份验证的本地数据库。 生产应用应使用可用的最安全的身份验证流。 有关已部署测试和生产应用的身份验证的详细信息,请参阅安全身份验证流。
先决条件
为所使用的分布式缓存提供程序添加包引用:
- 对于 Redis 分布式缓存,Microsoft.Extensions.Caching.StackExchangeRedis。
- 对于 SQL Server,Microsoft.Extensions.Caching.SqlServer。
- 对于 NCache 分布式缓存,NCache.Microsoft.Extensions.Caching.OpenSource。
IDistributedCache 接口
IDistributedCache 接口提供以下方法来处理分布式缓存实现中的项:
- Get、GetAsync:如果在缓存中找到,则接受字符串键并以
byte[]
数组的形式检索缓存项。 - Set、SetAsync:使用字符串键将项(作为
byte[]
数组)添加到缓存。 - Refresh、RefreshAsync:根据键刷新缓存中的项,重置其可调到期超时(如果有)。
- Remove、RemoveAsync:根据字符串键删除缓存项。
建立分布式缓存服务
在 Program.cs
中注册 IDistributedCache 实现。 本主题中所介绍的框架提供的实现包括:
分布式 Redis 缓存
建议生产应用使用分布式 Redis 缓存,因为它是性能最高的。 有关详细信息,请参阅建议。
Redis 是一种开放源代码内存中数据存储,通常用作分布式缓存。 可以为 Azure 托管的 ASP.NET Core 应用配置 Azure Cache for Redis,并使用 Azure Cache for Redis 进行本地开发。
应用会使用 RedisCache 实例通过调用 AddStackExchangeRedisCache 来配置缓存实现。 对于输出缓存,请使用 AddStackExchangeRedisOutputCache
。
- 创建 Azure Cache for Redis。
- 将主连接字符串 (StackExchange.Redis) 复制到配置。
- 本地开发:使用机密管理器保存连接字符串。
- Azure:将连接字符串保存在安全存储中,例如 Azure 密钥保管库
以下代码启用 Azure Cache for Redis:
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration.GetConnectionString("MyRedisConStr");
options.InstanceName = "SampleInstance";
});
上述代码假定主连接字符串 (StackExchange.Redis) 以键名 MyRedisConStr
保存在配置中。
有关详细信息,请参阅 Azure Cache for Redis。
有关本地 Redis 缓存的替代方法的讨论,请参阅此 GitHub 问题。
分布式内存缓存
分布式内存缓存 (AddDistributedMemoryCache) 是框架提供的 IDistributedCache 实现,用于将项存储在内存中。 分布式内存缓存不是真正的分布式缓存。 缓存项由应用实例存储在运行该应用的服务器上。
分布式内存缓存是一个有用的实现:
- 在开发和测试场景中。
- 当在生产环境中使用单个服务器并且内存消耗不重要时。 实现分布式内存缓存会抽象缓存的数据存储。 如果需要多个节点或容错,它允许在未来实现真正的分布式缓存解决方案。
当应用在 Program.cs
的开发环境中运行时,示例应用使用分布式内存缓存:
builder.Services.AddDistributedMemoryCache();
分布式 SQL Server 缓存
分布式 SQL Server 缓存实现 (AddDistributedSqlServerCache) 允许分布式缓存使用 SQL Server 数据库作为其后备存储。 要在 SQL Server 实例中创建 SQL Server 缓存项表,可以使用 sql-cache
工具。 该工具使用指定的名称和架构来创建表。
通过运行 sql-cache create
命令在 SQL Server 中创建一个表。 提供 SQL Server 实例 (Data Source
)、数据库 (Initial Catalog
)、架构(例如 dbo
)和表名(例如 TestCache
):
dotnet sql-cache create "Data Source=(localdb)/MSSQLLocalDB;Initial Catalog=DistCache;Integrated Security=True;" dbo TestCache
将记录一条消息以指示该工具已成功:
Table and index were created successfully.
通过 sql-cache
工具创建的表具有以下架构:
注意
应用应使用 IDistributedCache 实例(而不是 SqlServerCache)来处理缓存值。
示例应用在 Program.cs
的非开发环境中实现 SqlServerCache:
builder.Services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = builder.Configuration.GetConnectionString(
"DistCache_ConnectionString");
options.SchemaName = "dbo";
options.TableName = "TestCache";
});
说明
ConnectionString(以及可选的 SchemaName 和 TableName)通常存储在源代码管理外部(例如,由机密管理器存储或存储在 appsettings.json
/appsettings.{Environment}.json
文件中)。 连接字符串可能包含应保留在源代码管理系统外部的凭据。
分布式 NCache 缓存
NCache 是在 .NET 和 .NET Core 中以原生方式开发的开放源代码内存中分布式缓存。 NCache 既可以在本地工作,也可配置为在 Azure 或其他托管平台上运行的 ASP.NET Core 应用的分布式缓存群集。
要在本地计算机上安装和配置 NCache,请参阅Windows 入门指南(.NET 和 .NET Core)。
若要配置 NCache,请执行以下操作:
- 安装 NCache 开放源代码 NuGet。
- 在 client.ncconf 中配置缓存群集。
- 将下列代码添加到
Program.cs
:
builder.Services.AddNCacheDistributedCache(configuration =>
{
configuration.CacheName = "democache";
configuration.EnableLogs = true;
configuration.ExceptionsEnabled = true;
});
分布式 Azure CosmosDB 缓存
通过使用 接口,Azure Cosmos DBIDistributedCache
可以在 ASP.NET Core 中用作会话状态提供程序。 Azure Cosmos DB 是一个完全托管的 NoSQL 和关系数据库,适用于新式应用程序开发,为任务关键型应用程序提供高可用性、可伸缩性和低延迟的数据访问。
安装 Microsoft.Extensions.Caching.Cosmos NuGet 包后,配置 Azure Cosmos DB 分布式缓存,如下所示:
重用现有客户端
配置分布式缓存的最简单方法是重用现有的 Azure Cosmos DB 客户端。 在这种情况下,当释放提供程序时,不会释放 CosmosClient
实例。
services.AddCosmosCache((CosmosCacheOptions cacheOptions) =>
{
cacheOptions.ContainerName = Configuration["CosmosCacheContainer"];
cacheOptions.DatabaseName = Configuration["CosmosCacheDatabase"];
cacheOptions.CosmosClient = existingCosmosClient;
cacheOptions.CreateIfNotExists = true;
});
创建新客户端
或者,实例化新客户端。 在这种情况下,当释放提供程序时,将释放 CosmosClient
实例。
services.AddCosmosCache((CosmosCacheOptions cacheOptions) =>
{
cacheOptions.ContainerName = Configuration["CosmosCacheContainer"];
cacheOptions.DatabaseName = Configuration["CosmosCacheDatabase"];
cacheOptions.ClientBuilder = new CosmosClientBuilder(Configuration["CosmosConnectionString"]);
cacheOptions.CreateIfNotExists = true;
});
使用分布式缓存
要使用 IDistributedCache 接口,请在应用中请求 IDistributedCache 实例。 该实例由依赖项注入 (DI) 提供。
当示例应用启动时,会将 IDistributedCache 注入到 Program.cs
。 当前时间是使用 IHostApplicationLifetime 缓存的(有关详细信息,请参阅通用主机:IHostApplicationLifetime):
app.Lifetime.ApplicationStarted.Register(() =>
{
var currentTimeUTC = DateTime.UtcNow.ToString();
byte[] encodedCurrentTimeUTC = System.Text.Encoding.UTF8.GetBytes(currentTimeUTC);
var options = new DistributedCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(20));
app.Services.GetService<IDistributedCache>()
.Set("cachedTimeUTC", encodedCurrentTimeUTC, options);
});
示例应用将 IDistributedCache 注入 IndexModel
,以供索引页面使用。
每次加载索引页面时,都会检查缓存中 OnGetAsync
中的缓存时间。 如果缓存时间尚未过期,则会显示该时间。 如果自上次访问缓存时间(上次加载此页面)以来已过去 20 秒,则页面显示“缓存时间已过期”。
选择“重置缓存时间”按钮,即可将缓存时间更新为当前时间。 该按钮将触发 OnPostResetCachedTime
处理程序方法。
public class IndexModel : PageModel
{
private readonly IDistributedCache _cache;
public IndexModel(IDistributedCache cache)
{
_cache = cache;
}
public string? CachedTimeUTC { get; set; }
public string? ASP_Environment { get; set; }
public async Task OnGetAsync()
{
CachedTimeUTC = "Cached Time Expired";
var encodedCachedTimeUTC = await _cache.GetAsync("cachedTimeUTC");
if (encodedCachedTimeUTC != null)
{
CachedTimeUTC = Encoding.UTF8.GetString(encodedCachedTimeUTC);
}
ASP_Environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
if (String.IsNullOrEmpty(ASP_Environment))
{
ASP_Environment = "Null, so Production";
}
}
public async Task<IActionResult> OnPostResetCachedTime()
{
var currentTimeUTC = DateTime.UtcNow.ToString();
byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC);
var options = new DistributedCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(20));
await _cache.SetAsync("cachedTimeUTC", encodedCurrentTimeUTC, options);
return RedirectToPage();
}
}
对于具有内置实现的 IDistributedCache 实例,无需使用单一实例或范围内的生存期。
也可按需创建 IDistributedCache 实例,而不是使用 DI,但在代码中创建实例会使代码更难测试并且违反了显式依赖项原则。
建议
在确定适合你的应用的最佳 IDistributedCache 实现时,请考虑以下几点:
- 现有基础结构
- 性能要求
- 成本
- 团队经验
缓存解决方案通常依靠内存中存储来提供对缓存数据的快速检索,但内存是一种有限的资源并且扩展成本很高。 仅将常用数据存储在缓存中。
对于大多数应用来说,与 SQL Server 缓存相比,Redis 缓存可提供更高的吞吐量和更低的延迟。 但建议进行基准测试来确定缓存策略的性能特征。
当将 SQL Server 用作分布式缓存后备存储时,如果将同一数据库用于缓存以及应用的普通数据存储和检索,这可能会对两者的性能产生负面影响。 建议对分布式缓存后备存储使用专用的 SQL Server 实例。
其他资源
- Azure 上的 Redis 缓存
- Azure 上的 SQL 数据库
- 用于 Web 场中 NCache 的 ASP.NET Core IDistributedCache 提供程序(GitHub 上的 NCache)
- Microsoft.Extensions.Caching.Cosmos 的存储库自述文件
- ASP.NET Core 中的内存中缓存
- 使用 ASP.NET Core 中的更改令牌检测更改
- ASP.NET Core 中的响应缓存
- ASP.NET Core 中的响应缓存中间件
- ASP.NET Core MVC 中的缓存标记帮助程序
- ASP.NET Core 中的分布式缓存标记帮助程序
- 在 Web 场中托管 ASP.NET Core
// ms.sfi.ropc: t
分布式缓存是由多个应用服务器共享的缓存,通常作为访问它的应用服务器的外部服务进行维护。 分布式缓存可以提高 ASP.NET Core 应用的性能和可伸缩性,尤其是当应用由云服务或服务器场托管时。
与其他将缓存数据存储在单个应用服务器上的缓存方案相比,分布式缓存具有多个优势。
当分发缓存数据时,数据:
- 在多个服务器的请求之间保持一致(一致性)。
- 在进行服务器重启和应用部署后仍然有效。
- 不使用本地内存。
分布式缓存配置是特定于实现的。 本文介绍如何配置 SQL Server 和 Redis 分布式缓存。 还提供第三方实现,例如 NCache(GitHub 上的 NCache)。 无论选择哪种实现,应用都将使用 IDistributedCache 接口与缓存进行交互。
先决条件
为所使用的分布式缓存提供程序添加包引用:
对于 Redis 分布式缓存,Microsoft.Extensions.Caching.StackExchangeRedis。
对于 SQL Server,Microsoft.Extensions.Caching.SqlServer。
对于 NCache 分布式缓存,NCache.Microsoft.Extensions.Caching.OpenSource。
-
警告
本文使用不需要对用户进行身份验证的本地数据库。 生产应用应使用可用的最安全的身份验证流。 有关已部署测试和生产应用的身份验证的详细信息,请参阅安全身份验证流。
IDistributedCache 接口
IDistributedCache 接口提供以下方法来处理分布式缓存实现中的项:
- Get、GetAsync:如果在缓存中找到,则接受字符串键并以
byte[]
数组的形式检索缓存项。 - Set、SetAsync:使用字符串键将项(作为
byte[]
数组)添加到缓存。 - Refresh、RefreshAsync:根据键刷新缓存中的项,重置其可调到期超时(如果有)。
- Remove、RemoveAsync:根据字符串键删除缓存项。
建立分布式缓存服务
在 Program.cs
中注册 IDistributedCache 实现。 本主题中所介绍的框架提供的实现包括:
分布式 Redis 缓存
建议生产应用使用分布式 Redis 缓存,因为它是性能最高的。 有关详细信息,请参阅建议。
Redis 是一种开放源代码内存中数据存储,通常用作分布式缓存。 可以为 Azure 托管的 ASP.NET Core 应用配置 Azure Redis 缓存,并使用 Azure Redis 缓存进行本地开发。
应用使用 RedisCache 实例 (AddStackExchangeRedisCache) 来配置缓存实现。
- 创建 Azure Cache for Redis。
- 将主连接字符串 (StackExchange.Redis) 复制到配置。
- 本地开发:使用机密管理器保存连接字符串。
- Azure:将连接字符串保存在安全存储中,例如 Azure 密钥保管库
以下代码启用 Azure Cache for Redis:
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration.GetConnectionString("MyRedisConStr");
options.InstanceName = "SampleInstance";
});
上述代码假定主连接字符串 (StackExchange.Redis) 以键名 MyRedisConStr
保存在配置中。
有关详细信息,请参阅 Azure Cache for Redis。
有关本地 Redis 缓存的替代方法的讨论,请参阅此 GitHub 问题。
分布式内存缓存
分布式内存缓存 (AddDistributedMemoryCache) 是框架提供的 IDistributedCache 实现,用于将项存储在内存中。 分布式内存缓存不是真正的分布式缓存。 缓存项由应用实例存储在运行该应用的服务器上。
分布式内存缓存是一个有用的实现:
- 在开发和测试场景中。
- 当在生产环境中使用单个服务器并且内存消耗不重要时。 实现分布式内存缓存会抽象缓存的数据存储。 如果需要多个节点或容错,它允许在未来实现真正的分布式缓存解决方案。
当应用在 Program.cs
的开发环境中运行时,示例应用使用分布式内存缓存:
builder.Services.AddDistributedMemoryCache();
分布式 SQL Server 缓存
分布式 SQL Server 缓存实现 (AddDistributedSqlServerCache) 允许分布式缓存使用 SQL Server 数据库作为其后备存储。 要在 SQL Server 实例中创建 SQL Server 缓存项表,可以使用 sql-cache
工具。 该工具使用指定的名称和架构来创建表。
通过运行 sql-cache create
命令在 SQL Server 中创建一个表。 提供 SQL Server 实例 (Data Source
)、数据库 (Initial Catalog
)、架构(例如 dbo
)和表名(例如 TestCache
):
dotnet sql-cache create "Data Source=(localdb)/MSSQLLocalDB;Initial Catalog=DistCache;Integrated Security=True;" dbo TestCache
将记录一条消息以指示该工具已成功:
Table and index were created successfully.
通过 sql-cache
工具创建的表具有以下架构:
注意
应用应使用 IDistributedCache 实例(而不是 SqlServerCache)来处理缓存值。
示例应用在 Program.cs
的非开发环境中实现 SqlServerCache:
builder.Services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = builder.Configuration.GetConnectionString(
"DistCache_ConnectionString");
options.SchemaName = "dbo";
options.TableName = "TestCache";
});
说明
ConnectionString(以及可选的 SchemaName 和 TableName)通常存储在源代码管理外部(例如,由机密管理器存储或存储在 appsettings.json
/appsettings.{Environment}.json
文件中)。 连接字符串可能包含应保留在源代码管理系统外部的凭据。
分布式 NCache 缓存
NCache 是在 .NET 和 .NET Core 中以原生方式开发的开放源代码内存中分布式缓存。 NCache 既可以在本地工作,也可配置为在 Azure 或其他托管平台上运行的 ASP.NET Core 应用的分布式缓存群集。
要在本地计算机上安装和配置 NCache,请参阅Windows 入门指南(.NET 和 .NET Core)。
若要配置 NCache,请执行以下操作:
- 安装 NCache 开放源代码 NuGet。
- 在 client.ncconf 中配置缓存群集。
- 将下列代码添加到
Program.cs
:
builder.Services.AddNCacheDistributedCache(configuration =>
{
configuration.CacheName = "democache";
configuration.EnableLogs = true;
configuration.ExceptionsEnabled = true;
});
使用分布式缓存
要使用 IDistributedCache 接口,请在应用中请求 IDistributedCache 实例。 该实例由依赖项注入 (DI) 提供。
当示例应用启动时,会将 IDistributedCache 注入到 Program.cs
。 当前时间是使用 IHostApplicationLifetime 缓存的(有关详细信息,请参阅通用主机:IHostApplicationLifetime):
app.Lifetime.ApplicationStarted.Register(() =>
{
var currentTimeUTC = DateTime.UtcNow.ToString();
byte[] encodedCurrentTimeUTC = System.Text.Encoding.UTF8.GetBytes(currentTimeUTC);
var options = new DistributedCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(20));
app.Services.GetService<IDistributedCache>()
.Set("cachedTimeUTC", encodedCurrentTimeUTC, options);
});
示例应用将 IDistributedCache 注入 IndexModel
,以供索引页面使用。
每次加载索引页面时,都会检查缓存中 OnGetAsync
中的缓存时间。 如果缓存时间尚未过期,则会显示该时间。 如果自上次访问缓存时间(上次加载此页面)以来已过去 20 秒,则页面显示“缓存时间已过期”。
选择“重置缓存时间”按钮,即可将缓存时间更新为当前时间。 该按钮将触发 OnPostResetCachedTime
处理程序方法。
public class IndexModel : PageModel
{
private readonly IDistributedCache _cache;
public IndexModel(IDistributedCache cache)
{
_cache = cache;
}
public string? CachedTimeUTC { get; set; }
public string? ASP_Environment { get; set; }
public async Task OnGetAsync()
{
CachedTimeUTC = "Cached Time Expired";
var encodedCachedTimeUTC = await _cache.GetAsync("cachedTimeUTC");
if (encodedCachedTimeUTC != null)
{
CachedTimeUTC = Encoding.UTF8.GetString(encodedCachedTimeUTC);
}
ASP_Environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
if (String.IsNullOrEmpty(ASP_Environment))
{
ASP_Environment = "Null, so Production";
}
}
public async Task<IActionResult> OnPostResetCachedTime()
{
var currentTimeUTC = DateTime.UtcNow.ToString();
byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC);
var options = new DistributedCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(20));
await _cache.SetAsync("cachedTimeUTC", encodedCurrentTimeUTC, options);
return RedirectToPage();
}
}
对于具有内置实现的 IDistributedCache 实例,无需使用单一实例或范围内的生存期。
也可按需创建 IDistributedCache 实例,而不是使用 DI,但在代码中创建实例会使代码更难测试并且违反了显式依赖项原则。
建议
在确定适合你的应用的最佳 IDistributedCache 实现时,请考虑以下几点:
- 现有基础结构
- 性能要求
- 成本
- 团队经验
缓存解决方案通常依靠内存中存储来提供对缓存数据的快速检索,但内存是一种有限的资源并且扩展成本很高。 仅将常用数据存储在缓存中。
对于大多数应用来说,与 SQL Server 缓存相比,Redis 缓存可提供更高的吞吐量和更低的延迟。 但建议进行基准测试来确定缓存策略的性能特征。
当将 SQL Server 用作分布式缓存后备存储时,如果将同一数据库用于缓存以及应用的普通数据存储和检索,这可能会对两者的性能产生负面影响。 建议对分布式缓存后备存储使用专用的 SQL Server 实例。
其他资源
// ms.sfi.ropc: t
分布式缓存是由多个应用服务器共享的缓存,通常作为访问它的应用服务器的外部服务进行维护。 分布式缓存可以提高 ASP.NET Core 应用的性能和可伸缩性,尤其是当应用由云服务或服务器场托管时。
与其他将缓存数据存储在单个应用服务器上的缓存方案相比,分布式缓存具有多个优势。
当分发缓存数据时,数据:
- 在多个服务器的请求之间保持一致(一致性)。
- 在进行服务器重启和应用部署后仍然有效。
- 不使用本地内存。
分布式缓存配置是特定于实现的。 本文介绍如何配置 SQL Server 和 Redis 分布式缓存。 还提供第三方实现,例如 NCache(GitHub 上的 NCache)。 无论选择哪种实现,应用都将使用 IDistributedCache 接口与缓存进行交互。
先决条件
若要使用 SQL Server 分布式缓存,请添加对 Microsoft.Extensions.Caching.SqlServer 包的包引用。
若要使用 Redis 分布式缓存,请添加对 Microsoft.Extensions.Caching.StackExchangeRedis 包的包引用。
若要使用 NCache 分布式缓存,请添加对 NCache.Microsoft.Extensions.Caching.OpenSource 包的包引用。
IDistributedCache 接口
IDistributedCache 接口提供以下方法来处理分布式缓存实现中的项:
- Get、GetAsync:如果在缓存中找到,则接受字符串键并以
byte[]
数组的形式检索缓存项。 - Set、SetAsync:使用字符串键将项(作为
byte[]
数组)添加到缓存。 - Refresh、RefreshAsync:根据键刷新缓存中的项,重置其可调到期超时(如果有)。
- Remove、RemoveAsync:根据字符串键删除缓存项。
建立分布式缓存服务
在 Startup.ConfigureServices
中注册 IDistributedCache 实现。 本主题中所介绍的框架提供的实现包括:
分布式内存缓存
分布式内存缓存 (AddDistributedMemoryCache) 是框架提供的 IDistributedCache 实现,用于将项存储在内存中。 分布式内存缓存不是真正的分布式缓存。 缓存项由应用实例存储在运行该应用的服务器上。
分布式内存缓存是一个有用的实现:
- 在开发和测试场景中。
- 当在生产环境中使用单个服务器并且内存消耗不重要时。 实现分布式内存缓存会抽象缓存的数据存储。 如果需要多个节点或容错,它允许在未来实现真正的分布式缓存解决方案。
当应用在 Startup.ConfigureServices
的开发环境中运行时,示例应用使用分布式内存缓存:
services.AddDistributedMemoryCache();
分布式 SQL Server 缓存
分布式 SQL Server 缓存实现 (AddDistributedSqlServerCache) 允许分布式缓存使用 SQL Server 数据库作为其后备存储。 要在 SQL Server 实例中创建 SQL Server 缓存项表,可以使用 sql-cache
工具。 该工具使用指定的名称和架构来创建表。
通过运行 sql-cache create
命令在 SQL Server 中创建一个表。 提供 SQL Server 实例 (Data Source
)、数据库 (Initial Catalog
)、架构(例如 dbo
)和表名(例如 TestCache
):
dotnet sql-cache create "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=DistCache;Integrated Security=True;" dbo TestCache
将记录一条消息以指示该工具已成功:
Table and index were created successfully.
通过 sql-cache
工具创建的表具有以下架构:
注意
应用应使用 IDistributedCache 实例(而不是 SqlServerCache)来处理缓存值。
示例应用在 Startup.ConfigureServices
的非开发环境中实现 SqlServerCache:
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString =
_config["DistCache_ConnectionString"];
options.SchemaName = "dbo";
options.TableName = "TestCache";
});
说明
ConnectionString(以及可选的 SchemaName 和 TableName)通常存储在源代码管理外部(例如,由机密管理器存储或存储在 appsettings.json
/appsettings.{Environment}.json
文件中)。 连接字符串可能包含应保留在源代码管理系统外部的凭据。
分布式 Redis 缓存
Redis 是一种开放源代码内存中数据存储,通常用作分布式缓存。 可以为 Azure 托管的 ASP.NET Core 应用配置 Azure Redis 缓存,并使用 Azure Redis 缓存进行本地开发。
应用使用 RedisCache 实例 (AddStackExchangeRedisCache) 来配置缓存实现。
- 创建 Azure Cache for Redis。
- 将主连接字符串 (StackExchange.Redis) 复制到配置。
- 本地开发:使用机密管理器保存连接字符串。
- Azure:将连接字符串保存在安全存储中,例如 Azure 密钥保管库
以下代码启用 Azure Cache for Redis:
public void ConfigureServices(IServiceCollection services)
{
if (_hostContext.IsDevelopment())
{
services.AddDistributedMemoryCache();
}
else
{
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = _config["MyRedisConStr"];
options.InstanceName = "SampleInstance";
});
}
services.AddRazorPages();
}
上述代码假定主连接字符串 (StackExchange.Redis) 以键名 MyRedisConStr
保存在配置中。
有关详细信息,请参阅 Azure Cache for Redis。
有关本地 Redis 缓存的替代方法的讨论,请参阅此 GitHub 问题。
分布式 NCache 缓存
NCache 是在 .NET 和 .NET Core 中以原生方式开发的开放源代码内存中分布式缓存。 NCache 既可以在本地工作,也可配置为在 Azure 或其他托管平台上运行的 ASP.NET Core 应用的分布式缓存群集。
要在本地计算机上安装和配置 NCache,请参阅Windows 入门指南(.NET 和 .NET Core)。
若要配置 NCache,请执行以下操作:
在 client.ncconf 中配置缓存群集。
将下列代码添加到
Startup.ConfigureServices
:services.AddNCacheDistributedCache(configuration => { configuration.CacheName = "demoClusteredCache"; configuration.EnableLogs = true; configuration.ExceptionsEnabled = true; });
使用分布式缓存
要使用 IDistributedCache 接口,请从应用中的任何构造函数请求 IDistributedCache 实例。 该实例由依赖项注入 (DI) 提供。
当示例应用启动时,会将 IDistributedCache 注入到 Startup.Configure
。 当前时间是使用 IHostApplicationLifetime 缓存的(有关详细信息,请参阅通用主机:IHostApplicationLifetime):
public void Configure(IApplicationBuilder app, IWebHostEnvironment env,
IHostApplicationLifetime lifetime, IDistributedCache cache)
{
lifetime.ApplicationStarted.Register(() =>
{
var currentTimeUTC = DateTime.UtcNow.ToString();
byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC);
var options = new DistributedCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(20));
cache.Set("cachedTimeUTC", encodedCurrentTimeUTC, options);
});
示例应用将 IDistributedCache 注入 IndexModel
,以供索引页面使用。
每次加载索引页面时,都会检查缓存中 OnGetAsync
中的缓存时间。 如果缓存时间尚未过期,则会显示该时间。 如果自上次访问缓存时间(上次加载此页面)以来已过去 20 秒,则页面显示“缓存时间已过期”。
选择“重置缓存时间”按钮,即可将缓存时间更新为当前时间。 该按钮将触发 OnPostResetCachedTime
处理程序方法。
public class IndexModel : PageModel
{
private readonly IDistributedCache _cache;
public IndexModel(IDistributedCache cache)
{
_cache = cache;
}
public string CachedTimeUTC { get; set; }
public async Task OnGetAsync()
{
CachedTimeUTC = "Cached Time Expired";
var encodedCachedTimeUTC = await _cache.GetAsync("cachedTimeUTC");
if (encodedCachedTimeUTC != null)
{
CachedTimeUTC = Encoding.UTF8.GetString(encodedCachedTimeUTC);
}
}
public async Task<IActionResult> OnPostResetCachedTime()
{
var currentTimeUTC = DateTime.UtcNow.ToString();
byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC);
var options = new DistributedCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(20));
await _cache.SetAsync("cachedTimeUTC", encodedCurrentTimeUTC, options);
return RedirectToPage();
}
}
说明
IDistributedCache 实例无需使用单一实例或范围内的生存期(至少对于内置实现而言)。
也可按需创建 IDistributedCache 实例,而不是使用 DI,但在代码中创建实例会使代码更难测试并且违反了显式依赖项原则。
建议
在确定适合你的应用的最佳 IDistributedCache 实现时,请考虑以下几点:
- 现有基础结构
- 性能要求
- 成本
- 团队经验
缓存解决方案通常依靠内存中存储来提供对缓存数据的快速检索,但内存是一种有限的资源并且扩展成本很高。 仅将常用数据存储在缓存中。
通常,Redis 缓存比 SQL Server 缓存提供更高的吞吐量和更低的延迟。 但是,通常需要进行基准测试才能确定缓存策略的性能特征。
当将 SQL Server 用作分布式缓存后备存储时,如果将同一数据库用于缓存以及应用的普通数据存储和检索,这可能会对两者的性能产生负面影响。 建议对分布式缓存后备存储使用专用的 SQL Server 实例。