【问题标题】:Querying objects from static List causing spikes on cpu usage on server从静态列表中查询对象导致服务器上的 CPU 使用率达到峰值
【发布时间】:2012-02-05 07:10:28
【问题描述】:

我们有一个类似于 SO 上的相关问题的功能,我们在查看给定记录时显示相关记录。每次加载页面时都通过调用数据库来检索相关记录。为了减少数据库的负载,我创建了这些记录的静态列表,我在 Application_Start 上加载这些记录,现在使用 Linq 查询来查询这个列表。

在大多数情况下,这似乎工作正常。 db 上的负载减少了,Sql profiler 显示没有更多的相关记录查询。我昨晚推动了这个改变,今天早上我发现 IIS 工作进程的 CPU 为 100%,网站没有响应。我切换回旧代码(我在其中查询 db),Web 服务器上一切正常,但 db 负载增加。所以我再次切换到新代码,并一直在查看 Web 服务器上的 cpu 负载。这是我注意到的。

当使用查询数据库的旧代码时,IIS Worker 进程的 cpu 使用率可以忽略不计,几乎没有任何变化(在任务管理器的性能选项卡中看到直线)但是,当使用创建的新代码时并查询静态列表,我看到 IIS 工作进程的 CPU 使用率出现峰值。大多数情况下,它在 1% 到 5% 之间,但时不时地会超过这个值,自从我开始观察以来,我看到的最大值是 40%。我想知道为什么会发生这种情况以及在重负载下是否会导致工作进程崩溃?

这是一些查询静态列表的代码

    if (validSearchLatLong && (usePincodeLatLong || distanceFilterLimit != distanceLimit))
        {
            filteredRecords = StaticRecords.Where(job => LatLongDistance(centerLatitude, centerLongitude, job.lat, job.lon) <= distanceFilterLimit || (!string.IsNullOrEmpty(this.PreferredJobCity) ? job.city == this.PreferredJobCity : false)).ToList();
        }
        else
        {
            filteredRecords = StaticRecords.Where(job => (this.PreferredJobCity != "" ? job.city == this.PreferredJobCity : (this.City != "" ? job.city == this.city : (state != "" ? job.state.Trim() == state.Trim() : false)))).ToList();
        }

        if (RecordsearchFilter.JobCategories.Count > 0 && RecordsearchFilter.EnableFilter)
        {
            filteredRecords = filteredRecords.Where(job => this.RecordsearchFilter.JobCategories.Contains(job.JobCategoryClass)).ToList();
        }
        else
        {
            filteredRecords = filteredRecords.Where(job => MatchJobCategories(job.JobCategory, (short)this.jobCategory.SqlId) > 0).ToList();
        }

List 支持多个并发读取器,因此 StaticRecords 不应成为阻塞因素。之后我创建了过滤记录,它是一个新的过滤列表,应该独立于其他线程。

CPU 出现峰值的可能原因是什么?是否会导致 IIS 工作进程较早崩溃?

============编辑===============

我现在知道崩溃不是由这段代码引起的,而是另一个错误。静态 List 方法一直很稳定,似乎可以很好地实现其目的。

但我的问题仍然存在,为什么 CPU 会出现峰值?

当我说

List 支持多个并发读取器,因此 StaticRecords 不应该 成为阻碍因素。之后我正在创建filteredRecords 这是一个新的过滤列表,应该独立于其他 线程。

我错了吗?

【问题讨论】:

  • 您是否打开了跟踪以查看方法调用所花费的时间?
  • 静态记录有多大?您是否在高峰期看到页面错误? StaticRecords 使用 List?
  • @rene 是的 StaticRecords 使用 List。它有大约35000条记录。如果您指的是 asp.net 页面中的错误,则通过 pagefaults,那么不,我还没有看到任何错误。
  • @sassyboy with pagefaults 我的意思是内存页错误,即操作系统中的内存管理器必须从磁盘中获取内存块。虽然是退役内容,但还是有用的:msdn.microsoft.com/en-us/library/ff647791.aspx
  • 多年后......有同样的问题。 Linq 执行速度很快,但 CPU 运行不正常

标签: c# asp.net list collections


【解决方案1】:

SQL Server 在查询方面通常非常高效,尤其是当您正确优化了索引时。

您的新 StaticRecords 方法需要对所有项目进行内存扫描,并对每个项目执行 Where 谓词。这可能是您增加 CPU 使用率的原因,尤其是当 StaticRecords 中有很多项目时。尝试附加分析器并亲自查看。一般来说,我希望这种过滤在 SQL Server 上运行时比在内存中过滤的性能要好几个数量级。

【讨论】:

  • 嗯,网络服务器上的 CPU 使用率增加是预期的,只要它保持一致(主要在 1 到 5% 之间)就可以了。我担心的是使用高峰(当它达到 40% 时)。为什么我会看到突然的峰值?至于使用 Sql server,内存中的方法是减少 Sql server 的负载。有问题的特定查询已经过优化,所有必要的索引都已到位。我确信在 db 端必须进行进一步的优化,但在我们提出解决方案时不能让站点关闭。这更像是一个快速修复
  • 你考虑过缓存结果吗?峰值可能有一个简单的原因,因为一些并发请求都命中了该代码。
【解决方案2】:

性能问题可能是由于扫描List 中的StaticRecords

将数据读入内存一次很好,但看起来您需要更高效的数据结构才能有效地查询它。您可能还想重新考虑使用 LINQ 进行查询的想法。

至于导致您的崩溃和 100% CPU 峰值的原因,我在您发布的代码中没有看到明显的错误。

【讨论】:

  • 你建议用什么来代替 Linq?除了上述两个过滤器之外,还有更多过滤器。该方法是这样一种方式,即第一个过滤器将列表减少很多,然后将过滤的记录传递给下一个过滤器,然后进一步减少并再次为几个过滤器做同样的事情。目前静态列表包含大约 35000 个对象,在第一次过滤后,结果是大约 5000 个对象。下一个过滤器应用于 5000 个对象而不是 35000 个。所以它工作正常。我担心突然的峰值,可能导致它们的原因以及崩溃的可能性
  • 使用 LINQ - 不要在 Application_Start 中使用它。相反,在需要时查询您的模型,但缓存您的查询(例如,使缓存键成为参数的分隔列表)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-06
  • 1970-01-01
  • 1970-01-01
  • 2018-03-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多