2011-03-10 30 views
4

我们使用PostgreSQL数据库和AppFabric Server,运行一个繁忙的ASP.NET MVC电子商务网站。如何避免使用缓存存储模式的数据库查询风暴

继缓存存储模式之后,我们从缓存中请求数据,如果它不可用,我们查询数据库。

此方法导致'查询风暴',其中数据库在短时间内接收到同一数据的多个查询,而缓存中的给定对象正在刷新。这个问题由于长时间运行的查询而加剧,并且显然对相同数据的多个请求可能导致查询运行更长时间,形成令人不快的反馈循环。

解决此问题的一个办法是对缓存使用读取锁定。但是,如果发生数据库查询,则Web服务器在无故读取时被阻塞,这本身可能会导致Web场环境(甚至是单个繁忙的Web服务器)中的性能问题。

另一种解决方案是放弃缓存旁置模式并独立地对缓存进行种子处理。这是我们采取的方法来缓解我们在这个问题上看到的即时问题,但是对于所有数据来说这是不可能的。

我在这里错过了什么吗?人们采取了哪些其他方法来避免这种行为?

回答

1

根据您拥有的服务器数量和您当前的缓存体系结构,也可能需要评估添加服务器级别(或进程内)缓存。实际上,您将其用作后备缓存,在主存储(数据库)非常耗费资源或速度很慢的情况下,这尤其有用。

当我使用这个功能时,我已经使用了主缓存的缓存旁路模式和次要的旁通设计 - 次要模块被锁定并确保数据库不会过度饱和由相同的请求。通过这种体系结构,主缓存未命中每个服务器(或进程)每个实体最多只能向数据库提供一个查询。

所以基本的工作流程是:

1)尝试从主/共享缓存池

* If successful, return 
* If unsuccessul, continue 

2检索)检查进程缓存值

* If successful, return (optionally seeding primary cache) 
* If unsuccessul, continue 

3)通过缓存键获取锁定(并且在其他线程添加的情况下重新检查进程内缓存)

4)检索从初级的持久性(db对象)

5)种子过程中的高速缓存,并返回

我做这个使用注射用包装,我的缓存层都实现了相关IRepository接口,和StructureMap内喷射正确的缓存堆栈。这样可以保持实际的缓存行为灵活,重点突出,并且易于维护,尽管相当复杂。

0

我们已经成功地使用了AppFabric和上面提到的播种策略。事实上,我们确实使用了两种解决方案:如果可能的话

  1. 种已知的数据(我们有一组有限的,所以这实际上是容易让我们弄清楚)
  2. 在每个高速缓存访​​问方法,确保做一下 - 根据需要提供,并在从数据存储检索时填充缓存。

由于内存压力,或者仅仅因为在播种操作中错过了项目,因此需要进行旁观。我们有一个“升温”服务,它会在一个时间间隔(一小时)内产生脉冲,并将缓存填充必要的数据。我们会继续分析缓存未命中情况,如果我们发现在升温时间间隔期间频繁发生错失,则使用它来调整我们的升温策略。