譯者注:這篇文章依然是介紹.NET Framework框架下的性能問題排查,可能並不直接適用於.NET Core,但有時也能提供一些參考。
.NET應用程序7種最常見的性能問題及其解決方案
原文地址:https://www.eginnovations.com/blog/top-7-net-application-performance-problems/
Microsoft .NET Framework是最流行的應用程序開發平台和編程語言之一。C#和ASP.NET框架已被數百萬開發人員用於構建Windows客戶端應用程序,XML Web服務,分布式組件,客戶端-服務器應用程序,數據庫應用程序等。
隨着.NET應用范圍越來越廣泛,對於大多數應用程序所有者和開發人員來說,確保.NET應用程序的優良性能是最重要的需求。
.NET應用程序運行緩慢的原因可能有很多。這些包括不正確的內存大小調整,GC暫停,代碼級錯誤,異常的過多日志記錄,同步塊的高使用率,IIS服務器瓶頸等等。
在此博客中,我們將研究.NET應用程序中的一些常見性能問題,並提供解決和解決這些問題的技巧。
1、未處理的異常與記錄過多異常日志
.NET異常不是一件壞事,只有錯誤的用法卻是壞事。這就是大多數開發人員所相信的,如果對異常進行了適當的處理,即拋出,捕獲和處理(並且不忽略),則會帶來穩定的性能。
然而,就像太多的廚師會寵壞了湯一般,太多未處理的異常會導致代碼效率低下並影響應用程序性能[1]。
尤其是隱藏的異常更糟,這種隱藏異常就像雷區,一旦未能檢查這些異常,它們會影響網頁加載時間。
.NET的另一個問題是過多地記錄了異常。日志記錄可能是您的調試工具庫中的一個好工具,它可以識別在處理應用程序時記錄的異常。
但是,當設置日志記錄來捕獲應用程序體系結構每一層的異常時,最終可能會在Web,服務和數據層上記錄相同的異常。這可能會增加應用程序代碼的負擔,並增加響應時間。在生產環境中,只需要記錄致命事件和錯誤就需要小心。
記錄所有信息,包括參考消息,調試和警告,很容易使您的生產日志文件file臃腫,進而影響代碼處理。
有用的疑難解答提示:
•確保您的C#代碼具有“嘗試最終捕獲”塊以處理異常。•利用C#6和更高版本中提供的異常過濾器,該過濾器允許為每個catch塊指定一個條件子句•檢查空值,並使用TryParse避免潛在的異常。•請注意第二次機會異常,因為它們表明出現了第一次機會異常,並且未正確處理它。•使用異常處理和日志記錄庫(例如企業庫,NLog,Serilog或log4net)將異常記錄到文件或數據庫中。•確保僅根據需要記錄異常,並且最終不會使日志文件膨脹。
2、過度使用線程同步和Lock
.NET Framework提供了許多線程同步選項,例如進程間互斥,讀取器/寫入器鎖等。
有時,.NET開發人員將以這樣的方式編寫代碼:在給定的條件下,只有一個線程可以得到服務。
時間以及其他要處理的並行線程將不得不在隊列中等待。例如,結帳應用程序根據其業務邏輯應一次處理一個請求。同步和鎖定有助於序列化傳入線程以執行。通過創建同步的代碼塊並在特定對象上施加鎖定,需要傳入線程等待直到同步對象上的鎖可用為止。盡管此策略在某些情況下會有所幫助,但不應過度使用。
有用的疑難解答提示:
•使用同步編碼,僅在必要時使用鎖。在決定使用鎖之前,請先了解代碼執行的需求。•最佳地調整鎖的持續時間范圍,以便延遲獲取並提前釋放它們,並且不會長時間等待其他線程。•為了減少並發問題,請考慮使用松散耦合。事件委托模型也可以用於最小化鎖爭用。•使用代碼分析工具[2]監視.NET代碼,以識別線程鎖定是否導致應用程序處理緩慢。
3、應用程序掛起
有時特定的URL緩慢時,這是一回事。但是,當IIS網站剛剛掛起並且所有或大多數網頁需要永久加載時,它不會變得更糟。通常,當應用程序過載或死鎖時,可能會掛起。.NET應用程序通常會遇到兩種類型的應用程序掛起方案。
硬掛(IIS問題):這通常發生在請求處理管道的開始–在請求排隊的地方。由於應用程序死鎖,所有可用線程都可能被阻塞,導致隨后的傳入請求最終在等待服務的隊列中結束。當活動請求數超過IIS服務器上配置的並發限制時,也會發生這種情況。此類掛起將表現為請求超時並收到503 Service Unavailable錯誤。硬性影響所有URL和整個Web應用程序本身。
有用的疑難解答提示:
•不斷跟蹤IIS服務器中隊列中的請求數(Windows性能監視器中為Http Service Request Queues \ ArrivalRate)。這決不能超過為工作進程配置的請求處理限制。•還跟蹤隊列中的請求等待時間(Windows性能監視器中的Http Service Request Queues \ MaxQueueItemAge)。這將有助於檢測應用程序是否面臨潛在的掛起。•還可以通過監視IIS服務器事件來注意服務不可用和連接超時錯誤。
軟掛(ASP.NET問題):這通常是由於特定段中的應用程序代碼錯誤而造成的,僅影響幾個URL而不影響整個網站。通常,由ASP.NET控制器或頁面引起的掛起發生在
ExecuteRequestHandler
階段。為了確認這一點,您可能想調試一下調試器,以確切了解請求被卡在哪里。檢查模塊名稱,階段名稱和URL。URL將指示導致掛起的控制器/頁面。
有用的疑難解答提示:
•通過檢查Windows性能監視器中的Http服務請求隊列\ CurrentQueueSize計數器,驗證IIS是否是問題。如果為0,則IIS隊列中沒有任何請求。•如果不是IIS問題,則必須是ASP.NET控制器/頁面中的代碼級問題。•使用任何代碼分析,確定哪些URL掛起並獲得詳細的請求跟蹤。驗證請求掛起的模塊名稱和階段名稱,以確認這是ASP.NET問題。•使用事務跟蹤工具[3]進行代碼分析可以幫助識別存在問題的確切代碼行。
4、頻繁垃圾回收暫停
當托管堆上分配的對象使用的內存超過應用程序開發人員配置的可接受閾值時,.NET CLR中的垃圾回收(GC)會初始化。這是GC.Collect方法跳轉到動作並回收死對象占用的內存的時候。CLR中的GC通常發生在存儲短期對象的第0代堆中。當GC發生在包含長期對象的第二代堆中時,它稱為Full GC。每次發生GC都會在CLR上增加大量CPU負載,並減慢應用程序的處理速度。因此,如果GC暫停時間更長且更頻繁,則應用程序將趨於放緩。
有用的疑難解答提示:
•適當調整GC堆內存的大小,並確保已根據需要設置GC限制。•避免在不需要它們的地方使用對象和大字符串。•跟蹤GC的實例,GC花費的時間以及JVM花費的GC時間的百分比。•尋找發生完全GC的時間。這可能導致應用程序變慢。•根據應用程序需求明智地使用服務器GC或工作站GC。•端到端監視CLR層以識別內存使用情況,GC活動,CPU峰值等。
5 、IIS服務器瓶頸
Microsoft IIS Server是.NET Framework的關鍵部分。IIS是Web服務器,它承載構建於.NET上的Web應用程序或網站,並運行W3WP進程,該進程負責響應傳入的請求。IIS還集成了公共語言運行時(CLR),該運行時負責為線程處理分配資源。由於IIS具有各種活動部分,因此IIS中的瓶頸可能會對.NET應用程序性能產生直接的負面影響。
常見的IIS服務器問題:
•由於內存,CPU等資源的過度利用而導致服務器超載•高並發連接數和連接數下降•應用程序池故障•SSL證書已過期•ASP.NET請求處理服務的高響應時間•高CLR等待時間•緩存不正確•HTTP錯誤,包括靜態和動態內容錯誤以及連接錯誤
有用的疑難解答提示:
•調整IIS服務器的大小,以便不存在資源爭用或資源過度利用的情況。•根據傳入請求的速率與更多IIS服務器進行負載平衡。•跟蹤SSL證書的有效性,並在證書過期之前主動發出警報。•監視IIS性能[4],應用程序池,網站的所有方面,[5]並識別不正確的配置和性能偏差。
6、數據庫慢查詢
並非總是會影響應用程序性能的.NET代碼問題。運行緩慢的查詢通常是常見的原因。但是通常是.NET應用程序開發人員因應用程序性能下降[6]而受到指責。
這樣做的原因是,SQL性能如何影響.NET應用程序處理沒有上下文可見性。ADO.NET和ODP.NET連接問題可能是查詢處理緩慢的原因之一,但常見原因是查詢的格式不正確。執行計划不正確,索引缺失,架構設計不當,緩沖池較小,聯接缺失,緩存不正確,連接未正確進行池化等也是導致數據庫查詢處理受到影響的原因。
雖然DBA負責數據庫性能和查詢創建,但.NET應用程序所有者需要在應用程序處理期間跟蹤查詢級別的問題。這將有助於區分代碼級問題和數據庫問題,並且.NET開發人員不必花時間尋找代碼中的問題。
有用的疑難解答提示:
•在應用程序事務的上下文中監視查詢處理以識別慢查詢。•適當規划數據庫的大小和配置,以確保一致的性能。•使用數據庫監視工具[7]來識別和修復丟失的索引,通過重新索引來優化數據庫布局等。•跟蹤數據庫與應用程序的連接,以隔離所有連接問題。
溫馨提示:除了數據庫調用速度慢之外,由於外部調用[8](例如HTTP,Web Service,WCF)也可能導致速度慢[9]。
7、基礎設施故障:盡管不是.NET框架的問題,但仍是一個.NET問題!
.NET Framework不是獨立的層。使用.NET Framework的應用程序將與基礎架構(例如任何虛擬服務器,容器或雲基礎架構)有很多依賴性。然后,可能會有后端存儲設備。盡管這些不是直接的.NET問題,但是這些基礎結構組件中的任何一個問題都可能同樣影響.NET性能。
就像我們看到IIS服務器和數據庫可能遇到瓶頸一樣,VM可能會耗盡資源,SAN陣列可能會遇到無法處理的高IOPS,或者如果.NET應用程序托管在Azure上,那么可能會有一個應用程序服務運行不正常。
在大多數應用程序環境中,與網絡相關的投訴都位居榜首。無論是網絡問題還是應用程序問題之間總是存在責備游戲。網絡擁塞,丟包或設備故障可能會影響應用程序的性能和連接性。
有用的疑難解答提示:
.NET應用程序環境的總體性能保證要求應用程序與支持基礎結構之間的依存關系具有相關的可見性。確保實施融合的應用程序和基礎結構監視策略以捕獲基礎結構問題。
當您專注於捕獲和解決所有這些問題時,請務必記住,編寫干凈而高效的代碼可以解決.NET方面的許多問題。編寫良好的代碼,保持系統和基礎架構的健康,並實施必要的工具以監控自動化。這將幫助您提供高性能的.NET應用程序和數字體驗。
References
[1]
應用程序性能: https://www.eginnovations.com/blog/what-is-application-performance-monitoring/[2]
代碼分析工具: https://www.eginnovations.com/microsoft-net-monitoring[3]
事務跟蹤工具: https://www.eginnovations.com/microsoft-net-monitoring[4]
監視IIS性能: https://www.eginnovations.com/iis-monitoring[5]
所有方面,: https://www.eginnovations.com/iis-monitoring[6]
應用程序性能下降: https://www.eginnovations.com/webinar/my-application-is-slow-troubleshooting-prevention/[7]
數據庫監視工具: https://www.eginnovations.com/database-monitoring[8]
速度慢之外,由於外部調用: https://www.eginnovations.com/microsoft-net-monitoring#supported[9]
速度慢: https://www.eginnovations.com/microsoft-net-monitoring#supported