CLRThreadPoolQueue 中的大部分请求
Large percent of requests in CLRThreadPoolQueue
我们有一个 ASP.NET MVC 应用程序托管在 Azure 应用程序服务中。 运行使用分析器帮助诊断可能的缓慢请求后,我们惊讶地发现:
CLRThreadPoolQueue 中缓慢请求的百分比异常高。我们现在 运行 多个配置文件会话返回,每个会话在 CLRThreadPoolQueue 中有 40-80%(这是我们以前在以前的配置文件中从未见过的)。 CPU 每次都低于 40%,并且在检查我们的指标后,我们并没有遇到突然的请求激增。
大多数列为缓慢的请求都是超级简单的 api 调用。我们添加了响应缓存并使它们异步。他们所做的唯一一件事就是访问数据库以查找单个记录结果。我们检查了数据库上的指标,查询平均 运行 时间约为 50 毫秒或更短。查看这些请求的应用程序洞察证实了这一点,并表明数据库查询直到请求时间线的最后才发生(我假设这是队列中的请求)。
最近我们开始将 SignalR 纳入我们应用程序的一部分。它没有完全使用,但它在代码库中。我们后来改用 Azure SignalR 服务,没有发现任何变化。 SignalR 的添加是我们在遇到此问题后所做的唯一 "major" change/addition。
我知道我们可以扩大 and/or 增加 minWorkerThreads。然而,这感觉就像我只是在治疗症状而不是病因。
我们尝试过的事情:
- 找到最频繁的请求并使它们异步(之前不是)
- 对频繁请求的响应缓存
- 使用 Azure SignalR 服务而不是将其托管在同一网站上
- 运行 内存转储并联系 Azure 支持(他们
一无所获)。
- 扩展到 S3
- 使用和不使用线程报告进行分析
-- None 这些步骤解决了我们的问题 --
我们如何确定哪些请求 and/or 代码导致请求堆积在 CLRThreadPoolQueue 中?
我们遇到了类似的问题,我猜 SignalR 内部肯定用完了很多线程或其他一些争用的资源。
我们做了三件大有帮助的事情:
在应用程序启动时调用 ThreadPool.SetMinThreads(400, 1)
以确保线程池有足够的线程来处理从启动开始的所有传入请求
使用部署的相同代码创建第二个应用服务。在 javascript 中,将 SignalR URL 设置为指向第二个实例。这样,所有 SignalR 请求都转到一个应用程序服务,而应用程序的所有 HTTP 请求都转到另一个。显然这需要设置 SignalR 背板,但假设您的应用服务有超过 1 个实例,您无论如何都必须这样做
查看任何同步代码路径的代码(例如,对数据库或 API 进行非异步调用)并将它们转换为异步代码路径
我们有一个 ASP.NET MVC 应用程序托管在 Azure 应用程序服务中。 运行使用分析器帮助诊断可能的缓慢请求后,我们惊讶地发现:
CLRThreadPoolQueue 中缓慢请求的百分比异常高。我们现在 运行 多个配置文件会话返回,每个会话在 CLRThreadPoolQueue 中有 40-80%(这是我们以前在以前的配置文件中从未见过的)。 CPU 每次都低于 40%,并且在检查我们的指标后,我们并没有遇到突然的请求激增。
大多数列为缓慢的请求都是超级简单的 api 调用。我们添加了响应缓存并使它们异步。他们所做的唯一一件事就是访问数据库以查找单个记录结果。我们检查了数据库上的指标,查询平均 运行 时间约为 50 毫秒或更短。查看这些请求的应用程序洞察证实了这一点,并表明数据库查询直到请求时间线的最后才发生(我假设这是队列中的请求)。
最近我们开始将 SignalR 纳入我们应用程序的一部分。它没有完全使用,但它在代码库中。我们后来改用 Azure SignalR 服务,没有发现任何变化。 SignalR 的添加是我们在遇到此问题后所做的唯一 "major" change/addition。
我知道我们可以扩大 and/or 增加 minWorkerThreads。然而,这感觉就像我只是在治疗症状而不是病因。
我们尝试过的事情:
- 找到最频繁的请求并使它们异步(之前不是)
- 对频繁请求的响应缓存
- 使用 Azure SignalR 服务而不是将其托管在同一网站上
- 运行 内存转储并联系 Azure 支持(他们 一无所获)。
- 扩展到 S3
- 使用和不使用线程报告进行分析
-- None 这些步骤解决了我们的问题 --
我们如何确定哪些请求 and/or 代码导致请求堆积在 CLRThreadPoolQueue 中?
我们遇到了类似的问题,我猜 SignalR 内部肯定用完了很多线程或其他一些争用的资源。
我们做了三件大有帮助的事情:
在应用程序启动时调用
ThreadPool.SetMinThreads(400, 1)
以确保线程池有足够的线程来处理从启动开始的所有传入请求使用部署的相同代码创建第二个应用服务。在 javascript 中,将 SignalR URL 设置为指向第二个实例。这样,所有 SignalR 请求都转到一个应用程序服务,而应用程序的所有 HTTP 请求都转到另一个。显然这需要设置 SignalR 背板,但假设您的应用服务有超过 1 个实例,您无论如何都必须这样做
查看任何同步代码路径的代码(例如,对数据库或 API 进行非异步调用)并将它们转换为异步代码路径