如何使用缓存模式避免数据库查询风暴

时间:2011-03-10 11:06:52

标签: caching appfabric

我们正在使用PostgreSQL数据库和AppFabric Server,运行一个中等繁忙的ASP.NET MVC电子商务网站。

遵循缓存模式,我们从缓存中请求数据,如果它不可用,我们会查询数据库。

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

此问题的一个解决方案是在缓存上使用读锁定。但是,这可能会导致Web场情况(甚至是单个繁忙的Web服务器)出现性能问题,因为如果发生数据库查询,Web服务器会无理由地阻止读取。

另一个解决方案是删除缓存模式并独立播种缓存。这是我们采取的减轻我们在这个问题上遇到的直接问题的方法,但是对于所有数据都不可能。

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

2 个答案:

答案 0 :(得分: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注入了正确的缓存堆栈。这使得实际缓存行为保持灵活,集中且易于维护,尽管相当复杂。

答案 1 :(得分:0)

我们已经成功使用了AppFabric上面提到的播种策略。我们实际上确实使用了两种解决方案:

  1. 在可能的情况下播种已知数据(我们设置有限,因此我们很容易弄明白)
  2. 在每个缓存访问方法中,请确保根据需要进行后备,并在从数据存储中检索时填充缓存。
  3. 备用是必要的,因为物品可能因记忆压力而被驱逐,或仅仅因为它们在播种操作中被遗漏。我们有一个“加温”服务,它以一个间隔(一小时)发出脉冲并保持缓存中填充必要的数据。我们会对缓存未命中情况进行分析,如果我们在变暖区间看到频繁的未命中,则使用它来调整我们的变暖策略。