如何在 Linux (Kubernetes) 上解决 ASP.NET Core 中的线程不足问题



我在 Linux 上运行一个 ASP.NET Core API,在 Google Cloud 中的 Kubernetes 上运行。

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

我看到的是,部署后 API 可以正常工作一段时间,但在 10-20 分钟后它变得无响应,甚至运行状况检查端点(仅返回硬编码200 OK)也停止工作并超时。(这使得 Kubernetes 杀死了 pod。

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

谷歌搜索这些现象将我指向"线程饥饿",因此启动了太多线程池线程,或者太多线程阻塞了等待某些内容,因此池中没有线程可以拾取 ASP.NET Core请求(因此甚至运行状况检查端点超时)。

解决此问题的最佳方法是什么?我开始监视ThreadPool.GetMaxThreadsThreadPool.GetAvailableThreads返回的数字,但它们保持不变(完成端口始终1000max 和可用,并且工作线程始终32767)。
还有其他我应该监控的属性吗?

一般来说,长时间运行的工作对于 Web 应用程序来说是令人厌恶的。你需要正常运行的 Web 应用的亚秒级响应时间。如果您需要执行的工作是同步的或 CPU 密集型的,则尤其如此。异步至少可以在过程中释放线程,但是对于 CPU 密集型工作,线程是

捆绑的。您应该将正在执行的操作卸载到其他流程,然后监视进度。对于 API,这里的典型方法是将工作安排在不同的进程上,然后立即返回 202 Accepted,并在响应正文中有一个终结点,客户端可以利用该终结点来监视进度/获取最终完成的结果。您还可以实现一个 webhook,客户端可以注册该钩子以接收进程已完成的通知,而无需不断检查它。

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

也完全有可能代码中存在一些效率低下或问题,可以纠正这些问题,以减少流程花费的时间和/或消耗的资源。举个简单的例子,假设你正在使用类似Task.Run的东西,如果不这样做,你可能会释放大量的线程。Task.Run几乎不应该在 Web 应用程序的上下文中使用。但是,您尚未发布任何代码,因此无法在那里为您提供确切的指导。

你确定你的 ASP.NET Core Web 应用线程用完了吗?可能它只是使所有可用的 pod 资源饱和,导致 Kubernetes 只是杀死 pod 本身,因此您的 Web 应用程序。

我确实遇到过一个非常类似的场景,在 OpenShift 环境中的 Linux RedHat 上运行 ASP.NET Core Web API,它也支持 pod 概念,就像在 Kubernetes 中一样:一个调用大约需要 1 秒才能完成,在大工作负载下,它首先变慢,然后没有响应,导致 OpenShift 杀死 pod, 所以我的网络应用程序也是如此。

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

缓解步骤可能是为您的 Pod 提供更多容量,尤其是毫核,或者增加 Kubernetes 可以根据需要部署的 Pod 数量。 但是,在我的特定情况下,这种方法并没有多大帮助。 相反,通过将一个请求的执行从 1 秒减少到 300 毫秒来改进 API 本身,明智地提高了整体 Web 应用程序性能并实际解决了这个问题。

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

更快地处理每个请求将使 Web 应用不易出现填满可用 CPU 的风险,从而降低过多线程排队等待执行的风险。

最新更新