窃取:谁从虚拟机窃取 CPU 时间

窃取:谁从虚拟机窃取 CPU 时间

你好! 我想简单地告诉您有关虚拟机内部窃取的机制以及我们在研究过程中设法发现的一些不明显的工件,这是我作为云平台的技术总监必须深入研究的 Mail.ru 云解决方案。 该平台运行在KVM上。

CPU 窃取时间是虚拟机不接收用于其执行的处理器资源的时间。 该时间仅在虚拟化环境中的来宾操作系统中计算。 就像在生活中一样,这些分配最多的资源去向何处的原因非常模糊。 但我们决定弄清楚它,甚至进行了一些实验。 并不是说我们现在知道有关偷窃的一切,但我们现在会告诉您一些有趣的事情。

1.什么是偷窃

因此,窃取是一个指标,表明虚拟机内的进程缺乏处理器时间。 如上所述 在KVM内核补丁中隐形是指虚拟机管理程序在主机操作系统上执行其他进程的时间,即使它已将虚拟机进程排队等待执行。 也就是说,steal 计算为进程准备执行的时间与进程被分配处理器时间的时间之间的差值。

虚拟机内核从管理程序接收窃取指标。 同时,虚拟机管理程序并没有具体指定它正在运行哪些其他进程,它只是说“当我很忙时,我不能给你时间”。 在KVM上,添加了对窃取计算的支持 补丁。 这里有两个关键点:

  • 虚拟机从管理程序中学习窃取信息。 也就是说,从损失的角度来看,对于虚拟机本身上的进程来说,这是一种间接测量,可能会受到各种扭曲的影响。
  • 虚拟机管理程序不会与虚拟机共享有关其正在执行的其他操作的信息 - 最主要的是它不会投入时间。 因此,虚拟机本身无法检测到窃取指示器中的失真,这可以通过竞争进程的性质来评估。

2.什么影响偷窃

2.1. 偷窃计算

本质上,steal 的计算方式与正常 CPU 使用时间大致相同。 关于如何考虑回收的信息并不多。 可能是因为大多数人认为这个问题是显而易见的。 但这里也存在陷阱。 要熟悉此过程,您可以阅读 布伦丹·格雷格的文章:您将了解计算利用率时的许多细微差别,以及由于以下原因导致计算错误的情况:

  • 处理器过热,导致周期跳过。
  • 启用/禁用睿频加速,这会更改处理器时钟频率。
  • 使用 SpeedStep 等处理器节能技术时发生的时间片长度变化。
  • 计算平均值的问题是:估计一分钟利用率为 80% 可能会隐藏短期的 100% 爆发。
  • 自旋锁导致处理器被回收,但用户进程在其执行过程中看不到任何进展。 因此,该进程计算出的处理器利用率将为 XNUMX%,尽管该进程不会实际消耗处理器时间。

我还没有找到一篇描述类似窃取计算的文章(如果你知道,请在评论中分享)。 但是从源码来看,计算机制和回收是一样的。 简单来说,就是在内核中再增加一个计数器,直接针对KVM进程(虚拟机进程),统计KVM进程等待CPU时间的时长。 计数器从其规格中获取有关处理器的信息,并检查虚拟机进程是否使用了其所有滴答声。 如果仅此而已,那么我们假设处理器仅被虚拟机进程占用。 否则,我们会通知处理器正在做其他事情,出现了窃取。

偷窃计数过程会遇到与常规回收计数相同的问题。 并不是说此类问题经常出现,但它们看起来令人沮丧。

2.2. KVM 上的虚拟化类型

广义上讲,虚拟化有三种类型,KVM 都支持这三种类型。 窃取发生的机制可能取决于虚拟化的类型。

翻译。 在这种情况下,虚拟机操作系统与物理管理程序设备的操作会发生如下情况:

  1. 客户操作系统向其客户设备发送命令。
  2. 来宾设备驱动程序接收命令,生成对设备 BIOS 的请求并将其发送到管理程序。
  3. 虚拟机管理程序进程将物理设备的命令转换为命令,从而使其更加安全。
  4. 物理设备驱动程序接受修改后的命令并将其发送到物理设备本身。
  5. 执行命令的结果沿着相同的路径返回。

翻译的优点是它允许您模拟任何设备并且不需要特殊准备操作系统内核。 但你必须为此付出代价,首先是速度。

硬件虚拟化。 在这种情况下,硬件级别的设备可以理解来自操作系统的命令。 这是最快、最好的方法。 但不幸的是,并非所有物理设备、虚拟机管理程序和来宾操作系统都支持它。 目前支持硬件虚拟化的主要设备是处理器。

半虚拟化。 KVM 上设备虚拟化的最常见选项,通常也是来宾操作系统最常见的虚拟化模式。 其特点是使用虚拟机管理程序 API 来处理某些虚拟机管理程序子系统(例如,网络或磁盘堆栈)或分配内存页面,而无需转换低级命令。 这种虚拟化方法的缺点是必须修改来宾操作系统内核,以便它可以使用此 API 与虚拟机管理程序进行通信。 但这通常可以通过在来宾操作系统上安装特殊驱动程序来解决。 在 KVM 中这个 API 被称为 virtio API.

与广播相比,使用半虚拟化,通过直接从虚拟机向主机上的虚拟机管理程序进程发送命令,可以显着减少到物理设备的路径。 这使您可以加快虚拟机内所有指令的执行速度。 在 KVM 中,这是通过 virtio API 完成的,它仅适用于某些设备,例如网络或磁盘适配器。 这就是 virtio 驱动程序安装在虚拟机内的原因。

这种加速的缺点是,并非所有在虚拟机内运行的进程都保留在虚拟机内。 这会产生一些特殊效果,可能导致偷窃时生成。 我建议开始详细研究这个问题 虚拟 I/O 的 API:virtio.

2.3. “公平”调度

Hypervisor上的虚拟机实际上是一个普通的进程,遵守Linux内核中的调度(进程之间的资源分配)规律,所以让我们仔细看看它。

Linux使用所谓的CFS,Completely Fair Scheduler,从内核2.6.23开始它已经成为默认的调度器。 要理解这个算法,可以阅读Linux内核架构或者源代码。 CFS 的本质是根据进程的执行持续时间在进程之间分配处理器时间。 进程需要的 CPU 时间越多,它获得的 CPU 时间就越少。 这确保了所有进程都“公平”地执行——这样一个进程就不会一直占用所有处理器,而其他进程也可以执行。

有时,这种范例会产生有趣的工件。 Linux 的长期用户可能还记得,在运行编译器等资源密集型应用程序时,桌面上的常规文本编辑器会冻结。 发生这种情况是因为桌面应用程序中的非资源密集型任务与资源密集型任务(例如编译器)竞争。 CFS 认为这是不公平的,因此它定期停止文本编辑器并让处理器处理编译器的任务。 这是使用一种机制纠正的 sched_autogroup,但任务之间处理器时间分配的许多其他特征仍然存在。 实际上,这并不是一个关于 CFS 中一切有多糟糕的故事,而是试图引起人们注意这样一个事实:“公平”分配处理器时间并不是最微不足道的任务。

调度程序中的另一个重要点是抢占。 这是从处理器中踢出窃笑进程并让其他进程正常工作所必需的。 弹出过程称为上下文切换。 在这种情况下,任务的整个上下文都被保留:堆栈、寄存器等的状态,之后进程被发送等待,另一个进程取代它的位置。 对于操作系统来说,这是一项昂贵的操作,并且很少使用,但它本身并没有什么问题。 频繁的上下文切换可能表明操作系统存在问题,但通常它是连续的并且并不表明任何具体情况。

需要这么长的故事来解释一个事实:一个进程在诚实的 Linux 调度程序中尝试消耗的处理器资源越多,它就会越快停止,以便其他进程也可以工作。 这是否正确是一个复杂的问题,可以在不同的负载下以不同的方式解决。 在 Windows 中,直到最近,调度程序都专注于桌面应用程序的优先级处理,这可能会导致后台进程冻结。 Sun Solaris 有五种不同类别的调度程序。 当我们推出虚拟化时,我们添加了第六个, 公平份额调度程序,因为前五个无法与 Solaris Zones 虚拟化充分配合。 我建议通过以下书籍开始详细研究这个问题 Solaris 内部结构:Solaris 10 和 OpenSolaris 内核体系结构 или 了解 Linux 内核.

2.4. 如何监控盗窃行为?

与任何其他处理器指标一样,监控虚拟机内部的窃取情况很简单:您可以使用任何处理器指标工具。 最主要的是虚拟机是在Linux上的。 由于某种原因,Windows 不向其用户提供此信息。 🙁

窃取:谁从虚拟机窃取 CPU 时间
top 命令的输出:处理器负载的详细信息,在最右边的列中 - 窃取

当尝试从虚拟机管理程序获取此信息时会出现困难。 您可以尝试预测主机上的窃取,例如,使用平均负载 (LA) 参数 - 在执行队列中等待的进程数的平均值。 计算这个参数的方法并不简单,但一般来说,如果按处理器线程数归一化的LA大于1,则表明Linux服务器过载。

所有这些进程都在等待什么? 显而易见的答案是处理器。 但答案并不完全正确,因为有时处理器是免费的,但 LA 却超出了规模。 记住 NFS 如何衰落以及 LA 如何发展。 磁盘和其他输入/输出设备也会发生同样的情况。 但事实上,进程可以等待任何锁的结束,无论是物理锁(与 I/O 设备关联)还是逻辑锁(例如互斥锁)。 这还包括硬件级别的锁定(与磁盘的响应相同)或逻辑级别(所谓的锁定原语,其中包括一堆实体、互斥自适应和自旋、信号量、条件变量、rw 锁、ipc 锁) ...)。

LA 的另一个特点是它被视为操作系统的平均值。 例如,100个进程竞争一个文件,那么LA=50。 如此大的值似乎表明操作系统很糟糕。 但对于其他歪曲编写的代码来说,这可能是一种正常状态,尽管事实上只有它是坏的,操作系统中的其他进程不会受到影响。

由于这种平均(并且不少于一分钟),通过 LA 指标确定任何内容都不是最有价值的任务,在特定情况下结果非常不确定。 如果您尝试弄清楚,您会发现维基百科和其他可用资源上的文章仅描述了最简单的情况,而没有对该过程进行深入的解释。 我再次向所有感兴趣的人发送, 布伦丹·格雷格  - 请点击下面的链接。 谁懒得说英语—— 他关于洛杉矶的热门文章的翻译.

3.特效

现在我们来看看我们遇到的主要盗窃案例。 我将告诉您它们是如何从上述所有内容中得出的,以及它们与虚拟机管理程序上的指标有何关系。

回收。 最简单也是最常见的:hypervisor已经被复用了。 事实上,有很多正在运行的虚拟机,它们内部的处理器消耗很高,竞争很多,LA利用率大于1(通过处理器线程标准化)。 所有虚拟机内的所有内容都会变慢。 从管理程序传输的窃取也在增长,有必要重新分配负载或关闭某人。 一般来说,一切都是合乎逻辑且可以理解的。

半虚拟化与单实例。 虚拟机管理程序上只有一个虚拟机;它消耗其中的一小部分,但会产生大量 I/O 负载,例如在磁盘上。 并且从某个地方出现了一小部分偷窃,最多可达 10%(如多个实验所示)。

这个案子很有趣。 Steal 出现在这里正是因为半虚拟化驱动程序级别的阻塞。 中断在虚拟机内部创建,由驱动程序处理并发送到管理程序。 由于虚拟机管理程序上的中断处理,对于虚拟机来说,它看起来像是一个已发送的请求,它已准备好执行并正在等待处理器,但没有给予它处理器时间。 虚拟女孩认为这次被偷了。

这发生在缓冲区被发送的那一刻,它进入虚拟机管理程序的内核空间,我们开始等待它。 虽然,从虚拟机的角度来看,他应该立即返回。 因此,根据窃取计算算法,这次就被认为是被窃取了。 最有可能的是,在这种情况下可能存在其他机制(例如,处理一些其他系统调用),但它们应该没有太大不同。

调度程序与高负载虚拟机。 当一台虚拟机比其他虚拟机遭受更多窃取时,这是由于调度程序造成的。 进程加载处理器的次数越多,调度程序就会越早将其踢出,以便其他进程也可以工作。 如果虚拟机消耗很少,它几乎不会看到窃取:它的进程诚实地坐着等待,我们需要给它更多的时间。 如果虚拟机在其所有核心上产生最大负载,它通常会被处理器踢出,并且他们会尽量不给它太多时间。

当虚拟机内的进程因为无法处理数据处理而尝试获得更多处理器时,情况会更糟。 那么虚拟机管理程序上的操作系统,由于诚实的优化,将提供越来越少的处理器时间。 这个过程就像雪崩一样发生,偷跳到天空,尽管其他虚拟机可能很难注意到它。 核心越多,受影响的机器就越糟糕。 简而言之,具有多个核心的高负载虚拟机受到的影响最大。

低洛杉矶,但有偷窃。 如果 LA 约为 0,7(即虚拟机管理程序似乎负载不足),但在各个虚拟机内部观察到窃取:

  • 上面已经描述了半虚拟化选项。 尽管虚拟机管理程序没有问题,但虚拟机可以接收指示窃取的指标。 根据我们的实验结果,这种窃取选项不会超过 10%,并且不会对虚拟机内部应用程序的性能产生重大影响。
  • LA参数计算错误。 更准确地说,在每个特定时刻,它的计算都是正确的,但当平均一分钟时,它就会被低估。 例如,如果虚拟机管理程序的三分之一的虚拟机消耗其所有处理器正好半分钟,则虚拟机管理程序上每分钟的 LA 将为 0,15; 四个这样的虚拟机同时工作将给出 0,6。 根据 LA 指标,他们每个人在半分钟内都有 25% 的疯狂抢断,这一事实已无法再被撤销。
  • 再次,因为调度员认为某人吃得太多并让某人等待。 与此同时,我将切换上下文、处理中断并处理其他重要的系统事务。 因此,某些虚拟机没有发现任何问题,而另一些虚拟机则出现严重的性能下降。

4.其他扭曲

还有一百万个原因会扭曲虚拟机上处理器时间的公平返回。 例如,超线程和NUMA给计算带来了困难。 它们完全混淆了执行进程的内核的选择,因为调度程序使用系数 - 权重,这使得切换上下文时的计算更加困难。

由于睿频加速或节能模式等技术而导致失真,在计算利用率时,可以人为地增加或减少服务器上的频率甚至时间片。 启用睿频加速会降低一个处理器线程的性能,因为另一个处理器线程的性能会提高。 此时,有关当前处理器频率的信息不会传输到虚拟机,并且虚拟机认为有人正在窃取其时间(例如,它请求 2 GHz,但收到了一半)。

一般来说,造成失真的原因有很多。 您可能会在特定系统上找到其他东西。 最好从我上面提供链接的书籍开始,并使用 perf、sysdig、systemtap 等实用程序从虚拟机管理程序检索统计信息,其中 几十个.

5。 发现

  1. 由于半虚拟化,可能会出现一定程度的窃取,这可以认为是正常的。 他们在网上写到这个值可以是5-10%。 取决于虚拟机内的应用程序以及它施加在物理设备上的负载。 这里重要的是要注意应用程序在虚拟机中的感受。
  2. 虚拟机管理程序上的负载与虚拟机内部的窃取的比率并不总是明显相关;在不同负载下的特定情况下,两种窃取的估计都可能是错误的。
  3. 调度程序对要求太多的进程态度不好。 他试图为那些要求更多的人提供更少的东西。 大型虚拟机是邪恶的。
  4. 即使没有半虚拟化,少量窃取也可能是常态(考虑到虚拟机内部的负载、邻居负载的特征、跨线程的负载分配和其他因素)。
  5. 如果你想弄清楚特定系统中的窃取情况,你必须探索各种选项,收集指标,仔细分析它们并考虑如何均匀分配负载。 任何情况下的偏差都是可能的,这必须通过实验来确认或在内核调试器中查看。

来源: habr.com

添加评论