大家都知道ASP.NET 网站应用程序(WebSite)可以自动检测到你的ASP.NET应用的文件修改,其中要使用到的就是监视磁盘上的文件/目录的更改,以便应用程序可以采取它认为必要文件创建/删除/修改事件的反应中的任何步骤的FileSystemWatcher 类。
Mono的 FileSystemWatcher实现尽了最大的努力适应各种环境(Linux/Windows/*BSD),在各种操作系统环境下执行其分配的任务,在Unix环境下支持以下后端的系统:
- FAM
- kevent (BSD*/MacOSX only)
- gamin
- inotify (Linux only)
- Managed watcher
其中,假设您运行 Linux(内核2.6.13以上), inotify是一种首选的后端机制因为它需要对用户态应用程序的一部分,他不是使用轮询而是使用 Linux 内核的通知机制 (在我们的例子,Mono的运行库)。然而,它需要 Linux 内核来支持机制。
如果你的内核不支持inotify,Mono将尝试使用FAM和gamin 这样的用户态的应用程序来监测文件系统的文件/目录的更改,然后通知到Mono运行时,这样效率就大打折扣了,性能就很糟糕了。如果Mono 都无法检测到inotify,Fam以及gamin,mono将使用最后一个选项Managed watcher,此监测程序在托管代码中实现,并为监测、 轮询更改所选文件/目录上的文件系统使用一个单独的线程。由于应用程序可能 (和在 ASP.NET 的情况下有时不会)递归查看目录,它可能会非常昂贵的情况,需要检查更改为一大组的文件。每个运行的变化检测需要检查文件/目录是否存在 (以防托管观察程序这些都是两个 stat (2) 调用),然后检查更改的文件元数据 (大小、 修改时间等),生成一个事件。大约每750ms发生一次,并给服务器的 CPU 上带来大量的负载,导致CPU飙升。
解决方法也很简单,如果你可以的话的关闭文件系统监测 (这意味着您的ASP.NET应用程序将不自动重新启动修改 Web.config 时,不会重新编译文件,如果您修改代码隐藏.cs 或.aspx、.ascx 文件等)。Mono支持MONO_MANAGED_WATCHER环境变量 设置为值disable,减轻您的应用程序做上面所述的文件系统轮询事务,既然是生产环境,就不会有什么经常性更新关闭这个特性也不会有大的影响,还可以节约后台的线程资源 。
在linux上跑ASP.NET网站,有时cpu会出现占用率比较高的情况,过段时间它又正常了,在VPS中,这样情况出现的机率更大,处理方法:
1、不必管它,它自然会降下来,只是等的时间要长一点,而且有可能过段时间又出现,原因就是上述说明,如果是VPS或者云主机上出现这个问题,你一定得好好的分析下原因,是不是就是有这个特性引起的,如果是就把他关掉;
2、使用Jexus 跑ASP.NET网站,在jws.start/jws.restart两个文件中,插一句:export MONO_MANAGED_WATCHER=disable,禁止ASP.NET自动检测,当然副作用是:你修改源码后,得手工重启这个网站。
3、使用Apache的 Mod_mono 使用命令 MonoSetEnv [server_alias] MONO_MANAGED_WATCHER=disable
可以使用下面的代码检测你的Linux服务器上使用的是哪个FileSystemWatcher 实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
namespace FileWatchDetect
{
class Program
{
static void Main(string[] args)
{
object watcher = new FileSystemWatcher().GetType()
.GetField("watcher", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
Console.WriteLine(watcher != null ? watcher.GetType().FullName : "unknown");
Console.Read();
}
}
}
下面的结果是在Windows Azure上的一台OpenSuse 12.0.4上的运行:
Inotify: 高效、实时的Linux文件系统事件监控框架
Tip: Mono ASP.NET application burning CPU in idle state - FileSystemWatcher