2017-07-28 32 views
0

我看到很多討論關於網站中的靜態鎖定寫入單個文件進行日誌記錄。ASP.Net網站靜態鎖定文件寫入/ IIS回收問題

有些人說永遠不要使用靜態鎖,而其他人則說這是在這種情況下明確要求的。反對者認爲:如果IIS應用程序池被回收呢?然後,靜態鎖將丟失,並可能發生文件寫入錯誤。我的具體問題是:如果你的用戶數量相當小(n < 1000),並且你的鎖裏面有一行代碼,執行寫入<的500個字符的文件,這是一個天文上不太可能的問題與哪些有關?

如果是任何大小的問題,那麼什麼是改進避免這種罕見的IIS回收靜態鎖定錯誤的最簡單的路徑?在這種情況下,寫一個簡單的嘗試/捕獲甚至「捕獲」多個文件訪問?

+2

你爲什麼要重新發明輪子並做自己的日誌?爲什麼不使用專爲此類事物設計的現有日誌記錄庫?像[Serilog](https://serilog.net/)或[Nlog](http://nlog-project.org/)。 – mason

+0

你的觀點很好。對於IIS回收行爲的最小操作,網站上靜態鎖定的一般安全性似乎仍值得理解。 –

+0

'有些人說永遠不要使用靜態鎖'對於伐木,這些人是正確的。如果你這樣做,你不能運行一個網絡花園。 https://abhijitjana.net/2010/10/01/what-is-the-difference-between-web-farm-and-web-garden/ – mjwills

回答

0

使用FileShare.ReadWrite和useAsync =假

訪問通過創建使用this constructor(不要使用File.Open)一個FileStream文件並指定以下參數:

var stream = new FileStream(path, 
          FileMode.Append, 
          FileAccess.Write, 
          FileShare.ReadWrite, 
          4096, 
          false); 

的重要參數要注意的是FileShare.ReadWriteuseAsync = false

FileShare.ReadWrite:允許隨後打開文件進行讀取或寫入。如果未指定此標誌,則在文件關閉之前,打開文件進行讀取或寫入(通過此進程或其他進程)的任何請求都將失敗。但是,即使指定了此標誌,訪問該文件仍可能需要其他權限。

useAsync:指定是否使用異步I/O或同步I/O。但是請注意,底層操作系統可能不支持異步I/O,因此在指定true時,可能會根據平臺同步打開句柄。當以異步方式打開時,BeginRead和BeginWrite方法在大型讀取或寫入時執行得更好,但對於小型讀取或寫入,它們可能會慢很多。如果應用程序旨在利用異步I/O,請將useAsync參數設置爲true。使用異步I/O正確地可以加快多達應用程序作爲10倍,但使用它而不用重新設計爲異步I應用程序/ O可以作爲10.

通過一個因子多達降低性能使用這些參數,您將獲得一個允許其他進程並行訪問文件的文件句柄。同時你的寫操作將是同步的,這將防止你的輸出被另一個進程分裂成一半。仍然存在鎖定,但它由底層操作系統處理,並且對您和任何競爭過程都是透明的。

添加鎖

如果它讓你感覺更好,你可以在鎖把它包:

lock (lockObject) 
{ 
    using (var stream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite, 4096, false)) 
    { 
     var writer = new TextWriter(stream); 
     writer.Write(message); 
    } 
} 

注意,lock保護您免受競爭的線程,而不是相互競爭的過程。如果您有一個處理日誌寫入的工作線程(例如,與隊列和生產者/消費者模式),你可能不需要它,它會增加不必要的開銷。但是,如果您直接從Web工作線程寫入日誌,則確實需要它。

跨進程互斥

以上應該是很要命的安全,即使是在一個應用程序池回收。至少我從來沒有遇到任何問題。但是..如果你是真的偏執和你的日誌是關鍵的任務,你可以使用named mutex鎖定跨越進程邊界。

var mutex = new Mutex(false, "MyLoggingMutex"); 
try 
{ 
    mutex.WaitOne(); 
    using (var stream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite, 4096, false)) 
    { 
     var writer = new TextWriter(stream); 
     writer.Write(message); 
    } 
} 
finally 
{ 
    mutex.ReleaseMutex();   
} 

有相當多的開銷有這樣的事情,所以我除非記錄很可能不會使用它的關鍵任務,如您將可審計的數據轉儲到可能用於支持不可否認性的日誌文件(例如,以證明誰做了什麼以免被起訴等等)。但如果真的是這樣的話,我會堅持使用數據庫,這使得問題變得微不足道。

+0

主席先生,我很欣賞你花了很大的努力來回答這個問題,並將調查這些不同的途徑。謝謝。 –