• 【Azure 应用服务】由 Azure Functions runtime is unreachable 的错误消息推导出 ASYNC(异步)和 SYNC(同步)混用而引起ThreadPool耗尽问题


    问题描述

    在Azure Function Portal上显示: Azure Functions runtime is unreachable,引起的结果是Function App目前不工作,但是此前一直都是正常工作的,且没有对Azure Function做过任何的改动,那它是为什么出现这样的问题呢?

    问题分析

    Azure Functions runtime is unreachable 的错误是 ”Azure Functions 运行时不可访问”,此问题的最常见原因是函数应用失去了对其存储帐户的访问权限。首先我们根据官方文档( 排查错误:“Azure Functions 运行时不可访问” )排查以下每一点:

    1. 存储帐户已被删除

    2. 存储帐户应用程序设置已被删除

    3. 存储帐户凭据无效

    4. 存储帐户不可访问

    5. 每日执行配额已满

    6. 应用受防火墙保护

     注:多个Function App之间应尽量避免共享Storage Account,在创建Function App的时候,需要关联独立的Storage Account. 

    在排查完以上每一点后,如果依旧出现 “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:projectsazure-webjobs-sdk-rqm4tsrcMicrosoft.Azure.WebJobs.HostTimersTaskSeriesTimer.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 异常

    (收集DUMP后可使用Visual Studio 2019查看DUMP中的Stack信息)

    综上,根据DUMP文件中的发现,找到了问题原因:应用程序代码在异步代码调用中使用了Wait方法,导致在Service Bus消息的高峰期间,进程池耗尽,无法正常运行并处理消息,也引起 Azure Functions runtime is unreachable,在最佳的操作要求中,有明确的要求:

    在 C# 中,请始终避免引用 Result 属性或在 Task 实例上调用 Wait 方法。 这种方法会导致线程耗尽。

    解决办法

    一:从线程池耗尽的方面入手,增加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

    【完】

    当在复杂的环境中面临问题,格物之道需:浊而静之徐清,安以动之徐生。 云中,恰是如此!

  • 相关阅读:
    02-17 位图验证码(一般处理程序)+AJAX
    02-18 报表
    SQLite 函数大全
    SQLite中的时间日期函数(转)
    DES,AeS加解密,MD5,SHA加密
    suspendlayout
    AES--高级数据加密标准
    C#中Validating和Validated事件
    Net操作Excel(终极方法NPOI)
    decimal,float和double的区别
  • 原文地址:https://www.cnblogs.com/lulight/p/14853984.html
Copyright © 2020-2023  润新知