为进一步加强技术交流,推进云原生生态共建,6 月 28 日下午,首届云原生实践者大会在线上线下同步举办。来自作业帮、知乎、转转、58、同程等多家科技企业的数十名研发人员,以及中国信通院云大所的专家共同参与了此次技术研讨沙龙。 会上,作业帮架构研发高级工程师别路分享了作业帮在 K8s Serverless 上的探索历程,包括在 K8s 中通过虚拟节点使用 Serverless 的技术原理、Serverless 能带来哪些收益、作业帮在 K8s Serverless 上遇到的问题,以及如何在业界的调度方案都不太理想的情况下产出创新的调度方案、如何保持虚拟节点上 pod 的可观测性等,并在生产实践上给出建议。 以下,是别路的分享。
大家好,我是别路,来自作业帮基础架构部。先简单做个自我介绍,我 2017 年参加工作,先后在滴滴、旷视从事业务和架构开发工作。2020 年加入作业帮,负责 K8s 集群建设和基础组件研发工作。
很高兴在这里和大家分享,本次分享的主题是“作业帮 K8s Serverless 大规模应用实践”,内容分为以下 4 个部分:
作业帮的服务端技术体系正向着云原生化发展,提升资源利用率是云原生技术栈的核心目标之一。利用 Serverless 按量计费、快速伸缩、运维自动化等特点,能够带来降低基础设施成本、降低交付时间、降低人力成本等优势。
Serverless 化一直是作业帮基础架构探索的核心方向。目前业界的 Serverless 主要有两种形态,一种是函数计算,一种是 K8s 虚拟节点。
基于公司大部分服务已完成容器化的背景,我们选择使用 K8s 虚拟节点。使用 K8s 虚拟节点,对已经运行在 K8s 上的服务来说,无需改造即可使用,具有无感平滑迁移、用户体验较好的优点。
2020 年,我们开始尝试将部分密集计算调度到 Serverless 虚拟节点上,利用虚拟节点底层服务器的强隔离能力来规避服务间相互影响。2021 年,我们就将定时任务调度到 Serverless 虚拟节点,替代节点扩缩容,应对短期运行的任务,提升资源利用率降低成本。2022 年,我们开始将部分核心在线业务调度到了 Serverless 虚拟节点上。
虚拟节点是一种调度能力,支持将标准 Kubernetes 集群中的 pod 调度到集群服务器节点之外的资源中。部署在虚拟节点上的 pod 具备裸金属服务器一致的网络连通性,又具有无需预留资源,按量计费的特性。
业界 K8s 虚拟节点基本都是基于 Virtual Kubelet 实现的。Virtual Kubelet 是一个开源的 K8s Kubelet 实现,它通过实现 Kubelet 的一些接口来伪装成一个 Kubelet,而实际上创建 pod 的工作是由云厂商去通过相应的接口来实现。
其中,一些核心接口有注册节点容量,创建、销毁、更新 pod,获取 pod 信息等接口。这些都属于云厂商需要关注的范畴,而我们作为用户通常只需要把它当作一个特殊的节点来使用就可以。当然,理解它的工作原理更容易把握它的边界。
接下来,我们看一下用户视角的虚拟节点。从用户视角来看,虚拟节点和普通节点几乎一致。普通节点上的 pod 可以和虚拟节点上的 pod 互相访问,一个 Service 下还可以同时存在正常节点和虚拟节点上的 pod。Pod 是否部署到虚拟节点上对大多数业务来说几乎感知不到区别。
虚拟节点有着诸多优点,也存在一些限制,基本都是和 host 相关。这也很好理解,毕竟实际上并不存在真正的节点。所以,DaemonSet、HostNetwork、HostPath、HostPid 和 NodePort 类型的 Service 和节点绑定的资源通常是不可用的。
介绍完虚拟节点的原理,我们再来看一下虚拟节点可以带来的成本优势。
目前,作业帮的大部分服务都已经完成容器化,在线业务有着典型的高峰期,且高峰期持续时间较短(约 4 个小时/每天)。高峰期服务器平均负载接近 60%,而低峰期负载只有 10%左右。此场景就非常适合 Serverless 的弹性伸缩落地。
我们可以做一个简单的计算。假设全部使用自有服务器每小时的成本为 C,平均每天高峰期的时间为 4 小时,使用 Serverless 的单位时间成本为 1.5C,那么:
理论上高峰期波峰部分使用 Serverless 可降低的成本大约为:22.5%。可见,将在线服务高峰期弹性调度到 Serverless 可以节省大量的资源成本。
介绍完虚拟节点的原理和成本优势之后,接下来看看我们在使用虚拟节点过程中遇到的一些问题和解决方案。
第一个问题是调度问题,第二个是观察性问题,最后是性能、稳定性和其它问题。
我们先来看一下调度问题。在调度层面,主要需要解决两个问题:一是扩容时创建 pod 基于何种调度策略调度到虚拟节点;二是缩容时应优先缩虚拟节点上的 pod。这两种能力在当前的 Kubernetes 版本中能力是不足的。
对于调度到虚拟节点,业界常用的有两种方案。
第一种方案,也是调度到虚拟节点,最朴素的做法是通过 NodeSelector、节点亲和、污点和容忍的方式。这种方式是最简单的把虚拟节点用起来的方式,但是这样虚拟节点和标准节点是完全分开的,服务只能调度到指定的资源池:一个服务要么全上虚拟节点,要么全不上虚拟节点,而这样无法最大化利用成本优势。
第二种方案,也是很多云厂商提供的方案:用户不用指定 selector,当 pod 因固定节点资源不足调度 pending 的时候,再尝试调度到虚拟节点上。这种方案也存在问题:在集群资源已满的情况下才调度到虚拟节点,会导致 pod 部署过于密集,节点负载太高影响业务。
而我们理想方案是希望在集群物理服务器资源达到利用率瓶颈后,扩容到 serverless 虚拟节点上。这样就可以即没有负载过高的风险也可以最大化成本优势。
我们的业务场景需要更精细化的资源管理策略,所以我们研发了自己的方案:使用自研调度器将具体服务超过一定数量的 pod 调度到虚拟节点上,这个数量就是一个关键的“阈值”。该阈值基于在线服务的波峰波谷,进行预测推荐,计算出高峰该服务能在集群物理机上运行的副本数最优解,这样既能满足集群物理机的资源利用率也能满足性能要求。
该方案除了支持自动计算调度到虚拟节点的阈值,还支持人工手动设置以便于业务进行更精细的调控,调度到虚拟节点的能力还可以结合 hpa、cron-hpa 同时使用,以此满足业务更灵活的需求。
解决完扩容问题,再来看一下缩容问题。缩容时,优先缩 Serverless 虚拟节点上的 pod 很好理解,因为常备的资源池是包年包月的单价更低,虚拟节点上的资源是按量计费的单价较高,优先缩虚拟节点上的 pod 来达到成本最优。
具体的做法是通过自研调度器对虚拟节点上的 pod 注入自定义的注解,对 Kube-controller-manager 进行二次开发,将带有虚拟节点自定义注解的 pod 置于缩容队列的顶部,来完成优先缩容虚拟节点上的 pod。
说完调度问题,我们再来看一下观测性问题。我们的观测服务都是自建的,比如(日志检索、监控报警、分布式追踪)。因为是虚拟节点,pod 里跑的监控组件、日志采集是由云厂商内置的。我们需要保证业务感知层面上,pod 运行在 Serverless 虚拟节点和物理服务器上是一致的,所以就有一个转化到我们自有观测服务的过程。
在日志采集方面,通过 CRD 配置日志采集,将日志发送到统一的 Kafka。通过我们自研的日志消费服务,消费各云厂商和自有节点上的日志,实现了虚拟节点和正常节点上日志的统一。
在监控方面,云厂商虚拟节点实现的 metrics 接口和 Kubelet 完全兼容,可以无缝接入 Prometheus,完成了 Pod 实时 CPU/内存/磁盘/网络流量等监控,做到了和普通节点上的 pod 一致。
在分布式追踪方面,由于无法部署 daemonset 形式的 jeager agent,我们在 jeager client 端做了改造,通过环境变量识别 pod 运行的环境,如果是在虚拟节点上则跳过 jeager agent,直接将分布式追踪的数据推送到 jeager collector。
最后是性能、稳定性和其它问题。
目前该方案已经成熟,高峰期已有近万核规模的核心链路在线业务运行在 Kubernetes 虚拟节点上。随着业务的放量,未来运行在 Serverless 虚拟节点上的服务规模会进一步扩大,将节省更多的资源成本。
领取专属 10元无门槛券
私享最新 技术干货