只有累積,沒有奇蹟

2019年9月12日 星期四

[NETCore] ASP.NET Core Task block 檢測器 - Ben.BlockingDetector

前言
微軟從 ASP.NET Framework 4.5 開始支援 async / await 語法,提供開發者在撰寫非同步作業時更輕鬆與容易上手,如果對於 async / await 不夠熟悉可以看黑暗大之前的好文 ASP.NET async 基本心法但有時在一知半解寫出來的代碼有時殺傷力才會是最可怕的,如果沒有正確使用 async / await 會造成 Thread block 的問題發生,因此在撰寫 async / await 時需要更加小心留意,這篇文章就來介紹最近發現的 Ben.BlockingDetector 套件來解決此問題若有問題或是錯誤的地方歡迎高手大大給予指導或討論

安裝
為了讓大家更容易了解建立一個範例專案,專案範本使用 ASP.NET Core API 專案
開啟 Visual Studio 的 Nuget 並搜尋 BlockingDetector下載 
或是可以透過 Nuget Package Console 輸入下列指令
  1. Install-Package Ben.BlockingDetector -Version 0.0.3
安裝完畢之後到專案檔底下確認是否有安裝成功
  1. <ItemGroup>
  2. <PackageReference Include="Ben.BlockingDetector" Version="0.0.3" />
  3. </ItemGroup>

使用
一開始有提到過 async / await 未正確使用會造成 Thread block 情況發生,這裡舉一個最近遇到的 case 來說明,公司同仁連續幾天反應網站緩慢已嚴重影響正常操作,我們使用記憶體分析工具分析 dump 出來的 memory 檔案後,發現報告內容多個 Thread 都在等待的狀態,再繼續查看 Thread 的 Call Stack 發現緩慢的程式進入點皆為 PostJsonAsync,找到執行的代碼中發現是使用 Task.Result 要求同步方式回傳結果
在看到使用 Task.Result 幾位資深的同仁都笑了,紛紛表示都有踩過這雷,詳細造成原因與細節說明可以參考黑暗大的文章 : await與Task.Result/Task.Wait()的Deadlock問題,文中介紹來龍去脈非常清楚這裡就不在另外說明,在非同步中常見造成 block 原因有下列兩種

  • Task.wait
  • Task.Result

  • 解決方案有兩種,第一種是加上  configureAwait(false)  指定任務完成之後不再使用/等待原本的 Thread 執行,另一種則是將呼叫方法也改為 async 非同步方式進行,這兩種方法都能有效改善 block 問題。但此作法僅能在嚴重影響到應用程式運行時才能發現,在專案中如果要避免 Task block 情況發生,可以使用今天要介紹的主角 Ben.BlockingDetector 幫我們達到此目的,Ben.BlockingDetector 套件將會於 CLR 檢測 lock,ManualResetEventSlim,Semaphore{Slim},Task.Wait,Task.Result 等情況,並在遇到時紀錄在 Log 中,Log 內容會記錄 "Blocking method has been invoked and blocked, this can lead to threadpool starvation.",方便開發團隊日後進行追蹤的動作,下面將介紹使用方式

    加入 Detector
    開啟剛剛建立好的範例專案,在 Startup.cs 中 Configure 加入  app.UseBlockingDetection();  代碼
    1. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    2. {
    3. app.UseBlockingDetection();
    4. // other
    5. }

    調整代碼
    為了要示範 block 時的 log,我們調整 ValuesController 中 Get 方法加上 Task.Result 代碼,希望模擬阻塞的程式碼
    1. public class ValuesController : ControllerBase
    2. {
    3. // GET api/values
    4. [HttpGet]
    5. public async void Get()
    6. {
    7. var result = await Task.Run(() => BlockingTask());
    8. }
    9. private static int BlockingTask()
    10. {
    11. // Detected blocking
    12. return MethodAsync().Result;
    13. }
    14.  
    15. private static async Task<int> MethodAsync()
    16. {
    17. await Task.Delay(1000);
    18. return 5;
    19. }
    20. }
    接著啟動專案後並觀察輸出的 console 紀錄,可以清出的看到啟動後就有記錄到 block 的情況發生
    透過以上的步驟可以發現使用相當的簡單,套件實際背後運作原理相信對 ASP.NET Core 有一定理解的人也可以想像到,是加上 middleware 層針對執行的 thread 進行 monitor 的動作,若有興趣了解細節運作可以查看其 Github source code : 傳送門

    感想
    從上列描述可以得知使用上相當的簡單,下一步就可以看開發者要如何 "處理" 監測到的潛在風險代碼,或是將此紀錄丟到 ELK 加入 Daskboard 定期進行追蹤,發現的時候再請同仁協助改掉避免 block 情況影響到應用程式的運作,就看各位開發者大大如何處置了,希望這篇文章有幫助到大家&喜歡 :)

    參考
    Ben.BlockingDetector

    Related Posts:

    • [.NETCore] ASP.NET Core - Kestrel Web Server前言 上一篇分享了如何在 IIS 執行 ASP.NET Core 專案,其中 Kestrel 關鍵字一直不斷的在文章中被提到,Kestrel 可以說 .NET Core 在跨平台中扮演相當重要的角色,在研究 Kestrel 相關知識時發現在 MSDN 中有篇文章介紹 Kestrel web server implementation in ASP.NET Core 十分清楚,以下就分享閱讀完文章後… Read More
    • [.NETCore] 如何取得 appsettings.json 組態設定問題 在開發時有時會將資訊紀錄在 Web.Config 設定檔中的開發經驗,在 .NET Framework 要取得 web.config 自訂組態設定時可以透過  ConfigurationManager.AppSettings ,相信大家都有了解且不陌生;但今天場景換到 ASP.NET Core 時,在一開始建立好新專案後只有  appsettings.json  設定檔,那麼該如何… Read More
    • [.NETCore] ASP.NET Core - 使用 NLog 紀錄日誌資訊前言 在開發 .NET Framework 時候,一提到紀錄日誌的函式庫大家都會聯想到 NLog 與 Log4Net 兩種 library,兩者都是免費、OpenSource 且各有喜好者,各自提供簡單好使用的方式讓我們輕鬆地可以將需要的資訊生成相關日誌內容,從 .NET Framework 進入到 .Net Core 時代,紀錄 Application Log 勢必也是重要的功能之一,今天就要分享的是在 .NET Core … Read More
    • [VisualStudio] Unable to connect to web server 'IIS Express'問題  今天開發 .NET Core 一半忽然發生整個應用程式 hang 住不動,接著 Visual Studio 自動關閉重新啟動,啟動後心想沒事就開始繼續 Alt+F5 繼續偵錯,過沒多久就跳出提示視窗顯示訊息   "Unable to connect to web server 'IIS" ,接著就啟動跳針模式一直重開 VS & 然後跳出訊息文字,像是寫迴圈沒有加… Read More
    • [VS2017] The current .NET SDK does not support targeting .NET Core 2.1發生情境 最近在開發時遇到取完最新的source code Build時發生錯誤,Visual Studio error message 如下 The current .NET SDK does not support targeting .NET Core 2.1.  Either target .NET Core 2.0 or lower, or use a version of the .NET SDK that su… Read More

    0 意見:

    張貼留言

    Copyright © 2025 m@rcus 學習筆記 | Powered by Blogger

    Design by Anders Noren | Blogger Theme by NewBloggerThemes.com