【Azure 應用服務】由 Azure Functions runtime is unreachable 的錯誤訊息推匯出 ASYNC(非同步)和 SYNC(同步)混用而引起ThreadPool耗盡問題

路邊兩盞燈發表於2021-06-05

問題描述

在Azure Function Portal上顯示: Azure Functions runtime is unreachable,引起的結果是Function App目前不工作,但是此前一直都是正常工作的,且沒有對Azure Function做過任何的改動,那它是為什麼出現這樣的問題呢?

【Azure 應用服務】由 Azure Functions runtime is unreachable 的錯誤訊息推匯出 ASYNC(非同步)和 SYNC(同步)混用而引起ThreadPool耗盡問題

 

問題分析

Azure Functions runtime is unreachable 的錯誤是 ”Azure Functions 執行時不可訪問”,此問題的最常見原因是函式應用失去了對其儲存帳戶的訪問許可權。首先我們根據官方文件( 排查錯誤:“Azure Functions 執行時不可訪問” )排查以下每一點:

  1. 儲存帳戶已被刪除

  2. 儲存帳戶應用程式設定已被刪除

  3. 儲存帳戶憑據無效

  4. 儲存帳戶不可訪問

  5. 每日執行配額已滿

  6. 應用受防火牆保護

 注:多個Function App之間應儘量避免共享Storage Account,在建立Function App的時候,需要關聯獨立的Storage Account. 

【Azure 應用服務】由 Azure Functions runtime is unreachable 的錯誤訊息推匯出 ASYNC(非同步)和 SYNC(同步)混用而引起ThreadPool耗盡問題

 

在排查外以上每一點後,如果依舊出現 “Azure Functions runtime is unreachable”的問題,那麼此時就需要分析當前所執行的Function是否由異常,是否由出現CPU 100%, Memory 100%,以及執行緒數等情況。

 

在這次的問題中,在Azure Function的日誌中,發現大量的如下兩種異常:

異常一

Microsoft.Azure.ServiceBus.MessageLockLostException : The lock supplied is invalid. Either the lock expired, or the message has already been removed from the queue.

Reference:ae0230de-86a9-xxxx-fdd, TrackingId:eaeef_xxxxxxxxxxxxxxxxxxxx0_B17, SystemTracker:api-11:Topic:inmessage, Timestamp:2021-06-02T06:21:22

   at async Microsoft.Azure.ServiceBus.Core.MessageReceiver.OnRenewLockAsync(String lockToken)

   …..

   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

   at async Microsoft.Azure.ServiceBus.MessageReceivePump.RenewMessageLockTask(Message message,CancellationToken renewLockCancellationToken)

與Service Bus相關
異常二

Microsoft.Azure.Storage.StorageException : The lease ID specified did not match the lease ID for the blob.

   at async Microsoft.Azure.Storage.Core.Executor.Executor.ExecuteAsync[T](RESTCommand`1 cmd,IRetryPolicy policy,OperationContext operationContext,CancellationToken token)

   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

….

   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

   at async Microsoft.Azure.WebJobs.Host.Timers.TaskSeriesTimer.RunAsync(CancellationToken cancellationToken) at C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Timers\TaskSeriesTimer.cs : 147

與Storage Account相關

 

在異常資訊中,並沒有明確的指明當前Azure Funciton執行不正常及Azure Functions runtime is unreachable有關的資訊。但是Service Bus的 MessageLockLostException 異常值得重點分析,因為MessageLockLostException 異常意味著Function在消費Service Bus的訊息的時候,由於處理訊息的時間過長,超過了Meesage Lock(鎖定,預設30秒),訊息無法消費使得回滾會Service Bus的佇列中,然後進行下一輪的消費,如此往返。最終表現就是Azure Funciton執行不正常。為了驗證這一步,需要收集Function的DUMP檔案。PS: 如何獲取Windows下Function的DUMP,可參考博文:快速獲取DUMP檔案(App Service for Windows(.NET/.NET Core)https://www.cnblogs.com/lulight/p/13574331.html

 

檢查記憶體DUMP,確認大量執行緒(基本上是所有執行緒)都在等待執行 呼叫HttpClient上傳這一步。而執行緒池此時已耗盡,無法建立新的執行緒繼續完成Http請求。導致Azure Function執行不正常,無法消費Service Bus中的訊息,也引起了 Microsoft.Azure.ServiceBus.MessageLockLostException 異常

【Azure 應用服務】由 Azure Functions runtime is unreachable 的錯誤訊息推匯出 ASYNC(非同步)和 SYNC(同步)混用而引起ThreadPool耗盡問題

(收集DUMP後可使用Visual Studio 2019檢視DUMP中的Stack資訊)

 

綜上,根據DUMP檔案中的發現,找到了問題原因:應用程式程式碼在非同步程式碼呼叫中使用了Wait方法,導致在Service Bus訊息的高峰期間,程式池耗盡,無法正常執行並處理訊息,也引起 Azure Functions runtime is unreachable,在最佳的操作要求中,有明確的要求:

在 C# 中,請始終避免引用 Result 屬性或在 Task 例項上呼叫 Wait 方法。 這種方法會導致執行緒耗盡。

【Azure 應用服務】由 Azure Functions runtime is unreachable 的錯誤訊息推匯出 ASYNC(非同步)和 SYNC(同步)混用而引起ThreadPool耗盡問題

 

解決辦法

一:從執行緒池耗盡的方面入手,增加ThreadPool。在FunctionApp上更改平臺配置,改為按照64位模式執行。由於32位的程式(x86)的Function最大執行緒數位125,而64位修改後,ThreadPool最大值提升到32767。(如果應用打包時target的x86,則需要重新打包應用target x64)。

 

二:修改程式碼。移除在async方法中所呼叫的wait()方法,修改位await。PS: 使用非同步程式碼時,裡面應該一路使用async和await。

 

 

 

參考資料

排查錯誤:“Azure Functions 執行時不可訪問”: https://docs.azure.cn/zh-cn/azure-functions/functions-recover-storage-account

提高 Azure Functions 的效能和可靠性的最佳做法: https://docs.azure.cn/zh-cn/azure-functions/functions-best-practices#avoid-sharing-storage-accounts

 

【完】

相關文章