I'm having some trouble getting my cache to work the way I want.
我在使缓存按照我想要的方式工作时遇到了一些麻烦。
The problem: The process of retrieving the requested data is very time consuming. If using standard ASP.NET caching some users will take the "hit" of retrieving the data. This is not acceptable.
问题:检索所请求数据的过程非常耗时。如果使用标准的ASP.NET缓存,一些用户将会“检索”检索数据。这是不可接受的。
The solution?: It is not super important that the data is 100% current. I would like to serve old invalidated data while updating the cached data in another thread making the new data available for future requests. I reckon that the data needs to be persisted in some way in order to be able to serve the first user after application restart without that user taking the "hit".
解决方案?:数据100%当前并不是非常重要。我希望在更新另一个线程中的缓存数据时提供旧的无效数据,使新数据可用于将来的请求。我认为数据需要以某种方式持久化,以便能够在应用程序重新启动后为第一个用户提供服务,而不会让用户“点击”。
I've made a solution which does somewhat of the above, but I'm wondering if there is a "best practice" way or of there is a caching framework out there already supporting this behaviour?
我已经提出了一个解决方案,它可以解决上述问题,但我想知道是否存在“最佳实践”方式,或者是否存在支持此行为的缓存框架?
6 个解决方案
#1
There are tools that do this, for example Microsofts ISA Server (may be a bit expensive / overkill).
有一些工具可以做到这一点,例如微软ISA服务器(可能有点贵/过度杀伤)。
You can cache it in memory using Enterprise Libary Caching. Let your users read from Cache, and have other pages that update the Cache, these other pages should be called as regularly as you need to keep the data upto date.
您可以使用Enterprise Libary Caching将其缓存在内存中。让您的用户从缓存读取,并有其他页面更新缓存,这些其他页面应该定期调用,以保持数据最新。
#2
You could listen when the Cached Item is Removed and Process then,
您可以在删除缓存项目时进行监听,然后处理
public void RemovedCallback(String k, Object v, CacheItemRemovedReason r)
{
// Put Item Back IN Cache, ( so others can use it until u have finished grabbing the new data)
// Spawn Thread to Go Get Up To Date Data
// Over right Old data with new return...
}
in global asax
在全球的asax
protected void Application_Start(object sender, EventArgs e)
{
// Spawn worker thread to pre-load critical data
}
Ohh...I have no idea if this is best practice, i just thought it would be slick~ Good Luck~
哦......我不知道这是不是最好的做法,我只是觉得它很光滑〜祝你好运〜
#3
I created my own solution with a Dictionary/Hashtable in memory as a duplicate of the actual cache. When a method call came in requesting the object from cache and it wasn't there but was present in memory, the memory stored object was returned and fired a new thread to update the object in both memory and the cache using a delegate method.
我创建了自己的解决方案,在内存中使用Dictionary / Hashtable作为实际缓存的副本。当一个方法调用从缓存中请求对象并且它不存在但存在于内存中时,返回了内存存储对象并触发了一个新线程,以使用委托方法更新内存和缓存中的对象。
#4
You can do this pretty easily with the Cache
and Timer
classes built into .NET. The Timer runs on a separate thread.
您可以使用.NET内置的Cache和Timer类轻松地完成此操作。 Timer在单独的线程上运行。
And I actually wrote a very small wrapper library called WebCacheHelper which exposes this functionality in an overloaded constructor. The library also serves as a strongly typed wrapper around the Cache
object.
我实际上编写了一个名为WebCacheHelper的非常小的包装器库,它在重载的构造函数中公开了这个功能。该库还充当Cache对象周围的强类型包装器。
Here's an example of how you could do this...
这是一个如何做到这一点的例子......
public readonly static WebCacheHelper.Cache<int> RegisteredUsersCount =
new WebCacheHelper.Cache<int>(new TimeSpan(0, 5, 0), () => GetRegisteredUsersCount());
This has a lazy loading aspect to it where GetRegisteredUsersCount()
will be executed on the calling thread the instant that RegisteredUsersCount
is first accessed. However, after that it's executed every 5 minutes on a background thread. This means that the only user who will be penalized with a slow wait time will be the very first user.
这有一个延迟加载方面,其中GetRegisteredUsersCount()将在调用线程上首次访问RegisteredUsersCount时执行。但是,之后它在后台线程上每5分钟执行一次。这意味着唯一将在等待时间较短的情况下受到惩罚的用户将是第一个用户。
Then getting the value is as simple as referencing RegisteredUsersCount.Value
.
然后获取值就像引用RegisteredUsersCount.Value一样简单。
#5
Yeah you could just cache the most frequently accessed data when your app starts but that still means the first user to trigger that would "take the hit" as you say (assuming inproc cache of course).
是的,您可以在应用程序启动时缓存最常访问的数据,但这仍然意味着第一个触发的用户将按照您的说法“接受命中”(当然假设是inproc缓存)。
#6
What I do in this situation is using a CacheTable in db to cache the latest data, and running a background job (with a windows service. in a shared environment you can use threads also) that refreshes the data on the table.
我在这种情况下所做的是在db中使用CacheTable来缓存最新数据,并运行后台作业(在共享环境中使用Windows服务,也可以使用线程)刷新表中的数据。
There is a very little posibility to show user a blank screen. I eliminate this by also caching via asp.net cache for 1 minute.
向用户显示空白屏幕的可能性很小。我通过asp.net缓存缓存1分钟来消除这种情况。
Don't know if it's a bad design, but it's working great without a problem on a highly used web site.
不知道它是不是一个糟糕的设计,但它在高度使用的网站上没有问题的情况下运行良好。
#1
There are tools that do this, for example Microsofts ISA Server (may be a bit expensive / overkill).
有一些工具可以做到这一点,例如微软ISA服务器(可能有点贵/过度杀伤)。
You can cache it in memory using Enterprise Libary Caching. Let your users read from Cache, and have other pages that update the Cache, these other pages should be called as regularly as you need to keep the data upto date.
您可以使用Enterprise Libary Caching将其缓存在内存中。让您的用户从缓存读取,并有其他页面更新缓存,这些其他页面应该定期调用,以保持数据最新。
#2
You could listen when the Cached Item is Removed and Process then,
您可以在删除缓存项目时进行监听,然后处理
public void RemovedCallback(String k, Object v, CacheItemRemovedReason r)
{
// Put Item Back IN Cache, ( so others can use it until u have finished grabbing the new data)
// Spawn Thread to Go Get Up To Date Data
// Over right Old data with new return...
}
in global asax
在全球的asax
protected void Application_Start(object sender, EventArgs e)
{
// Spawn worker thread to pre-load critical data
}
Ohh...I have no idea if this is best practice, i just thought it would be slick~ Good Luck~
哦......我不知道这是不是最好的做法,我只是觉得它很光滑〜祝你好运〜
#3
I created my own solution with a Dictionary/Hashtable in memory as a duplicate of the actual cache. When a method call came in requesting the object from cache and it wasn't there but was present in memory, the memory stored object was returned and fired a new thread to update the object in both memory and the cache using a delegate method.
我创建了自己的解决方案,在内存中使用Dictionary / Hashtable作为实际缓存的副本。当一个方法调用从缓存中请求对象并且它不存在但存在于内存中时,返回了内存存储对象并触发了一个新线程,以使用委托方法更新内存和缓存中的对象。
#4
You can do this pretty easily with the Cache
and Timer
classes built into .NET. The Timer runs on a separate thread.
您可以使用.NET内置的Cache和Timer类轻松地完成此操作。 Timer在单独的线程上运行。
And I actually wrote a very small wrapper library called WebCacheHelper which exposes this functionality in an overloaded constructor. The library also serves as a strongly typed wrapper around the Cache
object.
我实际上编写了一个名为WebCacheHelper的非常小的包装器库,它在重载的构造函数中公开了这个功能。该库还充当Cache对象周围的强类型包装器。
Here's an example of how you could do this...
这是一个如何做到这一点的例子......
public readonly static WebCacheHelper.Cache<int> RegisteredUsersCount =
new WebCacheHelper.Cache<int>(new TimeSpan(0, 5, 0), () => GetRegisteredUsersCount());
This has a lazy loading aspect to it where GetRegisteredUsersCount()
will be executed on the calling thread the instant that RegisteredUsersCount
is first accessed. However, after that it's executed every 5 minutes on a background thread. This means that the only user who will be penalized with a slow wait time will be the very first user.
这有一个延迟加载方面,其中GetRegisteredUsersCount()将在调用线程上首次访问RegisteredUsersCount时执行。但是,之后它在后台线程上每5分钟执行一次。这意味着唯一将在等待时间较短的情况下受到惩罚的用户将是第一个用户。
Then getting the value is as simple as referencing RegisteredUsersCount.Value
.
然后获取值就像引用RegisteredUsersCount.Value一样简单。
#5
Yeah you could just cache the most frequently accessed data when your app starts but that still means the first user to trigger that would "take the hit" as you say (assuming inproc cache of course).
是的,您可以在应用程序启动时缓存最常访问的数据,但这仍然意味着第一个触发的用户将按照您的说法“接受命中”(当然假设是inproc缓存)。
#6
What I do in this situation is using a CacheTable in db to cache the latest data, and running a background job (with a windows service. in a shared environment you can use threads also) that refreshes the data on the table.
我在这种情况下所做的是在db中使用CacheTable来缓存最新数据,并运行后台作业(在共享环境中使用Windows服务,也可以使用线程)刷新表中的数据。
There is a very little posibility to show user a blank screen. I eliminate this by also caching via asp.net cache for 1 minute.
向用户显示空白屏幕的可能性很小。我通过asp.net缓存缓存1分钟来消除这种情况。
Don't know if it's a bad design, but it's working great without a problem on a highly used web site.
不知道它是不是一个糟糕的设计,但它在高度使用的网站上没有问题的情况下运行良好。