如何合理使用 CPU 管理策略,提升容器性能?

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
函数计算FC,每月15万CU 3个月
应用实时监控服务-应用监控,每月50GB免费额度
简介: CPU Burst、拓扑感知调度是阿里云容器服务 ACK 提升应用性能的两大利器,它们解决了不同场景下的 CPU 资源管理,可以共同使用。点击下文,查看详情!

作者:张佐玮(佑祎)


前言


在云原生时代下,应用工作负载都是以容器的形式部署在宿主机,共享各类物理资源。随着宿主机硬件性能的增强,单节点的容器部署密度进一步提升,由此带来的进程间 CPU 争用,跨 NUMA 访存等问题也更加严重,影响了应用性能表现。如何分配和管理宿主机的 CPU 资源,保障应用可以获得最优的服务质量,是衡量容器服务技术能力的关键因素。


节点侧容器 CPU 资源管理


Kubelet 的 CPU 分配策略


Kubernetes 为容器资源管理提供了 request(请求)和 limit(约束)的语义描述,当容器指定了 request 时,调度器会利用该信息决定 Pod 应该被分配到哪个节点上;当容器指定了 limit 时,Kubelet 会确保容器在运行时不会超用。


CPU 是一种典型的分时复用型资源,内核调度器会将 CPU 分为多个时间片,轮流为各进程分配一定的运行时间。Kubelet 默认的 CPU 管理策略会通过 Linux 内核的 CFS 带宽控制器(CFS Bandwidth Controller)来控制容器 CPU 资源的使用上限。在多核节点下,进程在运行过程中经常会被迁移到其不同的核心,考虑到有些应用的性能对 CPU 上下文切换比较敏感,Kubelet 还提供了 static 策略,允许 Guaranteed 类型 Pod 独占 CPU 核心。


内核 CPU 资源调度


内核 CFS 调度是通过 cfs_period 和 cfs_quota 两个参数来管理容器 CPU 时间片消耗的,cfs_period 一般为固定值 100 ms,cfs_quota 对应容器的 CPU Limit。例如对于一个 CPU Limit = 2 的容器,其 cfs_quota 会被设置为 200ms,表示该容器在每 100ms 的时间周期内最多使用 200ms 的 CPU 时间片,即 2 个 CPU 核心。当其 CPU 使用量超出预设的 limit 值时,容器中的进程会受内核调度约束而被限流。细心的应用管理员往往会在集群 Pod 监控中的 CPU Throttle Rate 指标观察到这一特征。image.gif


1.png


容器 CPU 性能问题现状


让应用管理员常常感到疑惑的是,为什么容器的资源利用率并不高,但却频繁出现应用性能下降的问题?从 CPU 资源的角度来分析,问题通常来自于以下两方面:一是内核在根据 CPU Limit 限制容器资源消耗时产生的 CPU Throttle 问题;二是受 CPU 拓扑结构的影响,部分应用对进程在 CPU 间的上下文切换比较敏感,尤其是在发生跨 NUMA 访问时的情况。


CPU Throttle 问题详解


受内核调度控制周期(cfs_period)影响,容器的 CPU 利用率往往具有一定的欺骗性,下图展示了某容器一段时间的 CPU 使用情况(单位为0.01核),可以看到在 1s 级别的粒度下(图中紫色折线),容器的 CPU 用量较为稳定,平均在 2.5 核左右。根据经验,管理员会将 CPU Limit设置为 4 核。本以为这已经保留了充足的弹性空间,然而若我们将观察粒度放大到 100ms 级别(图中绿色折线),容器的 CPU 用量呈现出了严重的毛刺现象,峰值达到 4 核以上。此时容器会产生频繁的 CPU Throttle,进而导致应用性能下降、RT 抖动,但我们从常用的 CPU 利用率指标中竟然完全无法发现!


2.png


毛刺产生的原因通常是由于应用突发性的 CPU 资源需求(如代码逻辑热点、流量突增等),下面我们用一个具体的例子来描述 CPU Throttle 导致应用性能下降的过程。图中展示了一个CPU Limit = 2 的 Web 服务类容器,在收到请求后(req)各线程(Thread)的 CPU 资源分配情况。假设每个请求的处理时间均为 60 ms,可以看到,即使容器在最近整体的 CPU 利用率较低,由于在 100 ms~200 ms 区间内连续处理了4 个请求,将该内核调度周期内的时间片预算(200ms)全部消耗,Thread 2 需要等待下一个周期才能继续将 req 2 处理完成,该请求的响应时延(RT)就会变长。这种情况在应用负载上升时将更容易发生,导致其 RT 的长尾情况将会变得更为严重。


3.png


为了避免 CPU Throttle 的问题,我们只能将容器的 CPU Limit 值调大。然而,若想彻底解决 CPU Throttle,通常需要将 CPU Limit 调大两三倍,有时甚至五到十倍,问题才会得到明显缓解。而为了降低 CPU Limit 超卖过多的风险,还需降低容器的部署密度,进而导致整体资源成本上升。


CPU 拓扑结构的影响


在 NUMA 架构下,节点中的 CPU 和内存会被切分成了两部分甚至更多(例如图中 Socket0,Socket1),CPU 被允许以不同的速度访问内存的不同部分,当 CPU 跨 Socket 访问另一端内存时,其访存时延相对更高。盲目地在节点为容器分配物理资源可能会降低延迟敏感应用的性能,因此我们需要避免将 CPU 分散绑定到多个 Socket 上,提升内存访问时的本地性。如下图所示,同样是为两个容器分配 CPU、内存资源,显然场景B中的分配策略更为合理。


4.png


Kubelet 提供的 CPU 管理策略 “static policy”、以及拓扑管理策略 “single-numa-node”,会将容器与 CPU 绑定,可以提升应用负载与 CPU Cache,以及 NUMA 之间的亲和性,但这是否一定能够解决所有因 CPU 带来的性能问题呢,我们可以看下面的例子。


某 CPU Limit = 2 的容器,其应用在 100ms 时间点收到了 4 个请求需要处理,在 Kubelet 提供的 static 模式下,容器会被固定在 CPU0 和 CPU1 两个核心,各线程只能排队运行,而在 Default 模式下,容器获得了更多的 CPU 弹性,收到请求后各线程可以立即处理。可以看出,绑核策略并不是“银弹”,Default 模式也有适合自己的应用场景。


5.png

image.gif

事实上,CPU 绑核解决的是进程在不同 Core,特别是不同 NUMA 间上下文切换带来的性能问题,但解决的同时也损失了资源弹性。在这种情况下线程会在各 CPU 排队运行,虽然 CPU Throttle 指标可能有所降低,但应用自身的性能问题并没有完全解决。


使用 CPU Burst 机制提升容器性能


往期文章我们介绍了阿里云贡献的 CPU Burst 内核特性,可以有效解决 CPU Throttle 的问题,当容器真实 CPU 资源使用小于 cfs_quota 时,内核会将多余的 CPU 时间“存入”到 cfs_burst 中;当容器有突发的 CPU 资源需求,需要使用超出 cfs_quota 的资源时,内核的 CFS 带宽控制器(CFS Bandwidth Controller,简称 BWC) 会允许其消费其之前存到 cfs_burst 的时间片。


6.png


CPU Burst 机制可以有效解决延迟敏感性应用的 RT 长尾问题,提升容器性能表现,目前阿里云容器服务 ACK 已经完成了对 CPU Burst 机制的全面支持。对于尚未支持 CPU Burst 策略的内核版本,ACK 也会通过类似的原理,监测容器 CPU Throttle 状态,并动态调节容器的 CPU Limit,实现与内核 CPU Burst 策略类似的效果。


我们使用 Apache HTTP Server 作为延迟敏感型在线应用,通过模拟请求流量,评估 CPU Burst 能力对响应时间(RT)的提升效果。以下数据分别展示了 CPU Burst 策略开启前后的表现情况:


7.pngimage.gif


对比以上数据可得知:


  • 在开启 CPU Burst 能力后,应用的 RT 指标的 p99 分位值得到了明显的优化。
  • 对比 CPU Throttled 及利用率指标,可以看到开启 CPU Burst 能力后,CPU Throttled 情况得到了消除,同时 Pod 整体利用率基本保持不变。


使用拓扑感知调度提升容器性能


虽然 Kubelet 提供了单机的资源管理策略(static policy,single-numa-node),可以部分解决应用性能表现受 CPU 缓存、NUMA 亲和性影响的问题,但该策略尚有以下不足之处:


  • static policy 只支持 QoS 为 Guaranteed 的 Pod,其他 QoS 类型的 Pod 无法使用
  • 策略对节点内所有 Pod 全部生效,而我们通过前面的分析知道,CPU 绑核并不是”银弹“
  • 中心调度并不感知节点实际的 CPU 分配情况,无法在集群范围内选择到最优组合


阿里云容器服务 ACK 基于 Scheduling framework 实现了拓扑感知调度以及灵活的绑核策略,针对 CPU 敏感型的工作负载可以提供更好的性能。ACK 拓扑感知调度可以适配所有 QoS 类型,并支持在 Pod 维度按需开启,同时可以在全集群范围内选择节点和 CPU 拓扑的最优组合。


通过对 Nginx 服务进行的评测,我们发现在 Intel(104核)、AMD(256核)的物理机上,使用 CPU 拓扑感知调度能够将应用性能提升 22%~43%。


8.png


总结

CPU Burst、拓扑感知调度是阿里云容器服务 ACK 提升应用性能的两大利器,它们解决了不同场景下的 CPU 资源管理,可以共同使用。


CPU Burst 解决了内核 BWC 调度时针对 CPU Limit 的限流问题,可以有效提升延时敏感型任务的性能表现。但 CPU Burst 本质并不是将资源无中生有地变出来,若容器 CPU 利用率已经很高(例如大于50%),CPU Burst 能起到的优化效果将会受限,此时应该通过 HPA 或 VPA 等手段对应用进行扩容。


拓扑感知调度降低了工作负载 CPU 上下文切换的开销,特别是在 NUMA 架构下,可以提升 CPU 密集型,访存密集型应用的服务质量。不过正如前文中提到的,CPU 绑核并不是“银弹”,实际效果取决于应用类型。此外,若同一节点内大量 Burstable  类型 Pod 同时开启了拓扑感知调度,CPU 绑核可能会产生重叠,在个别场景下反而会加剧应用间的干扰。因此,拓扑感知调度更适合针对性的开启。


点击此处,即可查看阿里云 ACK 支持 CPU Burst 、拓扑感知调度的详细介绍!


相关实践学习
巧用云服务器ECS制作节日贺卡
本场景带您体验如何在一台CentOS 7操作系统的ECS实例上,通过搭建web服务器,上传源码到web容器,制作节日贺卡网页。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
1月前
|
缓存 运维 监控
CPU被打满/CPU 100%:高效应对策略与技术干货分享
【10月更文挑战第3天】在信息技术高速发展的今天,无论是开发人员、运维人员还是数据分析师,都可能遇到CPU被打满(即CPU使用率达到100%)的情况。这不仅会影响系统的响应速度,严重时甚至会导致服务中断。本文将从诊断、分析与解决三个方面,详细介绍处理CPU 100%问题的技术干货。
84 3
|
2月前
|
移动开发 前端开发 HTML5
Twaver-HTML5基础学习(20)数据容器(3)_数据的批量加载(节省性能方法)
本文介绍了Twaver HTML5中数据的批量加载方法,通过使用`box.startBatch()`可以在大量数据加载时提高性能。文章通过示例代码展示了如何在React组件中使用批量加载功能,以减少界面重绘次数并提升效率。
55 1
Twaver-HTML5基础学习(20)数据容器(3)_数据的批量加载(节省性能方法)
|
3月前
|
Kubernetes Cloud Native Java
云原生之旅:从容器到微服务的演进之路Java 内存管理:垃圾收集器与性能调优
【8月更文挑战第30天】在数字化时代的浪潮中,企业如何乘风破浪?云原生技术提供了一个强有力的桨。本文将带你从容器技术的基石出发,探索微服务架构的奥秘,最终实现在云端自由翱翔的梦想。我们将一起见证代码如何转化为业务的翅膀,让你的应用在云海中高飞。
|
3月前
|
Kubernetes 开发者 容器
"Kubernetes的生死抉择:揭秘Pod容器重启策略如何决定应用命运的惊天大戏"
【8月更文挑战第20天】Kubernetes (k8s) 是一个强大的容器编排平台,其中Pod是最小的运行单元。Pod的重启策略确保服务连续性,主要有Always(总是重启)、OnFailure(失败时重启)和Never(从不重启)。默认策略为Always。根据不同场景,如Web服务、批处理作业或一次性任务,可以选择合适的策略。K8s还支持健康检查等高级机制来控制容器重启。合理配置这些策略对维护应用稳定性至关重要。
140 4
|
10天前
|
存储 缓存
CPU性能
【10月更文挑战第30天】CPU性能
21 3
|
1月前
|
存储 缓存 监控
如何提高服务器CPU性能?
如何提高服务器CPU性能?
135 3
|
26天前
|
运维 JavaScript Linux
容器内的Nodejs应用如何获取宿主机的基础信息-系统、内存、cpu、启动时间,以及一个df -h的坑
本文介绍了如何在Docker容器内的Node.js应用中获取宿主机的基础信息,包括系统信息、内存使用情况、磁盘空间和启动时间等。核心思路是将宿主机的根目录挂载到容器,但需注意权限和安全问题。文章还提到了使用`df -P`替代`df -h`以获得一致性输出,避免解析错误。
|
2月前
|
算法 Java 程序员
解锁Python高效之道:并发与异步在IO与CPU密集型任务中的精准打击策略!
在数据驱动时代,高效处理大规模数据和高并发请求至关重要。Python凭借其优雅的语法和强大的库支持,成为开发者首选。本文将介绍Python中的并发与异步编程,涵盖并发与异步的基本概念、IO密集型任务的并发策略、CPU密集型任务的并发策略以及异步IO的应用。通过具体示例,展示如何使用`concurrent.futures`、`asyncio`和`multiprocessing`等库提升程序性能,帮助开发者构建高效、可扩展的应用程序。
95 0
|
3月前
|
安全 网络安全 数据安全/隐私保护
云原生技术探索:容器化与微服务架构的实践之路网络安全与信息安全:保护数据的关键策略
【8月更文挑战第28天】本文将深入探讨云原生技术的核心概念,包括容器化和微服务架构。我们将通过实际案例和代码示例,展示如何在云平台上实现高效的应用部署和管理。文章不仅提供理论知识,还包含实操指南,帮助开发者理解并应用这些前沿技术。 【8月更文挑战第28天】在数字化时代,网络安全和信息安全是保护个人和企业数据的前线防御。本文将探讨网络安全漏洞的成因、加密技术的应用以及提升安全意识的重要性。文章旨在通过分析网络安全的薄弱环节,介绍如何利用加密技术和提高用户警觉性来构建更为坚固的数据保护屏障。
|
3月前
|
监控 Java Linux
CPU被打满/CPU 100%:高效诊断与优化策略
【8月更文挑战第28天】在日常的工作与学习中,遇到CPU使用率飙升至100%的情况时,往往意味着系统性能受到严重影响,甚至可能导致程序响应缓慢或系统崩溃。本文将围绕这一主题,分享一系列高效诊断与优化CPU使用的技术干货,帮助大家快速定位问题并恢复系统性能。
194 1