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

Posted

技术标签:

【中文标题】将内存或进程或线程池资源限制到弹簧控制器【英文标题】:Limit memory or process or thread pool resources to a spring controller 【发布时间】:2021-09-08 07:25:24 【问题描述】:

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

SmallController - 支持 1 个用例

MediumController - 支持 3 个用例

LargeController - 支持 20 个用例

问题是,如果我最终收到大量对 SmallController 的请求,比如 1000 TPS,消耗了我 50-60% 的资源,它最终会不会让我剩下的 23 个用例挨饿? 如果是这样,有没有办法配置我的 Spring 应用程序,使我发送到SmallController 的请求激增不会为其分配超出某个预定义值的内存/线程等资源,以便MediumControllerLargeController不要开始挨饿?

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

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

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

【问题讨论】:

相关:***.com/q/61921122/5515060。本质上,为每个控制器创建一个具有不同数量可用线程的线程池。然后只需将请求分派到线程池 【参考方案1】:

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

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

【讨论】:

所以基本上我不想限制我的内存资源用于一个特定的线程,而是限制特定弹簧控制器的线程数。可能是我错误地提出了这个问题吗?【参考方案2】:

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

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

【讨论】:

有趣,虽然我确实考虑过,但问题是如果请求仅针对特定控制器进行限制,是否可以针对特定控制器完成此操作。但更大的问题是,bucket4j 可能无法使用。是否有 Spring 或 Apache 或 Google 提供的类似库? 是的,它可以针对特定的控制器进行,这意味着不同控制器的速率限制不同(甚至某些控制器没有速率限制)。 bucket4j 是一个很小的库,如果你的产品不允许使用它,我相信也可以有一些其他的库(例如:Kite),或者你甚至可以在学习了这些算法之后编写自己的库已实施。【参考方案3】:

如果您想控制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()。您可以检查它是否返回 false 然后回复说“资源忙”

【讨论】:

【参考方案4】:

内存处于运行时级别,而不是控制器级别。让我们备份。您想管理资源以使应用仍能响应

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

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

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

【讨论】:

以上是关于将内存或进程或线程池资源限制到弹簧控制器的主要内容,如果未能解决你的问题,请参考以下文章

Linux最大线程数限制及当前线程数查询

是否存在ManagedExecutorService队列限制?

线程池与ForkJoin框架

线程池相关知识点

Docker 限制容器资源

java 创建线程池的4中方式