关于java:改善-Kubernetes-上的-JVM-预热问题

0次阅读

共计 3629 个字符,预计需要花费 10 分钟才能阅读完成。

作者:Vikas Kumar

翻译:Bach(才云)

校对:木子(才云)

JVM 预热是一个十分头疼而又难解决的问题。基于 JVM 的应用程序在达到最高性能之前,须要一些工夫来“预热”。当应用程序启动时,通常会从较低的性能开始。这归因于像即时(JIT)编译这些事儿,它会通过收集应用配置文件信息来优化罕用代码。最终这样的负面影响是,与平均水平相比,预热期间接管的 request 将具备十分高的响应工夫。在容器化、高吞吐量、频繁部署和主动伸缩的环境中,这个问题可能会加剧。

在这篇文章中,咱们将探讨 在运行在 Kubernetes 集群中的 Java 服务如何解决 JVM 预热问题的教训

起因

几年前,咱们逐渐从整体中拆散出服务,开始在 Kubernetes 上进行迁徙到基于微服务的体系结构。大多数新服务都是在 Java 中开发的。当咱们在印度市场上运行一个这样的服务时,咱们第一次遇到了这个问题。咱们通过负载测试进行了通常的容量布局过程,并确定 N 个 Pod 足以解决超过预期的峰值流量。

只管该服务在轻松解决顶峰流量,但咱们在部署过程中发现了问题。咱们的每个 Pod 在顶峰工夫解决的 RPM 都超过 10k,而咱们应用的是 Kubernetes 滚动更新机制。在部署过程中,服务的响应工夫会激增几分钟,而后再稳固到通常的稳固状态。在咱们的仪表板中,会看到相似的图表:

与此同时,咱们开始收到来自部署时间段内的大量投诉,简直都对于高响应工夫和超时谬误。

第一步:花钱解决问题

咱们很快意识到这个问题与 JVM 预热阶段无关,但过后有其余的重要事件,因而咱们没有太多工夫进行考察,间接尝试了 最简略的解决方案——减少 Pod 数量,以缩小每个 Pod 的吞吐量。咱们将 Pod 数量减少了近三倍,以便每个 Pod 在峰值解决约 4k RPM 的吞吐量。咱们还调整了部署策略,以确保一次最多滚动更新 25%(应用 maxSurgemaxUnavailable 参数)。这样就解决了问题,只管咱们的运行容量是稳固状态所需容量的 3 倍,但咱们可能在咱们的服务中或任何相干服务中没有问题地进行部署。

随着前面几个月里更多的迁徙服务,咱们开始在其余服务中经常看到这个问题。因而咱们决定花一些工夫来考察这个问题并找到更好的解决方案。

第二步:预热脚本

在仔细阅读了各种文章后,咱们决定尝试一下预热脚本。咱们的想法是 运行一个预热脚本,向服务发送几分钟的综合申请,来实现 JVM 预热,而后再容许理论流量通过

为了创立预热脚本,咱们从生产流量中抓取了理论的 URL。而后,咱们创立了一个 Python 脚本,应用这些 URL 发送并行申请。咱们相应地配置了 readiness 探针的 initialDelaySeconds,以确保预热脚本在 Pod 为 ready 并开始承受流量之前实现。

令人吃惊的是,只管后果有一些改良,但并不显著。咱们依然常常察看到高响应工夫和谬误。此外,预热脚本还带来了新的问题。之前,Pod 能够在 40-50 秒内准备就绪,但用了脚本,它们大概须要 3 分钟,这在部署期间成为了一个问题,更别说在主动伸缩期间。咱们在预热机制上做了一些调整,比方容许预热脚本和理论流量有一个短暂的重叠期,但也没有看到显著的改良。最初,咱们认为预热脚本的收益太小了,决定放弃。

第三步:启发式发现

因为预热脚本想法失败了,咱们决定尝试一些启发式技术 -

  • GC(G1、CMS 和 并行)和各种 GC 参数
  • 堆内存
  • CPU 调配

通过几轮试验,咱们终于获得了冲破。测试的服务配置了 Kubernetes 资源 limits:

咱们将 CPU request 和 limit 减少到 2000m,并部署服务以查看影响,能够看到响应工夫和谬误有了微小的改良,比预热脚本好得多。

第一个 Deployment(大概下午 1 点)应用 2 个 CPU 配置,第二个 Deployment(大概下午 1:25)应用原来 1 个 CPU 配置

为了进一步测试,咱们将配置降级到 3000m CPU,令咱们诧异的是,问题齐全隐没了。正如上面看到的,响应工夫没有峰值。

具备 3 个 CPU 配置的 Deployment

很快,咱们就发现问题出在 CPU 节流上。在预热阶段,JVM 须要比均匀稳固状态下更多的 CPU 工夫,但 Kubernetes 资源解决机制(CGroup)依据配置的 limits,从而限度了 CPU。

有一个简略的办法能够验证这一点。Kubernetes 公开了一个每个 Pod 的指标,container_cpu_cfs_throttled_seconds_total 示意这个 Pod 从开始到当初限度了多少秒 CPU。如果咱们用 1000m 配置察看这个指标,应该会在开始时看到很多节流,而后在几分钟后稳定下来。咱们应用该配置进行了部署,这是 Prometheus 中所有 Pod 的 container_cpu_cfs_throttled_seconds_total 图:

正如预期,在容器启动的前 5 到 7 分钟有很多节流,大部分在 500 秒到 1000 秒之间,而后稳定下来,这证实了咱们的假如。

当咱们应用 3000m CPU 配置进行部署时,察看到下图:

CPU 节流简直能够忽略不计(简直所有 Pod 都不到 4 秒)。

第四步:改良

只管咱们发现了这个问题的基本,但就老本而言,该解决方案并不太现实。因为有这个问题的大多数服务都曾经有相似的资源配置,并且在 Pod 数量上超额配置,以防止部署失败,然而没有一个团队有将 CPU 的 request、limits 增加三倍并相应缩小 Pod 数量的想法。这种解决方案实际上可能比运行更多的 Pod 更蹩脚,因为 Kubernetes 会依据 request 调度 Pod,找到具备 3 个闲暇 CPU 容量的节点比找到具备 1 个闲暇 CPU 的节点要艰难得多。它可能导致集群主动伸缩器频繁触发,从而向集群增加更多节点。

咱们又回到了原点 然而这次有了一些新的重要信息。当初问题是这样的:

在最后的预热阶段(继续几分钟),JVM 须要比配置的 limits(1000m)更多的 CPU(大概 3000m)。预热后,即便 CPU limits 为 1000m,JVM 也能够充分发挥其后劲。Kubernetes 会应用 request 而不是 limits 来调度 Pod。咱们分明地理解问题后,答案就呈现了——Kubernetes Burstable QoS。

Kubernetes 依据配置的资源 request 和 limits 将 QoS 类调配给 Pod。

到目前为止,咱们始终在通过指定具备相等值的 request 和 limits(最后是 1000m,而后是 3000m)来应用 Guaranteed QoS。只管 Guaranteed QoS 有它的益处,但咱们不须要在整个 Pod 生命周期中独占 3 个 CPU,咱们只须要在最后的几分钟内应用它。Burstable QoS 容许咱们指定小于 limits 的 request,例如:

因为 Kubernetes 应用 request 中指定的值来调度 Pod,它会找到具备 1000m CPU 容量的节点来调度这个 Pod。然而因为 3000m 的 limits 要高得多,如果应用程序在任何时候都须要超过 1000m 的 CPU,并且该节点上有闲暇的 CPU 容量,那么就不会在 CPU 上限度应用程序。如果可用,它最多能够应用 3000m。

这十分合乎咱们的问题。在预热阶段,当 JVM 须要更多的 CPU 时,它能够获取须要的 CPU。JVM 被优化后,能够在 request 范畴内全速运行。这容许咱们应用集群中的冗余的资源(足够可用时)来解决预热问题,而不须要任何额定的老本。

最初,进行假如测试。咱们更改了资源配置并部署了应用程序,胜利了!咱们做了更多的测试以验证后果统一。此外,咱们监控了 container_cpu_cfs_throttled_seconds_total 指标,以下是其中一个 Deployment 的图表:

正如咱们所看到的,这张图与 3000m CPU 的 Guaranteed QoS 设置十分类似。节流简直能够忽略不计,它证实了具备 Burstable QoS 的解决方案是无效的。

为了使 Burstable QoS 解决方案失常工作,节点上须要有可用的冗余资源。这能够通过两种形式验证:

  • 就 CPU 而言,节点资源未齐全耗尽;
  • 工作负载未应用 request 的 100% CPU。

论断

只管花了一些工夫,最终找到了一个老本效益高的解决方案。Kubernetes 资源限度是一个重要的概念。咱们在所有基于 Java 的服务中实现了该解决方案,部署和主动扩大都运行良好,没有任何问题。

要点:

  • 在为应用程序设置资源限度时要认真思考。花些工夫理解应用程序的工作负载并相应地设置 request 和 limits。理解设置资源限度和各种 QoS 类的含意。
  • 通过 monitoring/alertingcontainer_cpu_cfs_throttled_seconds_total 来关注 CPU 节流。如果察看到过多的节流,能够调整资源限度。
  • 应用 Burstable QoS 时,确保在 request 中指定了稳固状态所需的容量。

原文链接:https://tech.olx.com/improvin…

正文完
 0