队列访问数据库以避免多个缓存项

时间:2010-06-07 12:39:25

标签: asp.net multithreading sql-server-2008

我有一个与音乐相关的ASP.NET网站,可以在第一次请求时从数据库中缓存大量静态信息。

有时,重置应用程序并在应用程序负载繁重时清除缓存,然后所有http请求都会转到数据库以检索静态数据并将其缓存以用于其他请求。

如何确保只有一个请求进入数据库并缓存结果,以便其他请求只是从缓存中读取该信息,而不是一遍又一遍地不必要地检索相同的信息。

我可以使用线程锁定吗?例如,我可以执行锁定(此){db access here} 吗?

2 个答案:

答案 0 :(得分:3)

是的,在您的缓存代码中,您需要将数据库访问代码放在lock块中。但是,请勿锁定this。通常你会做类似

的事情
private static readonly object staticObjectToLockOn = new object();

...

if (cache[cacheKey] == null)
{
   lock(staticObjectToLockOn)
   {
      // double-check the cache is still null inside the lock
      if (cache[cacheKey] == null)
      {
         // get data from the database, add to cache
      }
   }
}

答案 1 :(得分:1)

关键是使用通用锁,你会遇到很多用户的严重问题,因为当你的应用启动时,每个缓存项都可以阻止线程。此外,每个线程仍会创建自己的锁和查询(并且每个线程有10台机器和32个线程,这是320个请求!)

我们采用这样的方法(每天10万次网页浏览量和memcached):

当从数据库中获取数据时,我们在类似的缓存键中存储“进行中”消息(例如,将in-progress添加到缓存键或其他内容)。当另一个线程找不到当前项时,它将检查进行中的键。如果项目正在进行中,请等待几毫秒。并尝试再次获取。如果在几分钟后(500毫秒?)再次从当前线程执行数据库操作,以防止在项目处于“进行中”时杀死应用程序。

通过这种方式,你可以创建某种锁,但是可以通过多台机器等来创建。

如果不这样做,我们的CMS服务器将在第一秒内获得200个相同的请求,因此我们确实需要群集范围的锁定。