Mvc 应用缓存
Mvc Application Cache
如何使用存储库模式为我的应用程序构建数据缓存?
使用锁定对象并为每个会话保留...
public sealed class NewsCache
{
List<int> _tagsIds = null;
static NewsCache _instance = new NewsCache();
private static readonly object LockObject = new object();
private readonly NewsManager _newsManager = new NewsManager();
public static NewsCache Instance
{
get
{
lock (LockObject)
{
if (_instance == null)
{
_instance = new NewsCache();
}
return _instance;
}
}
}
private NewsCache()
{
}
}
在缓存管理器中,您必须封装缓存运算符,并且必须确保您的缓存作为中央缓存运行。
您不需要句柄缓存的存储库模式。
按需将数据从数据存储加载到缓存中。这种模式可以提高性能,还有助于保持缓存中保存的数据与底层数据存储中的数据之间的一致性。
背景和问题
应用程序使用缓存来优化对数据存储中保存的信息的重复访问。但是,期望缓存数据始终与数据存储中的数据完全一致通常是不切实际的。应用程序应实施一种策略,以帮助确保缓存中的数据尽可能保持最新,但也可以检测和处理缓存中的数据变得陈旧时出现的情况。
解决方案
许多商业缓存系统提供通读和write-through/write-behind操作。在这些系统中,应用程序通过引用缓存来检索数据。如果数据不在缓存中,它会透明地从数据存储中检索并添加到缓存中。对缓存中保存的数据的任何修改也会自动写回到数据存储中。
对于不提供此功能的缓存,使用缓存的应用程序负责维护缓存中的数据。
应用程序可以通过实施缓存端策略来模拟直读缓存的功能。该策略有效地将数据按需加载到缓存中。
如果应用程序更新信息,它可以模拟如下的直写策略:
对数据存储进行修改
使缓存中的相应项无效。
当下次需要该项目时,使用缓存端策略将导致从数据存储中检索更新的数据并将其添加回缓存中。
问题和注意事项
在决定如何实施此模式时,请考虑以下几点:
**- **缓存数据的生命周期****
。许多缓存实施过期策略,如果在指定时间段内未访问数据,该策略会导致数据失效并从缓存中删除。要使缓存区有效,请确保过期策略与使用数据的应用程序的访问模式相匹配。不要将过期时间设置得太短,因为这会导致应用程序不断从数据存储中检索数据并将其添加到缓存中。同样,不要将过期时间设置得太长,以免缓存的数据变得陈旧。请记住,缓存对于相对静态的数据或经常读取的数据最有效。
**- **逐出数据。****
与数据来源的数据存储相比,大多数缓存的大小有限,必要时它们会逐出数据。大多数缓存采用最近最少使用的策略来选择要驱逐的项目,但这可能是可定制的。配置缓存的全局过期 属性 和其他属性,以及每个缓存项的过期 属性,以帮助确保缓存具有成本效益。将全局逐出策略应用于缓存中的每个项目可能并不总是合适的。例如,如果从数据存储中检索缓存项目的成本非常高,则将此项目保留在缓存中可能会有好处,但代价是访问更频繁但成本更低的项目。
**
- 启动缓存
**。许多解决方案使用应用程序在启动处理过程中可能需要的数据预先填充缓存。如果其中一些数据过期或被逐出,Cache-Aside 模式可能仍然有用。
**
- 一致性。
** 实施 Cache-Aside 模式并不能保证数据存储和缓存之间的一致性。数据存储中的项目可能随时被外部进程更改,并且在下一次将项目加载到缓存中之前,此更改可能不会反映在缓存中。在跨数据存储复制数据的系统中,如果同步发生非常频繁,则此问题可能会变得尤为严重。
**
- 本地(内存中)缓存。
** 缓存可以是应用程序实例的本地缓存,并存储在内存中。如果应用程序重复访问相同的数据,则缓存区在此环境中很有用。但是,本地缓存是私有的,因此不同的应用程序实例可以各自拥有相同缓存数据的副本。此数据可能会在缓存之间很快变得不一致,因此可能有必要使私有缓存中保存的数据过期并更频繁地刷新它。在这些情况下,研究共享或分布式缓存机制的使用可能是合适的。
示例:
...
public async Task<MyEntity> GetMyEntityAsync(int id)
{
// Define a unique key for this method and its parameters.
var key = string.Format("StoreWithCache_GetAsync_{0}", id);
var expiration = TimeSpan.FromMinutes(3);
bool cacheException = false;
try
{
// Try to get the entity from the cache.
var cacheItem = cache.GetCacheItem(key);
if (cacheItem != null)
{
return cacheItem.Value as MyEntity;
}
}
catch (DataCacheException)
{
// If there is a cache related issue, raise an exception
// and avoid using the cache for the rest of the call.
cacheException = true;
}
// If there is a cache miss, get the entity from the original store and cache it.
// Code has been omitted because it is data store dependent.
var entity = ...;
if (!cacheException)
{
try
{
// Avoid caching a null value.
if (entity != null)
{
// Put the item in the cache with a custom expiration time that
// depends on how critical it might be to have stale data.
cache.Put(key, entity, timeout: expiration);
}
}
catch (DataCacheException)
{
// If there is a cache related issue, ignore it
// and just return the entity.
}
}
return entity;
}
如何使用存储库模式为我的应用程序构建数据缓存? 使用锁定对象并为每个会话保留...
public sealed class NewsCache
{
List<int> _tagsIds = null;
static NewsCache _instance = new NewsCache();
private static readonly object LockObject = new object();
private readonly NewsManager _newsManager = new NewsManager();
public static NewsCache Instance
{
get
{
lock (LockObject)
{
if (_instance == null)
{
_instance = new NewsCache();
}
return _instance;
}
}
}
private NewsCache()
{
}
}
在缓存管理器中,您必须封装缓存运算符,并且必须确保您的缓存作为中央缓存运行。 您不需要句柄缓存的存储库模式。
按需将数据从数据存储加载到缓存中。这种模式可以提高性能,还有助于保持缓存中保存的数据与底层数据存储中的数据之间的一致性。
背景和问题
应用程序使用缓存来优化对数据存储中保存的信息的重复访问。但是,期望缓存数据始终与数据存储中的数据完全一致通常是不切实际的。应用程序应实施一种策略,以帮助确保缓存中的数据尽可能保持最新,但也可以检测和处理缓存中的数据变得陈旧时出现的情况。
解决方案
许多商业缓存系统提供通读和write-through/write-behind操作。在这些系统中,应用程序通过引用缓存来检索数据。如果数据不在缓存中,它会透明地从数据存储中检索并添加到缓存中。对缓存中保存的数据的任何修改也会自动写回到数据存储中。 对于不提供此功能的缓存,使用缓存的应用程序负责维护缓存中的数据。 应用程序可以通过实施缓存端策略来模拟直读缓存的功能。该策略有效地将数据按需加载到缓存中。
如果应用程序更新信息,它可以模拟如下的直写策略: 对数据存储进行修改 使缓存中的相应项无效。 当下次需要该项目时,使用缓存端策略将导致从数据存储中检索更新的数据并将其添加回缓存中。
问题和注意事项 在决定如何实施此模式时,请考虑以下几点:
**- **缓存数据的生命周期****
。许多缓存实施过期策略,如果在指定时间段内未访问数据,该策略会导致数据失效并从缓存中删除。要使缓存区有效,请确保过期策略与使用数据的应用程序的访问模式相匹配。不要将过期时间设置得太短,因为这会导致应用程序不断从数据存储中检索数据并将其添加到缓存中。同样,不要将过期时间设置得太长,以免缓存的数据变得陈旧。请记住,缓存对于相对静态的数据或经常读取的数据最有效。
**- **逐出数据。****
与数据来源的数据存储相比,大多数缓存的大小有限,必要时它们会逐出数据。大多数缓存采用最近最少使用的策略来选择要驱逐的项目,但这可能是可定制的。配置缓存的全局过期 属性 和其他属性,以及每个缓存项的过期 属性,以帮助确保缓存具有成本效益。将全局逐出策略应用于缓存中的每个项目可能并不总是合适的。例如,如果从数据存储中检索缓存项目的成本非常高,则将此项目保留在缓存中可能会有好处,但代价是访问更频繁但成本更低的项目。 **
- 启动缓存
**。许多解决方案使用应用程序在启动处理过程中可能需要的数据预先填充缓存。如果其中一些数据过期或被逐出,Cache-Aside 模式可能仍然有用。 **
- 一致性。
** 实施 Cache-Aside 模式并不能保证数据存储和缓存之间的一致性。数据存储中的项目可能随时被外部进程更改,并且在下一次将项目加载到缓存中之前,此更改可能不会反映在缓存中。在跨数据存储复制数据的系统中,如果同步发生非常频繁,则此问题可能会变得尤为严重。 **
- 本地(内存中)缓存。
** 缓存可以是应用程序实例的本地缓存,并存储在内存中。如果应用程序重复访问相同的数据,则缓存区在此环境中很有用。但是,本地缓存是私有的,因此不同的应用程序实例可以各自拥有相同缓存数据的副本。此数据可能会在缓存之间很快变得不一致,因此可能有必要使私有缓存中保存的数据过期并更频繁地刷新它。在这些情况下,研究共享或分布式缓存机制的使用可能是合适的。
示例:
...
public async Task<MyEntity> GetMyEntityAsync(int id)
{
// Define a unique key for this method and its parameters.
var key = string.Format("StoreWithCache_GetAsync_{0}", id);
var expiration = TimeSpan.FromMinutes(3);
bool cacheException = false;
try
{
// Try to get the entity from the cache.
var cacheItem = cache.GetCacheItem(key);
if (cacheItem != null)
{
return cacheItem.Value as MyEntity;
}
}
catch (DataCacheException)
{
// If there is a cache related issue, raise an exception
// and avoid using the cache for the rest of the call.
cacheException = true;
}
// If there is a cache miss, get the entity from the original store and cache it.
// Code has been omitted because it is data store dependent.
var entity = ...;
if (!cacheException)
{
try
{
// Avoid caching a null value.
if (entity != null)
{
// Put the item in the cache with a custom expiration time that
// depends on how critical it might be to have stale data.
cache.Put(key, entity, timeout: expiration);
}
}
catch (DataCacheException)
{
// If there is a cache related issue, ignore it
// and just return the entity.
}
}
return entity;
}