不可忽視的 .NET 應用5大性能問題

【編者按】本文系國內 ITOM 管理平臺 OneAPM 翻譯自 Steven Haines 的文章。Steven Haines 是 Pisksel 技術架構師,目前在奧蘭多迪士尼樂園工作。他是在線教育網站 geekcap.com 的創始人,著有上百篇 Java 相關的文章以及三本 Java 著作:《Java 2 From Scratch》《Java 2 Primer Plus》以及《Pro Java EE Performance Management and Optimization》

實現有效 APM 策略所面臨的挑戰:

  • 代碼依賴
  • 過度或不必要的日志
  • 同步與鎖
  • 潛在數據庫問題
  • 潛在的基礎架構問題

1、代碼依賴

開發程序是一項具有挑戰性的工作。你不僅要為了滿足商業需求而建立程序邏輯,還要選擇最合適的代碼庫和工具來幫助你。你能想象自己創建所有的日志管理代碼,XML 和 JSON 解析邏輯,或所有的序列化庫么?你當然可以編寫代碼來完成這些事,但是諸多開源開發者團隊已經做好了這些事情,你又何必親力親為呢?此外,如果你正在與第三方系統集成,你會自己讀完專有的通信協議規范,還是購買供應商提供的庫幫你完成呢?

我相信你會同意:如果有人已經解決了你的問題,使用他的解決辦法會比自己想辦法解決效率更高。如果這是一個已經被許多公司采用的開源項目,那么很可能它已經經過完備的測試,文檔充足,而且你應該找得到許多使用教程。

然而,使用依賴庫是有危險的。你需要回答以下問題:

  • 這個庫真的寫得很好并且已經充分測試了嗎?
  • 你是否用與眾多公司一樣的方式使用這個庫?
  • 你的使用方式是否正確?

請確保在選擇外部庫之前進行一些調查,如果你對某個庫的性能有什么疑問,那就進行一些性能測試。開源項目很好的地方在于你可以訪問它們的全部源代碼以及測試套件和構建流程。下載它們的源代碼,執行編譯過程,并查看測試結果。如果你看到很高的測試覆蓋率,那么就可以比沒有測試案例時信心百倍!

最后,確保正確地使用依賴庫。如果正確使用,ORM 工具的確能夠大大提高性能。ORM 工具的問題在于,如果你不花時間去學習如何正確地使用它,你就會輕易的砸自己腳,破壞自己的應用性能。關鍵就在于如果不花時間學習這些工具,本應幫助你的工具反而會傷害你。

2、過度或不必要的日志

日志記錄是調試工具庫里的強大武器,可以幫助你識別應用執行過程中在特定時間內可能發生的異常。當錯誤發生時,捕捉錯誤信息并收集盡可能多的上下文信息是非常重要的。然而,簡潔地捕捉錯誤條件和過度記錄之間是有差別的。

最普遍的兩個問題就是:

  • 多級別異常日志
  • 錯誤配置生產日志級別

異常日志能幫助你了解應用程序中發生的問題,因而非常重要。但一個常見的問題是,應用程序所有層級的異常都進行記錄。例如,你的某個數據訪問對象捕獲到一個數據庫異常,并將該異常傳達到服務層。服務層可能會捕捉該異常,并將其傳達到網絡層。如果我們在數據層、服務層和網絡層上都記錄該異常,那么我們對此相同的錯誤條件就有三條堆棧記錄。這會導致寫入日志文件的額外負擔,還會使日志文件充滿冗余信息。但這個問題非常普遍,我敢斷言,如果你檢查自己的日志文件,你很可能會發現多個這樣的例子。

生產應用中常見的另一個大的日志問題與日志級別有關。.NET 日志記錄器定義了以下日志記錄級別(.NET TraceLevel 與 log4net 中的命名會有所不同,但絕對相似):

  •     Off
    
  •     Fatal
    
  •     Error
    
  •     Warning
    
  •     Info
    
  •     Verbose / Debug 
    

在生產應用程序中,你應該只記錄 error 或 fetal 級別的日志語句,在更寬松的環境中,捕捉 warning 甚至 info 級別的日志信息也完全可以,但是一旦應用投入生產環境,用戶負載將迅速填滿日志并使應用程序陷入癱瘓。如果你不經意地將生產環境下的應用日志級別設為 debug,應用的響應時間比正常情況下高兩或三倍都不奇怪!

3、同步與鎖

有時候,你想確保應用代碼中每次只有一個線程執行一段代碼子集。
例如,讀取單線程規則執行組件之類的共享軟件資源,以及文件句柄或網絡連接之類的共享基礎架構資源。.NET 框架提供了許多不同類型的同步策略,包括鎖/監視器、進程間互斥,和讀/寫鎖這類的專用鎖。

不管你為什么要同步代碼或者選擇什么機制實現代碼同步,都會導致一個問題:那就是有部分代碼一次只能由一個線程執行。
設想去超市,只有一個收銀員在工作:許多人進入商店,瀏覽商品,將商品放進購物車里,但某一時候,他們不得不排隊以進行支付。在這個例子中,購物是多線程的,每個人都代表一個線程。然而結賬是單線程的,這意味著每個人都要花費排隊付款的時間。這個過程如圖1所示。

不可忽視的 .NET 應用5大性能問題
不可忽視的 .NET 應用5大性能問題

圖1:線程同步

我們有七個線程,都需要訪問一段同步代碼塊,所以它們依次獲得權限訪問該代碼塊,執行其功能,然后繼續。

在圖2中總結了線程同步的過程。


不可忽視的 .NET 應用5大性能問題
不可忽視的 .NET 應用5大性能問題

圖2 線程同步過程

首先,為特定的對象(System.Object 派生)創建鎖,意味著當一個線程試圖進入同步代碼塊時必須獲取該同步對象的鎖。如果該鎖可用,則該線程被授予執行同步代碼的權限。在圖2中的例子中,當第二個線程到達時,第一個線程已經占有了該鎖,所以第二個線程被強制等待,直到第一個線程執行完畢。當第一個線程執行結束時,會釋放該鎖,然后第二個線程被授予訪問權限。

正如你可能猜測到的,線程同步將給 .NET 應用帶來一個極大的挑戰。我們設計應用程序時,希望其能支持數十個甚至數百個同步請求,但線程同步會把所有處理這些請求的線程串行化,導致性能瓶頸!

解決的辦法有兩種:

  • 仔細檢查同步的代碼,以確定是否存在其他可行辦法
  • 限制同步代碼塊的范圍

有時候,你要訪問必須同步的共享資源,但很多時候,你可以用完全避免同步的方法重新解決該問題。例如,我們之前使用的規則過程引擎有單線程的要求,因此拖慢了程序中所有請求的執行速度。這顯然是一個設計上的缺陷,我們可以用一個可以并行工作的庫取代之。你需要問自己是否有更好的選擇:如果你在往一個本地文件系統寫入信息,你是否可以把信息發送給某項服務,再由該服務將信息存儲到數據庫中?你是否可以將對象設為不可變,從而無論是否有多線程訪問它都沒關系?等等,等等…

對于那些必須要同步的代碼段,請合理地選擇鎖。你的目標是將同步代碼塊隔離以滿足最低限度的同步要求。通常最好是定義一個特定的對象進行同步,而不是對包含同步代碼的對象進行同步,因為你可能會在不經意間拖慢該對象的其他交互。最后,考慮使用讀/寫鎖,而不是標準的鎖,這樣,你可以在資源只進行同步變化時,允許讀操作。

4.潛在的數據庫問題

幾乎所有的內容應用最終都會涉及到向/從數據庫或文檔存儲儲存/檢索數據。因此,數據庫、數據庫查詢,以及存儲過程調優對應用程序的性能來說是最重要的。

程序架構師/開發人員和數據庫架構師/開發人員之間有一個哲學性的劃分。應用程序架構師傾向于認為所有的業務邏輯都應該駐留在應用程序中,數據庫應該只提供訪問數據的通道。另一方面,數據庫架構師更傾向于認為將業務邏輯推到數據庫中更有益提高性能。這個劃分的答案很可能就是介于兩者之間。

作為一個應用程序架構師,我傾向于將更多的業務邏輯應用在程序當中,但我完全承認數據庫架構師能更好的理解數據和與數據交互的最佳方式。我認為,這兩個群體之間的協同合作才能產生最佳的解決方案。但是,不管你傾向于哪一方,請確保你的數據庫架構師檢查你的數據模型,所有的查詢語句和存儲過程,他們都有豐富的知識幫助你以最佳的方式來調整和配置數據庫,他們有大量的工具可以為你調整查詢語句。例如,有一些工具可用于 SQL 調優,遵循以下這些步驟:

  • 分析 SQL 語句
  • 確定查詢的執行計劃
  • 利用人工智能生成備選的 SQL 語句
  • 確定所有備選方案的執行計劃
  • 提出最佳的查詢方式來完成目標

當我在寫數據庫查詢代碼時,我使用了這類工具,并在高負載情況下量化了結果,一些細微的調整和優化,都能導致極大的性能提升。

5、潛在的基礎架構問題

之前提過,.NET 應用運行在分層的環境中,其層級結構如圖3所示:

不可忽視的 .NET 應用5大性能問題
不可忽視的 .NET 應用5大性能問題

圖3.NET分層執行模型

你的應用程序運行在 ASP.NET 或是 Windows Forms 容器中,使用 ADO 庫與運行在 CLR 內部的數據庫交互,而 CLR 運行在操作系統中,操作系統又運行在硬件里。而該硬件又與其他包含不同技術堆棧的硬件通過網絡相連。在你的應用與外部環境之間,以及在應用的組件之間,通常有多個負載平衡器。我們還有 API 管理服務以及多級緩存。所有這一切,都是為了說明,基礎構造數量龐雜,都可能影響應用程序的性能!

因此,你必須細致地調整基礎架構。檢查你的應用組件和數據庫所運行的操作系統和硬件設備,以確保它們的最佳表現。測量服務器之間的網絡延遲,并確保你有足夠的帶寬來滿足應用程序之間的交互。檢查緩存,確保較高的緩存命中率。分析負載平衡器的行為以確保請求很快地分發到所有可用的服務器??傊?,你需要全面檢查應用程序的性能,既包括應用業務交易也包括支持它們的基礎架構。

OneAPM 助您輕松鎖定 .NET 應用性能瓶頸,通過強大的 Trace 記錄逐層分析,直至鎖定行級問題代碼。以用戶角度展示系統響應速度,以地域和瀏覽器維度統計用戶使用情況。想閱讀更多技術文章,請訪問 OneAPM 官方博客。
本文轉自 OneAPM 官方博客

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容