如何正确管理 Kubernetes 中的 Java Spring 应用程序自动缩放?

Daw*_*wel 5 java spring jvm autoscaling kubernetes

我正在尝试在 Kubernetes(托管在 Google Kubernetes Engine 中)中为我的 Java Spring 应用程序设置自动缩放。我遇到了两个问题:

  1. Spring 应用程序在启动时使用大量 cpu(类似于 250mCPU*,但有时甚至是 500mCPU),这确实破坏了自动缩放,因为该应用程序的某些实例在或多或少不到 1 分钟后(Spring 上下文启动等),仅使用50mCPU。因为在某些环境下,应用程序使用少量的 mCPU(几乎在晚上的每个环境中),我想设置请求的 cpu=200mCPU max(= 80% 限制 cpu)(甚至更少!)。那么自动缩放就更有意义了。但我真的不能这么做,因为 Spring 的启动很繁重,如果我给他的 cpu 太少,它就不会完成。

  2. 当应用程序开始接收流量时(当由于自动缩放事件而创建新的 Pod 时),其 CPU 使用率可能会跳到标准使用率的 200% 之类的水平,然后又回到 100% - 看起来并不是因为太多的请求被推送到新的 pod,看起来更像是 JVM 在开始时速度较慢,并且在请求时收到了太多流量。看起来 JVM 需要诸如预热之类的东西(所以不要突然将 1/n 的流量推送到新 pod,而是将流量切换到新 pod 的速度更慢)。由于这种行为,自动缩放有时会变得疯狂 - 当它确实只需要多一个 Pod 时,它可以放大很多 Pod,然后缩小......

* 在 GKE 1000mCPU 中 = 1 个核心

在上传的图像上我们可以看到 cpu 图表。首先,我们可以看到启动后的cpu使用率比开始时要小得多。在第二个中,我们可以发现两个问题:开始时 CPU 使用率较高,然后是宽限期(就绪探测初始*延迟尚未完成),然后在接收流量开始时出现高选择。

* 我已将就绪探针初始延迟设置为比上下文加载更长。

图1 图2

我在互联网上找到的唯一一件事就是向该 Pod 添加容器,这只会“睡眠 x”,然后死掉。并将设置添加到该容器请求的 mCPU 数量,该数量将在 Spring 应用程序启动时使用(然后我必须增加该 Spring 应用程序容器的 cpu 限制,但无论如何它不应该造成损害,因为自动缩放应该防止 Spring 应用程序让其他应用程序挨饿)节点中的应用程序)。

我真的很感激任何建议。

Uro*_* T. 0

确实,Spring 应用程序并不是最适合容器的应用程序,但您可以尝试以下几种方法:

  1. 启动时,Spring 自动装配 bean 并执行依赖注入、在内存中创建对象等。所有这些都是 CPU 密集型的。如果为 Pod 分配较少的 CPU,从逻辑上讲,它会增加启动时间。您可以在这里做的事情有:
  • 使用 astartupProbe并给您的应用程序启动时间。这里很好地解释了如何计算延迟和阈值

  • 调整您的部署策略中的maxSurgemaxUnavailable,使其最适合您的情况(例如,您可能有 10 个副本,最大激增/最大不可用率为 10%,因此您的 pod 将一一缓慢地推出)。这将有助于减少整个应用程序副本上的流量峰值(文档位于此处)。

  • 如果您的用例允许,您可以考虑延迟加载 Spring 应用程序,这意味着它不会在启动时创建所有对象,而是会等到它们被使用为止。这可能有些危险,因为在某些情况下可能无法在启动时发现问题。

  1. 如果您在部署中启用了 HPA + 定义的replicas值,则在部署时可能会遇到问题,我找不到相关的 GH 问题 ATM,但您可能希望在那里运行一些测试来了解其行为(扩展超出应有的范围等) )。您可以在这里做的事情有:
  • 调整自动缩放阈值和时间(默认为 3 分钟,据我所知),以允许您的部署顺利推出而不会触发自动缩放。

  • 编写自定义自动缩放指标,而不是按 CPU 进行缩放。这需要一些工作,但可能会永久解决您的扩展问题(相关文档)。

最后,你所建议的边车看起来像是一个黑客:)虽然还没有尝试过,所以不能真正说出优点和缺点。

不幸的是,Spring Boot(或 Java)+ K8s 没有灵丹妙药,但情况比几年前要好得多。如果我找到一些有用的资源。我会回来并在这里链接它们。

希望以上内容有所帮助。

干杯