大家都知道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