首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何排查ASP.NET Core on Linux (Kubernetes)中的线程饥饿问题?

如何排查ASP.NET Core on Linux (Kubernetes)中的线程饥饿问题?
EN

Stack Overflow用户
提问于 2018-05-02 00:26:29
回答 2查看 11.6K关注 0票数 17

我在谷歌云中的Kubernetes上运行了一个ASP.NET核心API。

这是一个高负载的API,在每次请求时,它都会执行库,进行长时间(1-5秒)的CPU密集型操作。

我所看到的是,在部署之后,API会正常工作一段时间,但在10-20分钟后,它会变得没有响应,甚至健康检查端点(它只返回一个硬编码的200 OK)也会停止工作并超时。(这会让Kubernetes杀死pods。)

有时我还会在日志中看到臭名昭著的Heartbeat took longer than "00:00:01"错误消息。

谷歌这些现象将我指向“线程匮乏”,因此启动了太多的线程池线程,或者有太多的线程正在阻塞等待某些东西,因此池中没有剩余的线程可以获取ASP.NET核心请求(因此,甚至健康检查端点都超时)。

解决此问题的最佳方法是什么?我开始监视ThreadPool.GetMaxThreadsThreadPool.GetAvailableThreads返回的数字,但它们保持不变(对于max和available,完成端口始终为1000,而worker始终为32767)。

是否有其他我应该监视的属性?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-05-02 07:15:21

你确定你的ASP.NET核心web应用线程数不足吗?它可能只是简单地饱和了所有可用的pod资源,导致Kubernetes只是杀死pod本身,因此您的web应用程序。

我确实经历了一个非常类似的场景,在OpenShift环境中运行在Linux上,它也支持ASP.NET中的pod概念:一个调用大约需要1秒才能完成,在大量工作负载下,它先是变慢,然后变得没有响应,导致OpenShift杀死pod,所以我的web应用程序也是如此。

这可能是您的ASP.NET核心web应用程序没有耗尽线程,特别是考虑到ThreadPool中可用的大量工作线程。相反,与它们正在运行的pod中实际可用的毫微库相比,活动线程的数量与它们所需的CPU数量相比可能太大了:实际上,在创建之后,这些活动线程对于可用CPU来说太多了,以至于它们中的大多数最终都被调度程序排队并等待执行,而实际上只有一堆线程会运行。然后,调度器完成它的工作,通过频繁地切换使用它的线程,确保CPU在线程之间公平共享。至于你的情况,线程需要繁重和长时间的CPU限制操作,随着时间的推移,资源会饱和,web应用程序会变得没有响应。

缓解措施可能是为您的pod提供更多容量,特别是毫级存储,或者根据需要增加Kubernetes可能部署的pod数量。然而,在我的特定场景中,这种方法没有太大帮助。相反,通过将一个请求的执行时间从1s减少到300ms来改进API本身,明智地提高了整体web应用程序的性能,并实际解决了问题。

例如,如果你的库在一个以上的请求中执行相同的计算,你可以考虑在你的数据结构上引入缓存,以便以少量的内存成本来提高速度(这对我来说是有效的),特别是如果你的操作主要是CPU限制的,如果你对你的web应用程序有这样的请求需求。您也可以考虑启用cache response in ASP.NET Core,如果这对于您的应用编程接口的工作负载和响应是有意义的。使用缓存,您可以确保您的web应用程序不会执行相同的任务两次,从而释放CPU并降低线程排队的风险。

更快地处理每个请求将使您的web应用程序不太容易充满可用CPU的风险,从而降低有太多线程排队和等待执行的风险。

票数 5
EN

Stack Overflow用户

发布于 2018-05-02 04:15:12

一般来说,长时间运行的工作对于web应用程序来说是一件令人厌恶的事情。你想要一个健康的web应用程序的亚秒级响应时间。如果您需要做的工作是同步的或受CPU限制的,这一点尤其正确。Async至少可以在进程期间释放线程,但是对于CPU受限的工作,线程是独占的。

你应该把你正在做的任何事情转移到一个不同的进程,然后监控进程。对于应用编程接口,这里的典型方法是在不同的进程上调度工作,然后立即返回一个202 Accepted,在响应主体中有一个端点,客户端可以利用它来监控进度/获取最终完成的结果。您还可以实现一个webhook,客户端可以注册它来接收进程已完成的通知,而不必不断地检查它。

你唯一的其他选择是投入更多的资源来解决这个问题。例如,您可以将多个实例放在负载均衡器后面,在每个实例之间分配请求,以减少每个实例上的总体负载。

完全有可能的是,您的代码中存在一些低效或问题,可以通过纠正这些问题来减少进程所需的时间和/或消耗的资源。举个简单的例子,假设你正在使用像Task.Run这样的东西,你可以通过不这样做来释放大量的线程。Task.Run几乎不应该在web应用程序的上下文中使用。但是,您还没有发布任何代码,因此不可能在那里给您提供准确的指导。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50120167

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档