作者:vivo 互联网服务器团队 - Chen Han

容器平台针对业务资源申请值偏大的运营问题,通过静态超卖和动态超卖两种技术方案,使业务资源申请值趋于合理化,提高平台资源装箱率和资源利用率。

一、背景

在Kubernetes中,容器申请资源有request和limit概念来描述资源请求的最小值和最大值。

  • requests值在容器调度时会结合节点的资源容量(capacity)进行匹配选择节点。

  • limits表示容器在节点运行时可以使用的资源上限,当尝试超用资源时,CPU会被约束(throttled),内存会终止(oom-kill)。

总体而言,在调度的时候requests比较重要,在运行时limits比较重要。在实际使用时,容器资源规格 request 和 limit 的设置规格也一直都让Kubernetes的用户饱受困扰:

  • 对业务运维人员:希望预留相当数量的资源冗余来应对上下游链路的负载波动,保障线上应用的稳定性。

  • 对平台人员:集群的资源装箱率高,节点利用率低,存在大量的空闲资源无法调度,造成算力浪费。

二、现状

2.1 vivo容器平台介绍

vivo容器平台基于Kubernetes技术对内部业务提供容器服务。内部业务统一在CICD平台部署和管理容器资源,容器平台自研的caas-openapi组件提供restful接口与CICD交互。

平台通过标签,从资源维度逻辑上可以分为测试池、共享池、专有池、混部池。

  • 测试池:为业务部署容器测试,一般非现网业务,为业务测试提供便利。

  • 共享池:为业务不感知物理机,类似公有云全托管容器服务。

  • 专有池:为业务独享物理机,类似公有云半托管容器服务,业务方独占资源,容器平台维护。

  • 混部池:为业务独享物理机,在专有池基础上,混部离线业务,缓解离线资源缺口,提升整机利用率。

2.2 资源部署现状和问题

vivo容器平台的所有在线业务部署均要求设置request和limit,且request <= limit,默认情况request等于limit。在共享池中,常见业务request设置会出现如下情况:

(1) 较少情况,业务设置较低的 request 值,而实际使用资源远大于它的 request 值,若大量pod调度一个节点,加剧节点热点问题影响同节点其他业务。

(2)大多情况,业务按最大资源需求设置较高的 request 值,而实际使用资源长期远小于它的 request 值。业务侧账单成本高(按request计费),且容器异常退出时,重调度时可能因为平台空闲资源碎片,导致大规格容器无法调度。这会导致,平台侧可调度资源少,但平台整体节点资源利用率偏低。

对平台和用户方,request值设置合理很重要,但平台无法直接判断用户设置request值合理性,所以无法首次部署时硬限制。

2.3 资源规格合理性思考

2.3.1 request怎么样才是合理设置

request值接近业务实际使用量,例如用户申请request为2核,limit为4核,实际真实使用量最多1核,那么合理request值设置为1核附近。但是业务真实使用量只有运行一段时间后才能评估,属于后验知识。

2.3.2 保障资源最大使用量

不修改limit值就能保障业务最大使用量符合业务预期。

三、解决方案探索

3.1 静态超卖方案

思路:

静态超卖方案是将CICD用户申请规格的request按一定比例降低,根据平台运营经验设置不同集群不同机房不同环境的静态系数,由caas-openapi组件自动修改。如下图:

优点

首次部署时可以应用,实现简单。

缺点

生产环境系数设置保守,导致request依然偏大,且由于内存是不可压缩资源,实际实施时为避免业务实例内存oom-kill,静态超卖只开启了cpu维度,未开启内存静态超卖。

3.2 动态超卖方案

3.2.1 方案思路

开发caas-recommender组件,基于业务监控数据的真实资源用量来修正业务request值。

  1. 从监控组件拉取各个容器资源的真实使用量。

  2. 通过算法模型得到业务申请量的推荐值。

  3. 业务重新部署时,使用推荐值修改业务request值。

3.2.2 半衰期滑动窗口模型

结合容器业务的特点,对推荐算法有如下要求:

  • 当workload负载上升时,结果需要快速响应变化,即越新的数据对算法模型的影响越大;

  • 当workload负载下降时,结果需要推迟体现,即越旧的数据对算法结果的影响越小。

半衰期滑动窗口模型可以根据数据的时效性对其权重进行衰减,可以满足上述要求。

详细描述参考:google Borg Autopilot的moving window模型,参看原论文>>

公式如下:

其中 τ 为数据样本的时间点,t1/2 为半衰期,表示每经过 t1/2 时间间隔,前一个 t1/2 时间窗口内数据样本的权重就降低一半。

  • 核心理念:在参考时间点之前的数据点,离的越远权重越低。在参考时间点之后的数据点权重越高。

  • 半衰期halfLife:经过时间halfLife后,权重值降低到一半。默认的halfLife为24小时。

  • 数据点的时间timestamp:监控数据的时间戳。

  • 参考时间referenceTimestamp:监控数据上的某个时间(一般是监控时间最近的零点00:00)。

  • 衰减系数decayFactor:2^((timestamp-referenceTimestamp)/halfLife)

  • cpu资源的固定权重:CPU 使用量数据对应的固定权重是基于容器 CPU request 值确定的。当 CPU request 增加时,对应的固定权重也随之增加,旧的样本数据固定权重将相对减少。

  • memory资源的固定权重:由于内存为不可压缩资源,而内存使用量样本对应的固定权重系数为1.0。

  • 数据点权重 = 固定权重*衰减系数:例如现在的数据点的权重为1,那么24小时之前的监控数据点的权重为0.5,48小时前的数据点的权重为0.25,48小时后的数据权重为4。

3.2.3 指数直方图计算推荐值

caas-recommender每个扫描周期(默认1min)从 metrics server 或 prometheus 中获取带时间戳的样本数据,如 container 维度的 CPU、Memory 资源使用等。样本数据结合权重值,为每个workload构建指数直方图,指数直方图中每个桶的大小以指数速率逐步提升。指数直方图的样本存储方式也便于定期checkpoint保存,可以显著提升程序recover性能。如下图:

  1. 指数直方图的横轴定义为资源量,纵轴定义为对应权重,资源量统计间隔以5%左右的幅度增加。
  2. 桶的下标为N,桶的大小是指数增加的bucketSize=0.01*(1.05^N),下标为0的桶的大小为0.01,容纳范围为[0,0.01),下标为1的桶的大小为0.01*1.05^1=0.0105,容纳范围[0.01-0.0205)。[0.01,173]只需要两百个桶即可完整保存。

  3. 将每个数据点,按照数值大小丢到对应的桶中。

  4. 当某个桶里增加了一个数据点,则这个桶的权重增加固定权重*衰减系数,所有桶的权重也增加固定权重*衰减系数

  5. 计算出W(95)=95%*所有桶的总权重,如上图仅考虑前4个桶,总权重为20,w(95)权重为19。

  6. 从最小的桶到最大桶开始累加桶的权重,这个权重记为S,当S>=W(95)时候,这个时候桶的下标为N,那么下标为N+1桶的最小边界值就是95百分位值,如上图N=3时,S>=W(95),95百分位值即为0.01*1.05^2。

比如CPU波动较大且可压缩,采用95%分位值(P95),内存采用99%分位值(P99)。最终得到workload的资源推荐值。

3.2.4 caas-recommender组件流程图

1. 启动controller:profile Controller监听profile template crd,根据profile crd创建相应维度的recommendation crd,可支持namepace\workload\pod维度。

2. 初始化:判断是否有checkpoint,若无,可以选择从prometheus拉取数据构建直方图。若有,由checkpoint直接recover。

3. loop循环:

  • 从recommendation crd中判断哪些pod需要纳管(pod labels)

  • 根据pod label从Kubernetes获取pod信息

  • 根据pod的namespace从metrics server拉取监控数据,由container数据汇聚成pod用量数据。

  • 构建指数直方图,填充pod用量数据和权重值。

  • 根据直方图的分位值计算推荐值

  • 存储推荐值和直方图chekpoint

  • gc需要删除的recommendation crd或者直方图内存等无用数据。

4.支持原生workload常用类型,拓展支持了OpenKruise相关workload类型。

3.2.5 推荐值校正规则

  • 推荐值 = 模型推荐值 * 扩大倍数(可配置)

  • 推荐值 < 原生request值:按照推荐值修改

  • 推荐值 > 原始request值:  按照原始request修改

  • 内存是否修改可以通过配置

  • 不修改workload的limit值

3.3 HPA利用率计算逻辑改造

Pod 水平自动扩缩(Horizontal Pod Autoscaler, 简称 HPA)可以基于 CPU/MEM 利用率自动扩缩workload的Pod数量,也可以基于其他应程序提供的自定义度量指标来执行自动扩缩。

原生Kubernetes的HPA扩缩容利用率计算方式是基于request值。若资源超卖,request值被修改后,那么业务设置的HPA失灵,导致容器不符合预期扩缩容。

关于HPA是基于request还是基于limit,目前Kubernetes社区还存在争论,相关 issue 见72811。若需要使用limit计算利用率,可以修改kube-controller-manager源码,或者使用自定义指标来代替。

vivo容器平台兼容业务物理机利用率逻辑,规定内部统一监控系统的Pod利用率均基于limit计算。

HPA改造思路:通过修改kube-controller-manager源码方式实现基于limit维度计算。

  • 在pod annotation中记录设置值信息(request值和limit值),以及维度信息(request或limit维度)。

  • controller计算pod资源时,判断是否有指定annotation,若有,解析annotation记录值和维度信息计算利用率,若无,使用原生逻辑。

通过上述方式解耦HPA与pod request值,这样平台的资源超卖功能修改request不影响HPA自动扩缩预期。

3.4 专有池支持超卖能力

专有池物理机由业务自行运维管理,从平台角度,不应该随意修改业务的容器request规格。但是专有池业务也有降低容器规格,部署更多业务,复用资源,提高整机利用率的需求。平台默认所有共享池自动开启超卖能力,专有池可配置选择开启超卖能力。

  • 可自定义开启超卖类型:静态、动态、静态+动态。

  • 可自定义静态系数、动态超卖扩大系数。

  • 可配置是否自动修改超卖值,当不自动生效可通过接口查询推荐值,由业务自行修改。

3.5 整体方案

首次部署:

根据先验知识评估,通过固定静态系数修改request值,再根据部署后各个pod监控用量数据,生成workload的request推荐值。

再次部署:

若有推荐值,使用推荐值部署。无推荐值或者推荐值未生效时,使用静态系数。

四、效果和收益

4.1 测试集群收益

原测试机器的静态超卖系数很低,且只缩减cpu维度资源,导致集群内存成为资源瓶颈。

开启动态超卖能力4个月后,纳管90%的workload,节点pod平均内存request由4.07Gi下降到3.1Gi,内存平台装箱率降低10%,有效缓解集群内存不足问题。

4.2 共享池生产集群收益

原生产集群静态超卖系数较高,CPU资源装箱率高,导致集群的CPU成为瓶颈。

开启动态超卖能力3个月后,纳管60%的workload,节点pod平均cpu request由2.86降低为2.35,整体cpu利用率相比未开启前提升8%左右。

五、总结与展望

vivo容器平台通过资源超卖方案,将业务容器的request降低到合理值,降低业务使用成本,缓解了集群资源不足问题,达到了提升节点利用率目的。但是当前仅在生产集群开启了CPU资源超卖,规划近期开启内存资源超卖。

未来基于上述方法,可以纳管更多维度,比如GPU卡利用率再结合GPU虚拟化能力,从而提高GPU资源共享效率。根据动态超卖推荐值可以用于构建用户画像,区分业务是计算型或内存型,方便平台更好理解用户特性,辅助资源调度等。

参考资料:

vivo 容器平台资源运营实践的更多相关文章

  1. vivo 云原生容器探索和落地实践

    作者:vivo 互联网容器团队- Pan Liangbiao 本文根据潘良彪老师在"2022 vivo开发者大会"现场演讲内容整理而成.公众号回复[2022 VDC]获取互联网技术 ...

  2. vivo 容器集群监控系统架构与实践

    vivo 互联网服务器团队-YuanPeng 一.概述 从容器技术的推广以及 Kubernetes成为容器调度管理领域的事实标准开始,云原生的理念和技术架构体系逐渐在生产环境中得到了越来越广泛的应用实 ...

  3. 事件驱动架构在 vivo 内容平台的实践

    一.什么是事件驱动架构 当下,随着微服务的兴起,容器化技术的发展,以及云原生.serverless 概念的普及,事件驱动再次引起业界的广泛关注. 所谓事件驱动的架构,也就是使用事件来实现跨多个服务的业 ...

  4. vivo霍金实验平台设计与实践-平台产品系列02

    vivo 互联网平台产品研发团队 - Bao Dawei 本篇介绍了vivo霍金实验平台的系统架构以及业务发展过程中遇到的问题以及对应的解决方案. <平台产品>系列文章: 1.vivo平台 ...

  5. 基于kubernetes自研容器管理平台的技术实践

    一.容器云的背景 伴随着微服务的架构的普及,结合开源的Dubbo和Spring Cloud等微服务框架,宜信内部很多业务线逐渐了从原来的单体架构逐渐转移到微服务架构.应用从有状态到无状态,具体来说将业 ...

  6. Docker容器的原理与实践 (下)

    欢迎访问网易云社区,了解更多网易技术产品运营经验. Docker原理分析 Docker架构 镜像原理 镜像是一个只读的容器模板,含有启动docker容器所需的文件系统结构及内容Docker以镜像和在镜 ...

  7. 容器平台选型的十大模式:Docker、DC/OS、K8S 谁与当先?

    作者:刘超   来自:网易云 基础服务 无论是在社区,还是在同客户交流的过程中,总会被问到到底什么时候该用 Docker?什么时候用虚拟机?如果使用容器,应该使用哪个容器平台? 显而易见,我不会直接给 ...

  8. OpenResty 在又拍云容器平台中的应用

    大家好,我是又拍云叶靖,今天主要分享 OpenResty 在又拍云容器平台中的应用.目前又拍云有很多产品,其中很多都使用了 OpenResty 技术,比如又拍云的 CDN .网关都是基于 OpenRe ...

  9. 容器平台选型的十大模式:Docker、DC/OS、K8S 谁与当先?【转】

    网易企业服务2017-10-13 无论是在社区,还是在同客户交流的过程中,总会被问到到底什么时候该用 Docker?什么时候用虚拟机?如果使用容器,应该使用哪个容器平台? 显而易见,我不会直接给大家一 ...

  10. Docker容器的原理与实践(上)

    本文来自网易云社区. 虚拟化 是一种资源管理技术,将计算机的各种资源予以抽象.转换后呈现出来, 打破实体结构间的不可切割的障碍,使用户可以比原本更好的方式来应用这些资源. Hypervisor 一种运 ...

随机推荐

  1. LeetCode952三部曲之三:再次优化(122ms -> 96ms,超51% -> 超91%)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本文是<LeetCode952三部曲之 ...

  2. vue3 甘特图(二):甘特图时间轴切换

    vue3 甘特图(二):gantt时间轴切换 1.固定时间轴缩放级别 gantt.config.scale_unit = "month"; //时间轴单位 gantt.config ...

  3. DesignPattern-part1

    title: "modern C++ DesignPattern-Part1" date: 2018-04-03T16:06:33+08:00 lastmod: 2018-04-0 ...

  4. jQuery Ajax执行顺序问题

    代码如下: $(document).ready(function () { var res; $.ajax({ type: 'post', url: 'GridDemo.aspx/PlaceOrder ...

  5. Linux服务器搭建环境复盘

    Linux服务器搭建环境复盘 Linux服务器上是没有开发环境的,需要自己配置,在获得了服务器账号后,通过WinSCP登录可以传文件. 下载anaconda 官网下载Anaconda Linux版本 ...

  6. Solution -「CF 724F」Uniformly Branched Trees

    Description Link. 给定三个数 \(n,d,mod\),求有多少种 \(n\) 个点的不同构的树满足:除了度数为 \(1\) 的结点外,其余结点的度数均为 \(d\).答案对质数 \( ...

  7. Intrusion Detection Using Convolutional Neural Networks for Representation Learning 笔记

    Intrusion Detection Using Convolutional Neural Networks for Representation Learning 2.2 实验数据的预处理 为了确 ...

  8. 2023-10-18:用go语言,给定一个数组arr,长度为n,表示有0~n-1号设备, arr[i]表示i号设备的型号,型号的种类从0~k-1,一共k种型号, 给定一个k*k的矩阵map,来表示型号

    2023-10-18:用go语言,给定一个数组arr,长度为n,表示有0~n-1号设备, arr[i]表示i号设备的型号,型号的种类从0~k-1,一共k种型号, 给定一个k*k的矩阵map,来表示型号 ...

  9. Python 面向对象编程:类、对象、初始化和方法详解

    Python 是一种面向对象的编程语言.在 Python 中,几乎所有东西都是对象,都具有其属性和方法. 类似于对象构造函数或用于创建对象的"蓝图"的类. 创建一个类 要创建一个类 ...

  10. 批处理(Batch或离线计算)和流计算(Streaming或实时计算)

    大数据处理流程 课程:https://developer.aliyun.com/learning/course/432/detail/5385 流程 发 批处理(Batch或离线计算) 基础:goog ...