C# · 12月 26, 2021

c# – Windows服务增加CPU消耗

在我的工作中,我有一个由我负责的六个 Windows服务,用C#2003编写.每个服务都包含一个计时器,每分钟都会触发,大部分工作都在这里发生.

我的问题是,随着这些服务的运行,它们开始在循环的每次迭代中消耗越来越多的cpu时间,即使它们没有有意义的工作要做(即,它们只是闲置,查看数据库)做某事).当它们启动时,每个服务使用4个cpu的平均(约)2-3%,这很好. 24小时后,每个服务将在其循环运行期间消耗整个处理器.

有人可以帮忙吗?我不知道是什么导致了这一点.我们当前的解决方案是每天重启一次服务(他们关闭自己,然后脚本看到他们离线并在凌晨3点重新启动它们).但这不是一个长期的解决方案;我担心的是,随着服务变得越来越繁忙,每天重启一次可能还不够……但是因为它们有更大的启动惩罚(它们都使用NHibernate进行数据访问),因为它们变得更加繁忙,正是我们没有想要做的是更频繁地重新启动它们.

@akmad:没错,这很难.

>是的,隔离运行的服务会随着时间的推移显示相同的症状.
>不,它没有.我们已经看过了.这可能发生在上午10点或下午6点或半夜.没有一致性.
>我们做;他们是.服务正在做他们应该做的事情,而不是其他任何事情.
>不幸的是,这需要预先知道服务何时将最大化cpu,这在不可预测的时间表上发生,而且从来不会很快……这会使事情变得更加困难,因为我的老板会在他们启动时运行并重新启动它们遇到问题而不考虑调试问题.
>不,他们使用相当一致的RAM(每台大约60-80MB,机器上4GB).

很好的建议,但请放心,我们已经尝试了所有常见的故障排除.我希望这是一个有人可能知道的.NET问题,我们可以解决这个问题.我的老板解决方案(我强调不希望实现)是把一个领域中保存用于该服务多次在白天重新启动数据库,这样他就可以使问题就离开,不要去想它.我正在拼命寻找真正问题的原因,以便我能解决它,因为这个解决方案将在大约六个月内成为灾难.

@Yaakov Ellis:他们每个人都有不同的功能.一个人从异地的某个地方读取Oracle数据库中的记录;另一个处理这些记录并将属于这些记录的文件传输到我们的系统;第三个检查这些文件,以确保它们是我们期望的那样;另一种是维护服务,它不断检查磁盘空间(我们已经足够)等内容并轮询其他服务器以确保它们存活;一个正在运行,只是为了确保所有其他正在运行并执行其工作,监视和报告错误,并重新启动任何无法保持整个系统一天24小时运行的任何事情.

所以,如果你问我认为你在问什么,不,所有这些服务都没有一个共同点(除了通过NHibernate访问数据库),我可以指出这是一个潜在的问题.不幸的是,如果事实证明这是实际问题(这不会让我感到惊讶),整个事情可能会被搞砸 – 我最终会用简单的sql重写所有这些问题.我希望这是一个垃圾收集器问题或者比NHibernate更容易处理的东西.

@Joshdan:不是秘密.正如我所说,我们已经尝试了所有常见的故障排除.分析是无益的:我们使用的分析器无法指向cpu使用率很高时实际执行的任何代码.大约一个月前,这些服务被撕裂,寻找这个问题.分析了每个代码段,试图弄清楚我们的代码是否是问题;我不是在这里问,因为我没有完成我的作业.如果这是服务工作比预期更多的简单案例,那就是本应该被捕获的东西.

这里的问题是,大部分时间,服务都没有做任何事情,但仍设法消耗25%以上的四个cpu核心:他们发现没有工作要做,并退出其循环并等待下一次迭代.从字面上看,这应该几乎不占用cpu时间.

以下是我们所看到的行为示例,该服务在两天内没有工作要做(在不变的环境中).这是上周捕获的:

第1天,上午8点:平均cpu使用率约3%
第1天,下午6点:平均cpu使用率约8%
第2天,早上7点:平均cpu使用率约20%
第2天,上午11点:平均cpu使用率约30%

说完看了所有可能的世俗原因,我在这里问这个问题,因为我想(正确,事实证明),我会得到更多的创新答案(如Ubiguchi的),或指针的东西我hadn”想到(像伊恩的建议).

So does the cpu spike happen
immediately preceding the timer
callback,within the timer callback,
or immediately following the timer
callback?

你误会了.这不是一个尖峰.如果是的话,就不会有问题;我可以处理尖峰.但它不是…… cpu使用率普遍上升.即使服务无所事事,等待下一次计时器命中.当服务启动时,事情很好而且平静,图表看起来像你期望的……通常,0%的使用率,当NHibernate点击数据库或服务做了一些微不足道的工作时,峰值达到10% .但是在流程运行的过程中,这种情况一直增加到25%(更多,如果我让它走得太远).

这使得伊恩的建议成为逻辑银弹(当你不看的时候,NHibernate会做很多事情).唉,我已经实现了他的解决方案,但它没有产生影响(我没有证据证明这一点,但实际上我认为这会让事情变得更糟……现在平均使用率似乎要快得多).请注意,剥离NHibernate“部分”(如您所推荐)是不可行的,因为这将剥离服务中大约90%的代码,这将让我排除计时器作为一个问题(我绝对打算试试),但不能帮我排除的NHibernate的问题,因为如果NHibernate的是导致此,那么这就是实施了狡猾的修复(见下文)只是将不得不成了路系统工作;我们如此依赖NHibernate进行这个项目,PM根本不会接受它导致无法解决的结构问题.

I just noted a sense of desperation in
the question — that your problems
would continue barring a small miracle

不要故意让它脱离这种方式.目前,该服务每天都在重新启动(与选项输入任意数量的一天的时间为他们关闭和重启),该补丁的问题,但一旦他们走上生产机不能是长期的解决方案并开始变得忙碌.问题不会继续,无论我修复它们还是PM都会对它们保持这种约束.显然,我更愿意实现一个真正的修复,但由于最初的测试显示没有理由,并且服务已经被广泛审查,因此PM宁愿让它们重新启动多次,而不是花费更多的时间来修复它们.这完全超出了我的控制范围,使你所说的奇迹比其他方式更重要.

That is extremely intriguing (insofar
as you trust your profiler).

我不.但是,这些是在Windows 2000机器上运行的Windows服务,由一个狡猾的Nant脚本部署,使用旧版本的NHibernate进行数据库访问.我真的说我相信那台机器很少.

解决方法 你提到你正在使用NHibernate – 你是否在适当的时候关闭你的N​​Hibernate会话(例如每次迭代结束?)

如果没有,那么加载到内存中的对象映射的大小将随着时间的推移逐渐增加,并且每次会话刷新将占用越来越多的cpu时间.