写点什么

容器化 Java 程序秒级弹性伸缩实践

作者:HelloGeek
  • 2024-04-18
    河南
  • 本文字数:2215 字

    阅读完需:约 7 分钟

容器化Java程序秒级弹性伸缩实践

当前许多数字化转型企业都会将自己的系统微服务化、容器化,这些技术和策略可以帮助企业更有效地利用资源、提高开发运维效率,并且在处理不同流量场景下保证系统的稳定性和性能。

弹性扩缩容

在虚拟机时代,资源的占用和维护成本较高,因为承载容量是固定的,导致了大量资源的闲置。而在容器时代,借助开源的 Kubernetes 等方案,我们可以更灵活地利用资源,根据需要动态调整资源的分配。弹性伸缩涉及到的相关技术解决方案:HPA、无损上线、无损下线、秒级启动。

水平 Pod 自动伸缩(HAP Horizontal Pod Autoscaling)

apiVersion: autoscaling/v2beta2kind: HorizontalPodAutoscalermetadata:  name: your-java-app-hpaspec:  scaleTargetRef:    apiVersion: apps/v1    kind: Deployment    name: your-java-app  minReplicas: 1  maxReplicas: 10  metrics:    - type: Resource      resource:        name: cpu        targetAverageUtilization: 50
复制代码

上面的例子,是将 CPU 利用率配置为 50%,根据应用程序的负载情况,Kubernetes 将自动调整 Pod 的副本数,最小 1 个,最大 10 个 pod。除了 CPU,还可以使用内存和一些结合监控扩展的自定义指标。

通过 HPA 技术,不需要那么谨慎的为业务系统分配固定资源。比如之前的业务系统分配的 CPU 有为 4 核,但日常使用率仅 20%,那这时我们可以给他分配 2 核,理论上 CPU 使用率就提升到了 40%左右,当遇到 CPU 升高时可以通过扩容解决,这样能有效解决资源利用率使用过低问题。

无损上线

在小流量场景下,一般不会在调⽤时出现 Connection refused 和 No instance 等现象,但在流量高峰需要扩容时类似问题会比较明显。一般的解决方式是小流量预热。⼩流量预热⽅法主要是通过在服务消费端根据各个服务提供者实例的启动时间计算权重,结合负载均衡算法控制刚启动应⽤流量,随启动时间逐渐递增到正常⽔平,如下图所示。

将⾃身的预热时⻓和服务启动时长为参数,通过⼩流量服务预热模型计算公式进行权重流量分配,感兴趣的可以参考开源 Dubbo 的技术实现。

无损下线

虚机场景

虚机场景下的无损下线只需要注意服务下线时新流量不在进入已进入系统流量处理完毕,就能保证服务下线流量无损,具体步骤见下图。

• 主动注销我们应用服务下线前,主动通知注册中心注销该实例;

• 通知下线信息我们会在服务端实例下线前主动通知客户端,该服务节点下线的信息

• 调用其他提供者我们在客户端增强其负载均衡能力,在服务端下线后,客户端主动调用其他服务提供者节点。

容器场景

服务的启停不只是系统进程启停,涉及到 Pod 的生命周期,下面是一个 pod 的简单生命周期。

1. 新建 pod:通过 Kubernetes 调度器,调度到合适的服务器中,并准备所需的算力、存储和网络等基础资源;

2. 拉取业务系统镜像:拉取业务系统 Docker 镜像,拉取镜像的时间取决于网络、镜像大小和是否用到 P2P 加速镜像拉取技术;

3. 启动业务系统:启动业务服务进程,目前行内微服务采用的是基于 Java 语言的 Spring Cloud 微服务技术,为了提升开发效率,Spring Cloud 集成了大量的开源组件,加之业务系统代码及其所依赖的大量第三方组件,Web 容器启动时需要加载大量上述组件,并通过 Spring 维护其复杂的关联关系;

4. 启动健康检查:主要目的是确保 pod 健康,若业务应用配置为 1 分钟,则在容器启动 1 分钟后开始进行 Liveness 健康检查,如果探测连续超过一定的失败次数,Kubernetes 会认为服务不可用,pod 会被销毁并重建。在滚动发布场景下,当一个 pod 的 Liveness 探活成功后,才能开始下一个节点的发布,可以把健康检查-启动时间改为第 1 分钟(具体要结合各个业务系统自身的启动时间来定),增加每 30 秒探活一次,失败 3 次后重启(结合业务系统测试而定),这样可以缩短整个版本滚动发布时长。

5. 容器优雅终止:当接到删除 pod 命令时,Kubernetes 会给 pod 中容器一定的时间优雅停止,并触发 preStop 钩子执行微服务无损下线脚本(适用于配置有无损下线脚本微服务),实现流量无损下线。目前默认是 30 秒,设定时间越长越能保证流量完全无损下线,但整体滚动发版时间会被拉长,具体还需要根据业务自身情况设定;

6. 销毁 pod:Kubernetes 对算力、存储和网络等基础资源的释放。若应用配置固定 IP,销毁 pod 则需要约 8 秒。

所以在基于 Kubernetes 的容器场景下,关闭一个系统是关闭一个 pod,并且还需要在容器中添加钩子配置,调用系统优雅下线功能,需要注意的是容器最终宽限期 terminationGracePeriodPeriods 的时长大于优雅下线的时长,否则会被强制销毁。

提升启动速度

对于基于 Java 开发的业务系统,可以尝试使用:

  • 探索高版本 Spring Boot、JDK 等开源技术解决方案,调研 AppCDS、CRaC 等启动加速技术;

  • 探索平台框架启动速度提升方案,优化核心功能代码启动速度,支持组件按需加载;

  • 制定系统级优化启动速度技术规范,建设系统启动时间分析工具,指导业务系统进行代码优化,补齐应用启动生命周期的可观测能力;

  • 也可以尝试 Serverless 技术,将有潮汐场景的系统,改造为函数模式,可以进一步提升启动速度和资源利用率。

总结

数字化转型已成为企业提高效率和竞争力的重要途径。我们讨论了在微服务化和容器化过程中,利用弹性扩缩容技术提高资源利用率和开发运维效率的方法。通过水平 Pod 自动伸缩(HPA)、无损上线、无损下线和提升启动速度等技术,企业能够更灵活地应对不同的业务场景和需求,实现资源的最大化利用和系统的稳定性提升。


参考:


发布于: 刚刚阅读数: 6
用户头像

HelloGeek

关注

攻城攻城还需要一个师 2018-07-09 加入

混迹互联网多年,有一点心得,有一点体会。

评论

发布
暂无评论
容器化Java程序秒级弹性伸缩实践_Java_HelloGeek_InfoQ写作社区