我有一个与音乐相关的ASP.NET网站,可以在第一次请求时从数据库中缓存大量静态信息。
有时,重置应用程序并在应用程序负载繁重时清除缓存,然后所有http请求都会转到数据库以检索静态数据并将其缓存以用于其他请求。
如何确保只有一个请求进入数据库并缓存结果,以便其他请求只是从缓存中读取该信息,而不是一遍又一遍地不必要地检索相同的信息。
我可以使用线程锁定吗?例如,我可以执行锁定(此){db access here} 吗?
答案 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个相同的请求,因此我们确实需要群集范围的锁定。