写点什么

核心大应用发布效率提升 70%,宿主机容器先缩后扩模型分享

  • 2024-12-25
    北京
  • 本文字数:5459 字

    阅读完需:约 18 分钟

核心大应用发布效率提升70%,宿主机容器先缩后扩模型分享

1.背景

2023 年疫情过后旅游行业复苏,业务量迎来爆发式增长。然而业务同学遇到了一个发布效率的难题:激增的业务需求导致核心大应用的发布时长大幅度增加,对用户的工作效率产生了严重影响。为了解决这个用户痛点,我们经过多次调研、测试摸索出了一种有效的解决方案:

  • 通过纵向扩容 pod 实例、实现每个 pod 独占一个物理机,不仅成功降低了发布时间,也避免了在高峰期被驱逐的问题,从而大幅提升了发布过程的稳定性和发布效率。

  • 此外,我们还调整了发布模型,从先扩后缩转变为先缩后扩,使得我们不再需要额外的物理机作为发布使用的资源 buffer,节省了机器资源成本。

经过这样的改造和优化,我们成功地解决了业务核心应用的发布效率和成本问题。

2. 问题分析

2.1 问题现象

随着业务量的增长,核心应用实例数增长 200%,经常遇到发布总时长翻倍的问题,从原来的每次发布 1 个小时以内到 2 个小时,严重影响了需求交付效率。这种大应用在高峰期发布还伴随 2 个现象:

  • 上下游接口超时:随着实例数的增加,应用的上下游抖动加大,导致接口超时。例如,应用的 zk 元数据信息增长了 70%,使得在发布时消费者同步信息量过大,从而导致服务不稳定。

  • 依赖资源池打满:高峰期发布很容易把 redis、mysql 等资源连接数打满,导致服务异常。

为了规避这些风险,业务同学增加了发布过程的批次数来降低并发量,如从 5 个批次增加到 10 个批次。在理想情况下,10 个批次的发布时长最多需要 1 个小时,但在高峰期间,我们经常会遇到批次内 pod 交付失败的场景,然后用户通过失败重试来解决,这个过程可能会多花费大约 5 分钟时间。如果多个批次都遇到这种情况,发布的总时长就会增加近一个小时。

为了解决上述问题,我们需要厘清两个问题点:一是为什么高峰期发布批次内 pod 经常失败、失败后重试为什么多花费 5 分钟; 二是扩容后有没有可能不增加批次来降低发布总时长。下面我们会逐个问题进行分析:

2.2 分析

问题点 1:为什么高峰期批次内的 pod 经常失败、并且失败重试需要多花 5 分钟?

首先我们先看下单个 pod 上线流程, pod 从创建到上线并接入流量大致经过以下五个阶段:

  • k8s 调度:此阶段耗时约在秒级。为优化此阶段,我们采用了业界通用的 DragonFly + Harbor 方案进行镜像预热,并使用 P2P 方式实现镜像的快速拉取。经过测试,我们发现即使在业务高峰期,k8s 调度的时长最多也在 10 秒左右,平均值大约 2 秒。

  • 数据库授权:该阶段耗时在毫秒级。主要是在 init 容器中实现的,通过调用授权平台接口对应用所依赖的数据库进行 ip 授权。目前,此阶段的成功率接近 100%。

  • 应用启动:此阶段耗时约 2-3 分钟。主要涉及到 Spring + Tomcat 的启动,这部分的消耗主要与业务加载的类数量和初始化数据有关,优化空间相对较小。

  • 应用预热:耗时约在 2-3 分钟。主要包括预加载业务数据和提高上线后的吞吐能力。

  • 应用上线:耗时在秒级别。应用预热成功后,开始接入线上流量。

通过分析核心大应用的失败案例,我们发现绝大多数的失败都发生在预热阶段。当 pod 发生失败时,同一批次中的其他 pod 往往已经上线,因此,批次的额外时间耗费就是一个新 pod 从创建到上线的总时间,约为 5 分钟。这就是导致批次发布时间增加的主要原因。关于 pod 失败的原因,我们总结出两点:

  1. 高并发情况下,预热接口失败或超时。这个问题我们已经进行了优化处理,目前已经被解决。

  2. 预热阶段负载过高导致被 k8s 驱逐。尽管我们已经对核心应用做了 QoS 调整,以及亲和性和反亲和性调度到高配宿主机等策略,但由于高峰期集群的总体负载较大,这些措施的影响并不显著。

这个问题的最终方案需要我们进一步研究 k8s 的驱逐策略。目前 k8s 宿主机都是共享模式使用的,多个应用会共享一个宿主的资源。这就导致在负载过高时,pod 可能会被驱逐。我们也考虑过使用独占的模式,即一台物理机只运行一个 pod,但是这样会使得资源成本大大浪费。目前我们支持单个 pod 的内存规格最大为 12G,而宿主机的最小内存为 256G。因此,精细化资源分配和调度策略以解决驱逐问题就显得至关重要。

问题点 2:系统扩容后发布批次数是否可以不变或者减少?

在大部分业务场景中,我们通常通过增加实例来实现系统的横向扩容,进而提高性能。然而,随着实例数量的增长,我们常面临的挑战是发布过程的抖动以及数据库(如 MySQL、Redis)连接数达到上限,这迫使我们调整发布的批次数量,但这个方法并非最理想的解决方案。另一方面,一些特定的业务场景中,随着业务量的扩大,系统性能的瓶颈可以发生转移。例如,在某核心业务中,业务流量不断增大,扩容后性能没有任何提升。经过调研和测试,发现使用高配置的物理机器来部署应用实例可以解决性能瓶颈。通过部署高配置的物理机器,我们能够显著地减少需要运行的实例总数,从而相应地降低了发布批次。这在提升发布效率方面,取得了相当显著的成效。

2.3 解决思路

经过多轮压测、论证物理机以容器方式部署是可以解决特殊场景的性能问题与发布效率问题,另外独占机器的方式也解决了高峰期 pod 被驱逐的问题,保证了发布过程的稳定性,从而从整体上保证了发布效率。

3.部署物理机容器模型的方案选型

验证了物理机部署的成功性以后,接下来的挑战就是如何有效地执行部署。为了满足扩容速度和成本的要求,我们跟业务团队和运维团队讨论了以下几种方案:



方案介绍:

1)KVM 部署

  • 优点:没有额外的开发成本,可以直接复用现有的 KVM 部署流程,开发上线速度最快。

  • 劣势:扩容相对较慢,需要经过物理机审批流程。在流量突增的情况下,它无法像 HPA 那样快速扩容,不能充分利用公有云的弹性能力。

2)容器部署 - 先扩后缩

  • 优点:直接复用现有的容器部署流程,上线速度快,发布和回滚效率高。

  • 劣势:资源成本较高,需要预留一部分物理机作为发布缓冲。在高峰期间,如果批次设置不合理,可能会引发服务抖动、接口超时等问题。

3)容器部署 - 先缩后扩

  • 优点:HPA 能利用公有云的弹性能力,可以解决流量突增问题,同时也可以解决资源成本问题。

  • 劣势:有额外的开发成本,上线速度相比于其他方案来说较慢。

4)临时方案 - Argo CD 半自动部署

  • 优点:上线速度快。

  • 劣势:需要业务同学学习新的操作方式,且没有发布系统的一击回滚等功能,存在操作风险。

综合讨论后,我们决定先采用 Argo CD 作为临时方案优先解决业务问题,同时发布平台支持容器的"先缩后扩"模式。待先缩后扩模式上线后,逐步淘汰 Argo CD。

4.先缩后扩模型方案调研

决定支持先缩后扩的模式后,我们开始调研业界多个开源方案,包括 ArgoCD、Argo Rollout、Kruise 以及 Kruise Rollout。我们关注的主要功能点是:

  • 开源是否有先缩后扩的应用场景以及可供参考的方案。

  • 了解开源实现中的风险点以及兜底策略。

  • 开发方案和我们发布平台现有功能的适配度。

针对以上的关注点,我们对各开源方案进行对比分析:



方案简介:

1)现有方案-双 deployment:

优势:

  • 过程简单明了:新版本 deployment 扩容、旧版本 deployment 缩容。

  • 控制性强:可以精确控制发布过程每一个步骤、并可以终止。

  • 实现先缩后扩成本低

劣势:

  • 复杂性管理:当应用操作复杂、多次发布终止、和回滚时,容器数量会有膨胀、2 个 deployment 控制会比较复杂。

特点

  • 灵活、安全性高:可以在不影响旧版本的情况下对新版本进行操作。

2) Kruise Rollout 

优势:

  • 是由 OpenKruise 提供的 Kubernetes 原生应用交付解决方案。

  • 支持多种应用升级策略,包括蓝绿部署、金丝雀发布等。

  • 可以与 Kubernetes 生态系统无缝集成,并且可以很好地支持现有的 Deployment、StatefulSet 等工作负载资源。

劣势:

  • 相对于 Argo Rollouts 和 KubeVela,社区活跃度相对低一些。

  • 集中于滚动更新策略,功能范围可能没有 KubeVela 那么广泛。

 特点:

  • 专注于为 Kubernetes 应用提供高级滚动更新方案。

3) Argo Rollouts

优势:

  • 提供 Kubernetes 原生的渐进式交付策略,包括蓝绿部署和金丝雀发布。

  • Argo Rollouts 非常适合与 Argo CD 配合使用,实现 GitOps 工作流程。

  • 可视化和 CLI 工具辅助,增强了使用体验。

劣势:

  • 主要聚焦于提供渐进式交付特性,并不是一个全方位的应用交付平台。

  • 如果不使用 GitOps 或 Argo 生态以外的工具,整合起来可能需要额外工作。

特点:

  • 支持复杂的部署策略和与其它 Argo 项目的集成。

4) KubeVela

优势:

  • 提供一个高度扩展的应用平台,涵盖声明式 API、应用部署、运维特征绑定等。

  • 基于 OAM,提供了一个更高层次的抽象,使得开发人员不需要关心 Kubernetes 的复杂性。

  • 开发者友好,可以直接在应用描述中集成运维功能,如自动扩缩容、灰度发布等,而无需改动 Kubernetes 原生的资源对象。

  • 支持各类发布策略、金丝雀、蓝绿、先缩后扩、先扩后缩等,先缩后扩这个特性是我们关注的,借鉴它的思路并少踩一些坑。

劣势:

  • 对于那些只是想要在 Kubernetes 中实现简单的纯滚动更新的团队来说,可能有些过于复杂。

  • 需要一定的学习曲线去理解和利用 OAM 模型。

特点:

  • 一站式应用部署和管理解决方案,强调开发者体验和应用全生命周期管理。对于没有历史包袱的应用非常适合使用,成熟度非常高。

调研后发现,先缩后扩模式 KubeVela 社区已经有使用的了,因此可以参考借鉴它的思路,减少踩坑的风险。不过具体实现还是基于当前架构的双 deployment 来做,预估总的人力成本为 23 人天。

5. 先缩后扩模型设计关键点

可用实例数是业务和我们都关注的重要指标,在发布前、发布中、发布后的三个阶段,业务同学都会重点关注这个指标。如果可用实例数过低,我们会及时发出告警并在发布过程中及时终止,以降低风险。

发布前阶段:

  1. 校验发布批次数,必须大于 1 如果批次数为 1,在发布完一批次后,线上可用的实例将会直接降为 0,导致服务故障,这是业务不能接受的。因此,批次数必须大于 1,具体的批次数应根据实际业务压测后的容量评估结果设定。

  2. 校验缩容一批实例后的可用实例数例如,在线上有 4 个实例时,我们分两批发布。如果在发布中有 2 个实例因为 oom 在重启,若此时发布的第一批是现有的 2 个可用实例,那么发布后可能会导致服务故障。因此,在发布前需要提前校验缩容后的可用实例数。如果可用实例为 0,我们则需立刻终止发布,并发出提醒。

发布中阶段

  1. 在执行每个发布批次的缩容操作前,先提前计算缩容后的 upstream 实例数量以做判断,防止缩容后流量网关 upstream 列表为空造成故障。

  2. 在每个发布批次扩容后,需要检测扩容后的实例是否成功更新到流量网关中,如果没有更新成功,则直接中断发布,并提醒可能涉及的用户快速介入排查。

  3. 针对缩容、删除 deployment 等操作的底层可用性防护拦截。每次进行缩容操作和发布成功后删除旧 deployment 的操作,底层都会校验当前应用可用实例的数量。如果实例的可用比例低于阈值 50%,则立刻终止此操作。



发布后阶段

使用 pod_ready_total 指标实时监控线上可用实例的比例

该指标是实时生效的,当在线上可用实例数低于总数的一半时,将立刻通过消息通知用户,并同时电话周知应用的负责人。

  通知消息如下:



6.实践中的挑战以及解决方案

尽管我们在设计过程中已经考虑到了很多要素,但在实践中仍然遇到了一些挑战,甚至出现了 P1 级别的故障。

1. 先扩后缩改为先缩后扩导致调度失败

  • 问题:我们发现,先扩后缩的策略在调度资源上没有问题,因为在扩容过程中有足够的资源供新的实例使用。然而在先缩后扩的策略下,即使我们成功完成了缩容,资源并未立即释放。此时扩容操作可能因为资源不足而无法进行,导致发布过程卡住。

  • 解决方案:我们在缩容后会进行 pod 的检查,查看资源是否已经释放。只有在资源成功释放之后,才会继续下一步的扩容。如果资源释放超时(默认设置为 1 分钟),则系统会进行强制删除,以保证发布的顺畅进行。

2. 高峰期先缩后扩导致系统容量不足引发故障

  • 问题:我们的 HPA(水平 Pod 自动扩容) 是基于单一 deployment 配置的,因此当两个 deployment 同时存在时,HPA 将不能做出正确的决策。因此在发布期间,我们通常会关闭 HPA,并在发布成功后重新开启。然而在业务高峰期间,系统在进行缩容和扩容的过程中可能会出现容量不足的问题。在扩容后新启动的实例由于 Java JIT 的因素处理能力有限,导致系统容量达到危险水位,而接下来的一轮缩容使得整个系统无法正常处理业务,造成了故障。

  • 解决方案:为了解决这个问题,我们提出了以下解决方案:

  • 将核心大应用拆分为多个环境,并按环境发布。这种方式可以保证在发布期间总有一个环境的 HPA 是处于激活状态,能够实时感知系统流量变化进行扩容。

  • 在发布前对流量和系统容量进行评估,推荐合理的发布批次数。在系统容量有风险的情况下,应增加批次数,使发布过程更为稳定。

  • 考虑在发布过程中开启单环境下双 deployment 的 HPA,以研究其可行性。

7.效果数据

我们的方法在实践中取得了显著的效果,具体表现在以下三个方面:

发布效率

核心业务的 11 个核心大应用在发布和回滚的效率上提升了 70%。

资源成本

核心大应用 CPU 节省了 32.5%。

周边系统压力

核心大应用的实例数减少了一个数量级,降低了发布过程中上下游依赖的压力,发布过程中的系统指标平稳了很多。

8.总结与展望

本文详细分析了 Qunar 核心大应用在业务高峰期发布时长翻倍、影响研发效率的痛点问题,并通过一系列问题分析探索出一个可行的解决方案:即采用先缩后扩的发布策略,以及采用单一容器物理机部署来提高发布效率和优化资源使用。在实践中,此种策略虽然解决了发布效率问题,但也暴露出发布期间系统容量评估不足的风险。

为了彻底解决发布过程中的应用稳定性隐患,我们计划下半年做几个优化改进:

  1. 发布管家:负责发布期间的风险评估与提示,如果发布过程有问题及时终止发布。其中风险评估包括实例总量、db 连接数、变更风险、影响范围,同时支持核心应用的秒级回滚。

  2. 发布期间开启 HPA, 保证 HPA 能及时扩容应对突发流量。

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

还未添加个人签名 2020-11-28 加入

去哪儿网官方技术大本营,有前沿的热门话题和满满的技术干货~

评论

发布
暂无评论
核心大应用发布效率提升70%,宿主机容器先缩后扩模型分享_后端_Qunar技术沙龙_InfoQ写作社区