将内存或进程或线程池资源限制到 spring 控制器

Limit memory or process or thread pool resources to a spring controller

我有 Spring 带有 3 个控制器的应用程序,每个都支持一些用例集,比如

SmallController - supports 1 usecase

MediumController - supports 3 usecases

LargeController - Supports 20 usecases

问题是,如果我最终收到 SmallController 的大量请求,比如说 1000 TPS,消耗了我 50-60% 的资源,它最终会耗尽我剩下的 23 个用例吗? 如果是这样,有没有一种方法可以配置我的 Spring 应用程序,使我发送到 SmallController 的请求激增不会为它分配 memory/threads 等超出特定预定义的资源值,以便 MediumControllerLargeController 不会开始挨饿?

基本上,如果我有 100 Mbs 的内存,假设有 100 个线程池限制,

是否可以防止 SmallController 超过 50 Mbs 的内存并说最多 40 个线程,同时保证 MediumControllerLargeController 的剩余资源?

如果根本没有现成的工具来控制资源的使用,有人可以建议一种可以探索的方法来开始构建一个吗?

Java 没有特定线程拥有的内存量的概念。内存由整个进程拥有。 运行 堆转储上的堆分析器可能允许您将分配归因于特定线程或线程池,但这是一种离线分析,无法在运行时廉价地执行。

因此,如果您想对资源进行分区,您应该启动多个应用程序并为每个应用程序设置资源限制。

我的建议是引入“节流”(Rate Limit)。 你可以有自己的实现或者你可以使用像 Buket4j 这样的东西 例如:https://www.baeldung.com/spring-bucket4j.

如果你不想污染控制器的源代码,你可以在 MVC 拦截器级别这样做(更干净的解决方案,在拦截器 preHandle 方法中处理)。

如果您想控制 SmallController 中的许可数,那么您可以尝试使用 Semaphore。请注意,这只是一个建议,如果这不符合要求,您可以探索其他选项。

@RestController
public class SmallController{

private Semaphore semaphore = new Semaphore(10);//no of calls allowed

@GetMapping("/someaction")
public ResponseEntity<T> action(){
  semaphore.acquire(); // this will block the request until permit is available. 
  try{ 
     //resource intensive operation
  }finally{
    semaphore.release();
  }
 // return response entity object
}

}

如果你想要非阻塞信号量,你可以使用semaphore.tryAcquire()。您可以检查它是否 returns false 然后回复说 'resource busy'

内存在运行时间级别,不是控制器级别。让我们备份。您想要管理资源以使应用程序仍然响应

即使可能,在应用程序级别执行此操作也会让您头疼。听起来您真的很想实施 API 使用计划。然后,您可以限制和/或拒绝使系统过载的请求,以保持系统响应。希望你有这种或另一种口味的(AWS APIGW、Kong 等)

否则,您可能需要考虑使用不同的配置文件部署您的应用程序,以便控制器 运行 在不同的盒子上隔离故障并保持应用程序响应,或者将其分解为单独的微服务。这应该会产生更好的性能,并使您能够扩展应用程序的各个部分。

我知道这些答案假设您有这些选项可用,希望您有。