基于JVM堆内存的Kubernetes HPA

Man*_*har 3 garbage-collection jvm kubernetes

我有一个在 Kubernetes 集群上运行的 openjdk:8 映像。我添加了内存 HPA(Horizo​​ntal Pod Autoscaling),它可以很好地扩展,但由于 JVM 不会将内存从堆释放回操作系统,因此 Pod 不会缩小规模。以下是 hpa.yaml

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: image-server
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: image-server
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 60
Run Code Online (Sandbox Code Playgroud)

解决此问题的一种方法是使用正确的 GC 并使其释放内存,但由于 JVM 出于性能原因设计为不会频繁地从堆中释放内存,因此这样做并不是一个好主意。Kubernetes 有办法处理这个问题吗?就像不检查操作系统的内存使用情况一样,我们是否可以只检查堆和缩放中的内存使用情况?

dan*_*orn 8

在 Kubernetes 中扩展 Java 应用程序有点棘手。HPA 仅查看系统内存,正如所指出的,JVM 通常不会释放已提交的堆空间(至少不会立即释放)。

\n

有两种主要方法可以解决这个问题

\n

1. 调整 JVM 参数,使提交堆更紧密地跟随已用堆

\n

根据使用的 JVM 和 GC,调整选项可能略有不同,但最重要的是

\n
    \n
  • MaxHeapFreeRatio- 允许未使用的提交堆的数量
  • \n
  • GCTimeRatio- 允许 GC 运行的频率(影响性能)
  • \n
  • AdaptiveSizePolicyWeight- 在计算新堆时如何权衡较旧的 GC 运行与较新的 GC 运行
  • \n
\n

给出这些的准确值并不容易,这是快速释放内存和应用程序性能之间的折衷。最佳设置将取决于应用程序的负载特性。

\n

Patrick Dillon 撰写了 RedHat 发表的一篇名为“扩展 Java 容器”的文章,深入探讨了这个主题。

\n

2. 自定义缩放逻辑

\n

您可以创建自己的扩展逻辑,并将其作为定期运行的作业部署到 Kubernetes 中,以执行以下操作,而不是使用 HPA:

\n
    \n
  1. 检查所有 pod 中的堆使用情况(例如通过在 pod 内运行 jstat)
  2. \n
  3. 如果达到最大阈值,则横向扩展新的 Pod
  4. \n
  5. 如果达到最小阈值,则在 pod 中进行扩展
  6. \n
\n

这种方法的优点是可以查看实际的堆使用情况,但需要自定义组件。

\n

可以在 powercloudup 的文章Autoscaling based on CPU/Memory in Kubernetes \xe2\x80\x94 Part II中找到这方面的示例

\n