
嗨! 在本文中,我想以通俗易懂的方式解释
窃取如何在虚拟机中出现,并告诉您一些有关在我作为
邮件 CTO参与的主题的研究过程中发现的不太明显的工件
。 com云解决方案平台。 该平台运行KVM。
CPU窃取时间是指VM无法接收到所需的资源来运行的时间。 此时间只能在虚拟化环境中的来宾OS中计算。 就像在现实生活中一样,目前还不清楚分配的资源在哪里丢失。 但是,我们决定解决这个问题,我们甚至进行了一系列测试。 这并不是说我们对
盗窃一无所知
,但我们希望与您分享一些有趣的事情。
1.什么是偷窃 ?
窃取是一种指标,表明VM进程缺少CPU时间。 如
KVM内核补丁中所述 ,
窃取是虚拟机管理程序花费时间在VM进程处于运行队列中时在主机OS中运行其他进程的时间。 换句话说,
窃取被计算为进程准备运行的时刻与为该进程分配CPU时间之间的差。
VM内核从管理程序获取
窃取指标。 系统管理程序未指定其正在运行的进程。 它只是说:“我很忙,不能给您分配任何时间。” 在KVM中,
补丁程序支持
窃取计算。 关于此点有两个要点:
- VM从管理程序了解窃取 。 这意味着就损失而言, 窃取是一种间接测量,可以通过多种方式进行失真。
- 虚拟机管理程序不会与VM共享有关其占用的信息。 最关键的一点是它没有分配时间。 因此,VM本身无法检测到窃取度量标准中的失真,这可以通过竞争进程的性质来估计。
2.什么会影响盗窃 ?
2.1。 计算偷窃
本质上,
窃取的计算方式与CPU利用率时间大致相同。 关于如何计算利用率的信息不多。 这可能是因为大多数专业人士认为这很明显。 但是,有一些陷阱。
Brendann Gregg在
一篇文章中描述了该过程。 他讨论了有关如何计算利用率和错误计算场景的许多细微差别:
- CPU过热和节流。
- 打开/关闭Turbo Boost,导致CPU时钟频率改变。
- 使用CPU节电技术(例如SpeedStep)时发生的时间片更改。
- 与计算平均值有关的问题:以80%的功率测量一分钟的利用率可能会在短期内隐藏100%的提升。
- 自旋锁导致使用处理器但用户进程无法进行的情况。 结果,计算出的CPU利用率将为100%,但是该进程实际上不会消耗CPU时间。
我还没有看到任何描述这种
偷窃计算方法的文章(如果您知道的话,请在评论部分中分享)。 从源代码中可以看到,计算机制与利用率相同。 唯一的不同是专门为KVM进程(VM进程)添加了另一个计数器,该计数器计算KVM进程等待CPU时间的时间。 计数器从其规格中获取CPU上的数据,并检查VM进程是否正在使用其所有的滴答声。 如果所有刻度都被使用,则表明CPU仅忙于VM进程。 否则,我们知道CPU正在执行其他操作并出现
盗窃 。
计算
窃取的过程与常规使用率计算存在相同的问题。 这些问题并不常见,但可能会引起混乱。
2.2。 KVM虚拟化的类型
通常,虚拟化有三种类型,并且都由KVM支持。 发生
窃取的机制可能取决于虚拟化的类型。
笔译 在这种情况下,VM OS将通过以下方式与物理管理程序设备一起使用:
- 来宾OS向其来宾设备发送命令。
- 来宾设备驱动程序接受该命令,创建BIOS设备请求,然后将该命令发送到管理程序。
- 系统管理程序进程将命令转换为物理设备命令,从而使其更加安全。
- 物理设备驱动程序接受修改后的命令,并将其转发给物理设备本身。
- 命令的执行结果返回相同的路径。
转换的优点是它允许我们模拟任何设备,并且不需要特殊准备OS内核。 但这是以性能为代价的。
硬件虚拟化。 在这种情况下,设备会在硬件级别上从OS接收命令。 这是最快,总体上最好的方法。 不幸的是,并非所有物理设备,虚拟机管理程序和来宾操作系统都支持它。 目前,支持硬件虚拟化的主要设备是CPU。
半虚拟化。 KVM上的设备虚拟化的最常见选项,以及来宾OS的最广泛的虚拟化类型。 它的主要特征是它可以与某些虚拟机监控程序子系统(例如网络或驱动器堆栈)一起使用,并使用虚拟机监控程序API分配内存页面,而无需转换低级命令。 这种虚拟化方法的缺点是需要修改来宾OS的内核,以允许使用相同的API与管理程序进行交互。 解决此问题的最常见方法是在来宾操作系统中安装特殊的驱动程序。 在KVM中,此API称为
virtio API 。
使用半虚拟化时,到物理设备的路径比使用转换时要短得多,这是因为命令直接从VM发送到主机中的管理程序进程。 这加速了VM中所有指令的执行。 在KVM中,需要使用virtio API。 它仅适用于某些设备,例如网络和驱动器适配器。 这就是将virtio驱动程序安装到VM的原因。
这种加速的不利方面是,并非在VM中执行的所有进程都留在VM中。 这导致产生多种影响,这可能会导致
偷窃 。 如果您想了解更多信息,请从
用于虚拟I / O的API开始
:virtio 。
2.3。 公平安排
实际上,虚拟机管理程序上的VM是一个常规进程,它受Linux内核中的调度规则(进程之间的资源分配)约束。 让我们仔细看看。
Linux使用所谓的CFS,完全公平调度程序,它在内核2.6.23中成为默认设置。 要了解此算法,请阅读Linux Kernel Architecture或源代码。 CFS的本质在于进程之间的CPU时间分配,具体取决于它们的运行时间。 一个进程需要的CPU时间越长,它获得的CPU时间就越少。 这保证了所有进程的“公平”执行,并有助于避免一个进程一直占用所有处理器,并允许其他进程也运行。
有时,这种范例会产生有趣的伪像。 长期使用Linux的用户无疑会记得,当运行诸如编译器之类的资源密集型应用程序时,桌面上的常规文本编辑器将如何冻结。 之所以发生这种情况,是因为资源轻的任务(例如桌面应用程序)正在与使用许多资源的任务(例如编译器)竞争。 CFS认为这是不公平的,因此它会不时停止文本编辑器,并让CPU处理编译器任务。 这是使用
sched_autogroup机制修复的; 但是,CPU时间分配还有许多其他特性。 本文并不是真的关于CFS有多糟糕。 这是一种试图引起人们注意的事实,即“公平”分配CPU时间并不是最琐碎的任务。
调度程序的另一个重要方面是抢占。 这对于消除CPU过度沉迷的进程并允许其他进程也很有用。 这称为
上下文切换 。 整个任务上下文将保留:堆栈状态,寄存器等,然后让该进程等待,并由另一个进程替换。 对于OS,这是一项昂贵的操作。 它很少使用,但实际上一点也不差。 频繁的上下文切换可能是操作系统问题的指示,但它通常会连续发生,并且尤其不表示任何问题。
冗长的论述对于解释一个事实是必要的:在一个公平的Linux调度程序中,进程消耗的CPU资源越多,停止它以允许其他进程工作的速度就越快。 这是否正确是一个复杂的问题,解决方案因负载而异。 直到最近,Windows Scheduler仍对桌面应用程序进行了优先排序,这导致后台进程变慢。 在Sun Solaris中,有五个不同的调度程序类。 引入虚拟化后,他们又添加了一个
公平共享调度程序 ,因为其他应用程序无法在Solaris Zones虚拟化中正常运行。 为了更深入地了解这一点,我建议从
Solaris Internals:Solaris 10和OpenSolaris内核体系结构或
了解Linux内核开始 。
2.4。 我们如何监视盗窃 ?
就像其他任何CPU指标一样,很容易监控VM内部的
窃取 。 您可以使用任何CPU指标测量工具。 最主要的是,VM必须在Linux上。 由于某些原因,Windows不会向用户提供此类信息。 :(
顶部输出:CPU负载的规格,右列中包含尝试从管理程序获取此信息时,事情变得很复杂。 例如,您可以尝试使用平均负载(LA)预测主机上的
窃取 。 这是运行队列中进程数的平均值。 此参数的计算方法不是一种简单的方法,但通常,如果根据CPU线程数标准化的LA大于1,则意味着Linux服务器过载。
那么,所有这些过程还在等待什么呢? 显然,CPU。 但是,此答案不太准确,因为有时CPU空闲,而LA太高。 请记住
,NFS下降而LA同时上升 。 驱动器和其他输入/输出设备可能会发生类似情况。 实际上,进程可能正在等待锁的结束:物理(与输入/输出设备有关)或逻辑(例如,互斥对象)。 对于硬件级锁(例如,磁盘响应)或逻辑级锁(所谓的“锁定原语”,包括许多实体,互斥量自适应和自旋,信号量,条件变量,rw锁, ipc锁...)。
LA的另一个功能是将其计算为OS内的平均值。 例如,如果100个进程争用一个文件,则LA为50。这个很大的数字可能看起来对操作系统不利。 但是,对于写得不好的代码,这可能是正常的。 只有那个特定的代码会是不好的,而其余的OS可能会很好。
由于这种平均(少于一分钟),因此使用LA确定任何内容都不是最好的主意,因为在某些情况下,它可能会产生极其模糊的结果。 如果您尝试查找有关此内容的更多信息,则会发现Wikipedia和其他可用资源仅描述了最简单的情况,并且未详细描述该过程。 如果您对此感兴趣,请再次访问
Brendann Gregg并点击链接。
3.特效
现在,让我们了解一下我们遇到的主要
盗窃案件。 让我解释一下它们是如何产生上述结果的,以及它们与虚拟机管理程序指标之间的关系。
过度利用。 最简单,最常见的情况是:管理程序被过度利用。 确实,随着许多VM运行并消耗大量CPU资源,竞争非常激烈,根据LA的利用率大于1(根据CPU线程标准化)。 一切都滞留在所有VM中。 从虚拟机监控程序发送的
窃取也会增加。 您必须重新分配负载或关闭电源。 总体而言,这是合乎逻辑和直接的。
半虚拟化与单个实例。 虚拟机管理程序上只有一个VM。 VM仅消耗一小部分,但提供较高的输入/输出负载(例如,驱动器)。 出乎意料的是,出现的
窃取率不到10%(正如我们进行的一些测试所示)。
这是一个奇怪的情况。 在这里,由于半虚拟化设备级别上的锁定而出现
盗窃 。 在VM内部,将创建一个断点。 这由驱动程序处理,然后转到管理程序。 由于在管理程序上进行了断点处理,因此VM将其视为已发送的请求。 它已准备就绪,可以运行并等待CPU,但是没有收到CPU时间。 VM认为时间已被盗。
发送缓冲区时会发生这种情况。 它进入虚拟机管理程序的内核空间,我们等待它。 从VM的角度来看,它应该立即返回。 因此,根据我们的
窃取计算算法,这次被认为是被盗。 其他机制可能也可能参与其中(例如,其他
sys调用的处理),但是它们之间不应有任何重大差异。
调度程序与高负载虚拟机。 当一个虚拟机遭受的
窃取比其他虚拟机更多时,这将直接与调度程序连接。 进程对CPU的负载越大,调度程序将其扔出的速度就越快,以便允许其他进程正常工作。 如果虚拟机消耗很少,则几乎不会
被盗。 它的过程一直处于等待状态,需要给予更多时间。 如果VM在所有内核上都施加了最大负载,则该过程将被更频繁地丢弃,并且为VM提供的时间更少。
当VM中的进程试图获取更多的CPU时,甚至更糟,因为它们无法处理数据。 然后,由于合理的优化,虚拟机监控程序上的操作系统将提供更少的CPU时间。 这个过程雪上加霜,并且
窃取的浪潮飞速上升,而其他VM可能甚至没有注意到它。 内核越多,不幸的VM越差。 简而言之,具有多个内核的高负载VM受害最大。
低LA,但存在
抢断 。 如果LA约为0.7(这意味着管理程序似乎负载不足),但是某些VM会被
窃取 :
- 前面提到的半虚拟化示例适用。 VM可能正在接收指示“ 偷”的指标,而虚拟机管理程序没有问题。 根据我们的测试结果,这种盗用趋势不会超过10%,并且不会对VM中的应用程序性能产生重大影响。
- LA参数计算错误。 更准确地说,它已在特定时刻正确计算,但是在平均时,它在一分钟内低于应有的值。 例如,如果一个虚拟机(系统管理程序的三分之一)消耗了所有CPU 30秒,那么一分钟的LA将为0.15。 四个同时运行的VM的值为0.6。 基于洛杉矶,您将无法推断出每人30秒的抢断率接近25%。
- 同样,这是由于调度程序而发生的,该调度程序决定某人“吃”得太多,并让他们等待。 同时,它将切换上下文,处理断点并处理其他重要的系统事务。 结果,一些虚拟机没有任何问题,而其他虚拟机则遭受了严重的性能损失。
4.其他变形
有100万个可能的原因导致VM上的CPU时间分配不合理。 例如,超线程和NUMA增加了计算的复杂性。 因为调度程序使用系数,所以它们使用于运行进程的核心的选择复杂化。 也就是说,权重使切换上下文时的计算更加复杂。
诸如Turbo Boost或相反的省电模式之类的技术会产生一些失真,这些失真可能会人为地增加或降低CPU核心速度甚至时间片。 由于另一线程的性能提高,因此启用Turbo Boost会降低一个CPU线程的生产率。 那时,有关当前CPU时钟速度的信息没有发送到VM,VM认为有人正在窃取时间(例如,它请求2 GHz的时间是原来的一半)。
实际上,可能有许多导致失真的原因。 您可能会在任何给定系统中完全找到其他内容。 我建议从上面链接的书开始,并使用诸如perf,sysdig,systemtap之类的工具从管理程序中获取统计信息。
5.结论
- 由于半虚拟化,可能会出现一些盗窃行为 ,这可以认为是正常现象。 在线消息人士说,该值可以为5-10%。 它取决于VM中的应用程序,以及VM对其物理设备施加的负载。 重要的是要注意应用程序在虚拟机内部的感觉。
- 虚拟机管理程序上的负载与VM中的窃取之间的相关性并不总是确定的。 在某些情况下以及负载不同时,两种窃取计算都可能是错误的。
- 调度程序不赞成需要大量资源的进程。 它试图减少那些要求更多的人。 大实例是卑鄙的。
- 在没有半虚拟化的情况下,小偷也是正常的(考虑到VM内的负载,邻居负载的特殊性,线程之间的负载分布以及其他因素)。
- 如果您想计算特定系统中的窃取率 ,请研究各种可能性,收集指标,进行彻底分析,然后考虑如何公平地分配负载。 无论如何,都可能存在偏差,必须使用测试进行验证或在内核调试器中查看这些偏差。