作者:郑嘉扬、何杉
前言
享道出行是一家专注于出行服务的专业品牌,是上汽集团实现汽车产业“新四化”(即“电动化、智能网联化、共享化、国际化”)的重要组成部分。作为上汽集团移动出行战略品牌,享道出行充分利用全产业链竞争优势,从消费者对安全及品质的需求出发,通过为消费者提供安全、高效、舒适、便捷的品质体验,打造品质出行服务平台。
在快速的业务发展过程中,基础设施规模的不断增长,为企业管理者带来了对于效率和成本的高度关注。容器技术作为云计算时代基础设施的核心,自然成为了我们关注的焦点。随着容器技术及其生态的不断成熟,对于企业级开发者来说,在提高部署速度、优化资源利用率以及降低环境间差异等方面展现出了巨大的潜力。然而,随着容器数量的激增,如何管理和调度这些容器也成为了一个挑战。
业务架构与痛点
当前业务开发主要采用 Java 技术栈,应用部署架构如图所示:
核心痛点
- 目前使用的 Kubernetes 原生 HPA 弹性扩缩容方案以及 CronHPA 方案,在容器算力准备阶段流程长,包括算力资源准备、调度、镜像拉取、容器创建、容器启动以及应用启动导致冷启动基本是分钟级弹性。
- 无法承接预期外流量,流量损失对业务有感。
- 需要运维人员通过编码、维护程序自动化测算生产环境资源水位,评估扩缩容阈值,运维成本较高。测算结果不够精准也会导致资源浪费或影响业务稳定。
解决方案
针对以上痛点,为解决弹性滞后的问题同时兼顾成本最优,方案如下:
- ACK AHPA 智能弹性
- ECS、ECI 混合部署
作为出行行业,享道的业务特征具备明显的潮汐效应,通过弹性架构改造,我们能够充分发挥云弹性算力的优势,进一步提升了业务自身的容错性。
ACK 智能弹性(AHPA)
针对传统弹性能力所存在的问题,在方案设计阶段我们采用了 阿里云ACK 容器服务推出的 AHPA(Advanced Horizontal Pod Autoscaler)弹性预测,可以根据历史 Pod 的 Ready Time 以及历史 Metrics 自动学习规律,在业务量上涨之前的一个 Ready Time 开始扩容,在业务量上涨时 Pod 已提前准备,可以及时供给资源,解决弹性滞后的问题。
AHPA 弹性预测根据历史数据自动规划未来 24 小时每一分钟的应用实例数,相当于进行 1440 个点(一天为 1440 分钟)的 CronHPA 定时配置。
预先扩容
由于业务具有很强的潮汐属性,每日的涨潮落潮时间比较固定,AHPA 会根据过往的数据推测之后的所需要的 Pod 数量。例如,服务A根据以往双休日情况预测出这个双休日可能出现的 Pod 数量最大值为 16,那么就可以预先扩出来满足这些额外 pod。
ECS、ECI 混合部署
如前文所述,AHPA 只能够解决应用层的弹性滞后问题,并不能提前对底层资源是否足够提前做出判断。这也意味着当底层资源不足时,仍存在使应用扩容时间被无限拉长的风险。
弹性容器实例 ECI(Elastic Container Instance) 作为一种纯 Serverless 容器运行服务,对于用户而言,无需管理底层服务器资源,同样也不需要关心运行过程中的容量规划,只需要提供打包好的 Docker 镜像,即可运行容器,非常适合应对这种流量突发场景下的业务场景。
但从成本性上讲,单位价格会相对裸金属 ECS 较贵,该方案结合了各付费模式和底层架构的优势,当前采取混合部署模式,兼顾成本及稳定性两方面的业务目标。如下图所示,未来目标是一半以上的应用作为业务基线部署在裸金属 ECS 上,对于周期型应用部署在按量付费的 ECS 资源,结合出行行业早晚高峰,剩余 10% 以上的场景均通过 ECI 实例保障。
注: ECI 的计算资源与 ECS 等实例完全解耦,在每个可用区有单独的资源划分给到 Serverless 架构相关产品,对于大部分场景(CPU 数不超过 1 万 Core),无需担心资源不足的情况产生。因此 ECI 也是一种相对可靠的算力容量保障手段。
自定义弹性资源优先级调度
在资源的调度策略上,由于采用了 ECS 及 ECI 两种部署模式,我们期望应用扩容和缩容行为都是确定性的,当应用需要部署一个 Deployment,此时集群中有对应的多种类型的资源,分别是包年包月的 ECS、按量付费的 ECS 和弹性实例 ECI。
那么,部署的服务优先调度顺序理论上依次为:包年包月的 ECS、按量付费的 ECS、弹性实例 ECI。 同时在服务缩容时优先删除 ECI 上的 Pod,释放 ECI 的节点资源,然后删除按量付费的 ECS 上的 Pod,最后删除包年包月的 ECS 上的 Pod。
对于包年包月及按量付费两种不同付费类型的节点需通过打上不同 label 标签实现。然后创建 ResourcePolicy 自定义节点池调度顺序。
ResourcePolicy 配置示例:
apiVersion: scheduling.alibabacloud.com/v1alpha1
kind: ResourcePolicy
metadata:
name: DEMO
namespace: demo-ns
spec:
units:
- max: 15
nodeSelector:
env: prd
resource: ecs
- max: 5
nodeSelector:
foo: bar
resource: ecs
- resource: eci
whenExceedMax: NeverEvict
这里具体的调度策略可根据实际业务场景区分,若对于成本不敏感,且业务的波峰波谷抖动较大的场景,也可以考虑当 ECS 资源不足时,使用 ECI 弹性资源,进而加速 Pod 的启动时间。
向虚拟节点 Pod 注入 Sidecar 容器
在享道的集群架构中,存在采集微服务日志的场景,日志采集器会在 ECS 节点上通过 DaemonSet 方式部署 Agent,但虚拟节点不是真实节点,不支持运行 DaemonSet Pod,如何让调度到虚拟节点的 Pod 也支持上述 Agent 的同等能力呢?答案是向虚拟节点 Pod 注入 Sidecar 容器。
在实施过程中,我们希望做到:
- 维护一份 Deployment 发布模板。在资源调度部署时,自动对底层 ECS 和 ECI 做区分,当 Pod 被调度到 ECS 节点时,无需注入 Sidecar 容器,当 Pod 被调度到虚拟节点时,则自动向 Pod 中注入 Sidecar 容器,从而实现通过维护一份 Deployment 发布模版,即可同时满足不同架构下的兼容性需求。
- 对已有存量业务入侵尽可能小。根据软件设计开闭原则,应该对修改关闭,避免改动线上已经运行稳定的存量业务(如 DaemonSet),只增加新的或对新增内容做改变。
使用一个 Deployment 在原生 K8s 架构中无法做到,原因是添加 Sidecar 容器需要修改 Pod Spec,而原生 K8s 架构中 Pod Spec 落到 etcd 之后就不允许修改了,但 Pod 是否调度到虚拟节点是在 Pod Spec 落到 etcd 后由调度器决定的。因此,使用 OpenKruise 原生 SidecarSet,因为采用 Admission Webhook 机制,在 Pod 创建阶段通过 Label 的匹配所有符合条件的 Pod,此时 Pod 还未调度到虚拟节点,无法仅对调度到虚拟节点的 Pod 生效。
注: SidecarSet 是阿里云开源的云原生应用自动化引擎 OpenKruise 的核心功能之一。使用 SidecarSet 可以为集群中创建的符合条件的 Pod 自动注入 Sidecar 容器,实现 Sidecar 容器(如监控、日志等 agent)的定义和生命周期与业务容器解耦。
虚拟节点支持 SidecarSet 就是专门用于解决该问题。借助虚拟节点组件(ACK Virtual Node)仅为调度到虚拟节点上的 Pod 自动注入 Sidecar 容器,来解耦虚拟节点 Pod 的 Sidecar 容器与业务容器。其原理如下图所示:
通过标签 Serverless.alibabacloud.com/virtual-node:"true" 指定,该标签会在 Pod 确定调度到虚拟节点后自动打上。同时,该方案与 OpenKrusie 原生 SidecarSet 完全兼容,对于后续 Sidecar 容器的升级、运维等操作,仍可以继续使用OpenKrusie原生 SidecarSet 实现。
自定义弹性指标
如上文所述,基于 CPU/内存的弹性指标无法同真实业务工作复杂完全拟合。很多场景下,用户期望根据自定义指标对应用进行扩缩容。AHPA 所提供的 External Metrics 机制,结合 alibaba-cloud-metrics-adapter 组件,可以为应用提供更丰富的扩缩容机制。
业务价值
当前享道出行已经规模化上线智能容器弹性能力,在保证稳定性的前提下,大大节省了资源成本,并能很好地应对突发流量。 如图所示:当阈值设置为 50,指标有到 50 的趋势时,即会触发弹性扩容,能够更好地应对突发流量,保障业务稳定性的同时,也能够实现可观的降本效果。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。