NLog 的檔案管理策略

NLog 是一個在 .NET 開發領域相當受歡迎的 log 管理工具,因為操作簡單、功能齊全,且具備完善的歸檔與壓縮機制。然而,前陣子我們團隊因為 NLog 的檔案管理策略設定不當,導致線上服務在歸檔過程中完全卡住,無法處理任何請求。以這個實際問題為契機,我想紀錄一下使用 NLog 管理 log 時的正確策略、可能的風險,以及設定時的考量,以避免日後再度踩坑。

設定單檔大小上限的重要性

當應用程式進入正式環境後,log 會持續地被寫入並逐漸增大。有時為了進行問題排查,我們會設定比較詳細的 log 等級(如 Debug),這會使 log 檔案快速膨脹,甚至達到幾百 MB 以上。這麼大的 log 檔案,許多編輯工具或 log 檢視工具(例如 Notepad++、VS Code、甚至特製的 log 分析工具)開啟時可能會變慢,甚至完全無法開啟。

為了避免這個問題,建議根據團隊常用的 log 檢視工具性能,設定單一 log 檔案的大小上限。一旦 log 檔案大小超過設定的上限,NLog 就會自動拆分成新的檔案,例如:

1
2
3
4
5
6
<target xsi:type="File" name="logfile"
fileName="logs/logfile.log"
archiveFileName="logs/archives/log.{#}.log"
archiveAboveSize="52428800" <!-- 50MB -->
archiveNumbering="Rolling"
maxArchiveFiles="30" />

上述設定代表單一 log 檔案超過 50MB 時,自動歸檔並建立新的 log 檔案,最多保留最近的 30 個檔案。

歸檔後壓縮造成的潛在風險

NLog 提供了方便的歸檔與壓縮功能,但在實務上我們發現這個功能可能會導致非預期的副作用。

NLog 在進行歸檔壓縮時,會將檔案鎖定,這時 log 的寫入會暫停。如果檔案較小,這個鎖檔的過程可能很短,使用者幾乎不會察覺;但若 log 檔案過大,或是伺服器正處於高負載狀態,則可能造成明顯的服務停頓或延遲。特別是在高流量環境下,這種「短暫」的鎖檔動作可能會引發一連串問題,例如:

  • Thread starvation:
    因為 log 的寫入請求會持續排隊等待,進而佔用越來越多執行緒,最終導致系統無法處理新進的使用者請求。
  • 記憶體用量暴增:
    無法寫入 log 的服務可能會暫存資料在記憶體中,逐漸佔據過多記憶體資源,最終導致系統資源耗盡。

為了避免上述問題,可以考慮以下幾個策略:

  • 減少單檔大小,縮短壓縮時間
    單檔大小設定得越小,單次壓縮的時間自然越短。但這終究只是降低鎖檔時間,並沒有從根本上解決問題。
  • 避免壓縮,換取系統穩定性
    若磁碟空間足夠,乾脆不要使用壓縮功能,直接歸檔即可。以較大的硬碟空間成本來換取服務的穩定運行。
  • 使用外部排程工具進行壓縮
    有一種替代方案是使用外部的排程工具(如 Windows Task Scheduler 或 Linux cron job)定期將已歸檔的 log 檔案進行壓縮,避免 NLog 本身在壓縮時的鎖檔問題。但這種方式容易造成額外的維護成本與交接困難,經常會出現設定未同步、有些同事不知道這些機制、任務執行失敗未被察覺等問題,因此我個人不建議採用這個做法。

參考

ChatGPT