【问题标题】:Queue access to the database to avoid multiple cache items对数据库进行队列访问,避免多个缓存项
【发布时间】:2010-06-07 21:58:00
【问题描述】:

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

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

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

我可以使用线程锁定吗?例如,我可以执行 lock(this) { db access here } 之类的操作吗?

【问题讨论】:

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


    【解决方案1】:

    是的,在您的缓存代码中,您需要将访问数据库的代码放在 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
          }
       }
    }
    

    【讨论】:

    • 谢谢,但是你能解释一下什么是“staticObjectToLockOn”吗?
    • @MikeJ:你想提供一个类的所有实例都可以访问的变量,即一个静态对象。有关更多信息,请参阅 MSDN 文档 - msdn.microsoft.com/en-us/library/c5kehkcz(VS.10).aspx
    • 格雷厄姆,谢谢,现在很清楚,接受了。但是,我想知道,还有其他想法吗?
    • 是的,正如 Jan Jongboom 所说,这种方法可能无法扩展,特别是如果您有多个服务器(一个网络农场),并且您希望同时有许多请求。对于这些场景,您可能需要查看分布式缓存解决方案。
    • 嗯,那我不太确定这个锁有什么帮助?我认为这段代码会保护同一进程中其他线程的数据库访问?那个静态变量不是跨线程共享的吗?我的意思是,如果我在同一毫秒内收到 10 个请求,那么第一个请求不会阻塞同一进程中的其他 9 个请求吗?
    【解决方案2】:

    重点在于使用通用锁,因为当您的应用程序启动时,线程可能会因每个缓存项而被阻塞,所以您会遇到很多用户的严重问题。此外,每个线程仍会创建自己的锁和查询(每台机器有 10 台机器和 32 个线程,即 320 个请求!)

    我们采用这样的方法(> 10 mio 网页浏览/天,并且使用 memcached):

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

    通过这种方式,您可以创建某种锁,但可以在多台机器上等。

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

    【讨论】:

    • 不确定您要如何等待? Thread.Sleep() 在 while 循环中?这不是也很危险,可能会挂起进程/线程吗?
    • 啊,现在我明白了……我将只锁定当前线程,但我可能会在机器上拥有 32 个线程,所以我仍然会在每台机器上发出至少 32 个 db 请求?我可以以某种方式检查我的应用程序正在使用多少线程吗?谢谢你的警告,好点
    • 不,因为你放了一个集中锁。 Graham 的解决方案只锁定当前线程;如果完全加载,则生成 32 个(取决于机器)数据库操作。通过将锁放入您的缓存系统,您可以避免这种情况。 thread.sleep() 是为了确保您 执行 32 个请求。顺便说一句,您可以进行进程转储以获取线程数以及它们在做什么,但不知道如何。我们有创建这些的应用程序管理团队:-)
    • @Jan Jongboom:我认为锁定静态变量会影响整个应用程序域,而不仅仅是单个线程。因此,对于单个 Web 服务器,所有请求都将有效地访问同一个变量。
    • 是的,抱歉,我现在看到您正在使用 static 变量进行锁定。在这种情况下,整个域访问相同的变量。
    猜你喜欢
    • 2011-01-05
    • 1970-01-01
    • 2017-07-10
    • 2020-10-09
    • 1970-01-01
    • 1970-01-01
    • 2011-05-24
    • 2020-03-27
    • 2021-07-12
    相关资源
    最近更新 更多