Docker容器、虚拟机和裸机运行的性能比较_tiknovel-最新最全的nft,web3,AI技术资讯技术社区

Docker容器、虚拟机和裸机运行的性能比较

2022-12-18 19:58:12  浏览:2158  作者:管理员
Docker容器、虚拟机和裸机运行的性能比较

编者按:

大家一直对虚拟机和容器的性能损耗都有一定的认识,但具体多少应该没有几个人能说清楚。这篇文章详细的评测了相关的应用场景在容器、虚拟机、裸机三种场景下的性能对比,相信会对大家有所帮助。

参考链接:

An Updated Performance Comparison of Virtual Machines and Linux Containers, IBM Research
https://dominoweb.draco.res.ibm.com/reports/rc25482.pdf

摘要

云计算大量使用虚拟机(VM),因为可以通过VM把工作负载彼此隔离,并在一定程度上控制资源使用。然而,虚拟化所涉及的额外抽象代价降低了工作负载的性能,并将其作为成本和性能降低转嫁给了客户。基于容器的虚拟化简化了应用程序的部署,同时仍允许对分配给不同应用程序的资源进行控制。

在本文中,我们探讨了传统虚拟机部署的性能,并将其与Linux容器的使用进行了对比。我们使用一组工作负载,对CPU、内存、存储和网络资源造成压力。我们使用KVM作为虚拟化的Hypervisor,使用Docker作为容器管理器。我们的结果显示,在几乎所有情况下,容器的性能都与VM相同或更好。VM和容器都需要优化以支持IO密集型应用程序。我们还讨论了性能结果对未来云架构的影响。

1 介绍

虚拟机广泛应用于云计算中。特别是,基础设施即服务(Infrastructure as a Service, IaaS)中的最新技术在很大程度上等同于虚拟机。像Amazon EC2这样的云平台让用户可以使用VM,也可以在VM中运行数据库这样的服务。许多“平台即服务”(PaaS)和“软件即服务”(SaaS)提供商都构建在IaaS之上,它们的所有工作负载都运行在VM中。由于目前几乎所有的云工作负载都在VM中运行,所以VM性能是整体云性能的关键部分。一旦Hypervisor的开销增加,没有任何其他层的手段可以删除它。这样的开销将成为云工作负载性能的普遍负担。有许多研究显示了VM执行与裸机执行的对比情况,此类研究已经成为普遍提高VM技术质量的一个激励因素。

基于容器的虚拟化为云中的虚拟机提供了一个有趣的替代方案。虚拟专用服务器提供商,可能被视为云计算的先驱,已经使用容器超过十年了。但他们中的许多人转向VM以提供更一致的性能。尽管很好地理解了名称空间等容器的基础概念,但是容器技术一直处于停滞状态,直到因为需要快速部署的需要,PaaS提供者采用并标准化了容器,使得采用容器来提供隔离和资源控制的复兴。Linux由于其免费、庞大的生态系统、良好的硬件支持、良好的性能和可靠性而成为云计算的首选操作系统。在Linux中实现容器所需的内核名称空间特性很早前就被讨论,但直到最近几年才变得成熟。在过去的两年中,Docker已经成为Linux容器的标准运行时、镜像格式和构建系统。

本文着眼于目前实现资源控制的两种不同方式,即容器和虚拟机,并比较了两种环境中一组工作负载的性能,以及与无虚拟化环境的性能。除了一系列强调计算、内存带宽、内存延迟、网络带宽和I/O带宽等不同方面的基准测试外,我们还探讨了两个真实应用程序的性能,即Redis和MySQL在不同环境下的性能。

我们的目标是隔离并理解虚拟机(特别是KVM)和容器(特别是Docker)相对于非虚拟化Linux所带来的开销。我们希望其他管理程序,如Xen、VMware ESX和Microsoft Hyper-V,能够提供与KVM类似的性能,因为它们使用相同的硬件加速特性。同样地,当其他容器工具使用相同的机制时,它们应该具有与Docker相同的性能。我们不评估在VM中运行容器或在容器中运行VM的情况,因为我们认为这种双重虚拟化是冗余的(至少从性能角度来看)。Linux可以同时承载VM和容器,这一事实为这两种技术之间的相互比较创造了机会——与以前的许多比较相比,混淆变量更少一些。

我们做出了如下贡献:

  • 我们提供了一个本地、容器和虚拟机环境的最新比较,使用最新的硬件和软件,以及与云相关的有趣的基准测试和工作负载。

  • 我们确定了当前虚拟化选项对高性能计算和服务器工作负载的主要性能影响。

  • 我们详细阐述了一些影响虚拟化性能的不明显的实际问题。

  • 我们证明,即使在整个服务器的规模下,容器也是可行的,且对性能的影响很小。

本文的其余部分组织如下。第二节描述Docker和KVM,为理解论文的其余部分提供必要的背景。第三节描述并评估这三个环境上的不同工作负载。第四部分对相关工作进行了回顾,第五部分对全文进行了总结。

2 背景

2.1 云虚拟化的动机和要求

Unix传统上并没有强烈地实现最小权限原则,即“系统的每个程序和每个用户都应该使用完成工作所需的最小权限集进行操作。”以及最不常见的机制原则,即“每个共享机制……代表了用户之间的潜在信息路径,在设计时必须非常小心,以确保它不会无意地危及安全性。”Unix中的大多数对象,包括文件系统、进程和网络堆栈,对所有用户都是全局可见的。

Unix的共享全局文件系统造成的一个问题是缺乏配置隔离。多个应用程序可能对系统范围的配置设定有冲突的要求。共享库依赖关系尤其有问题,因为现代应用程序使用许多库,而且不同的应用程序通常需要相同库的不同版本。当在一个操作系统上安装多个应用程序时,系统管理的成本可能超过软件本身的成本。

普通服务器操作系统中的这些弱点导致管理员和开发人员通过将每个应用程序安装在单独的操作系统副本上(或者在专用服务器上,或者在虚拟机上)来简化部署。与共享服务器相比,这种隔离与在应用程序之间共享任何代码、数据或配置所需的显式操作恰恰相反。

不管环境如何,客户都想要得到他们为之付费的性能。与基础设施和工作负载属于同一家公司的企业整合场景不同,在IaaS和PaaS中,提供者和客户之间存在一种独立的关系。这使得解决性能异常变得困难,所以*aaS提供商通常提供固定的容量单位(CPU内核和RAM),而没有超额订阅。虚拟化系统需要强制执行这种资源隔离,以适应云基础设施的使用。

2.2 KVM

内核虚拟机(KVM)是Linux的一个特性,它允许Linux充当类型1的Hypervisor,在Linux进程中运行未经修改的Guest操作系统(OS)。KVM在较新的处理器中使用硬件虚拟化特性来降低复杂性和开销;例如,Intel VT-x硬件消除了对复杂的Ring压缩方案的需要,而这些方案是由早期的hypervisor,如Xen和VMware,所开创的。KVM既支持通过QEMU模拟I/O设备,也支持使用virtio的半虚拟(paravirtual)I/O设备。硬件加速和半虚拟I/O的结合是为了将虚拟化开销降低到非常低的水平。KVM支持实时迁移,允许腾出物理服务器甚至整个数据中心进行维护,而不会中断Guest操作系统。KVM也很容易通过libvirt等工具来管理。

因为虚拟机有静态数量的虚拟CPU (vCPU)和固定数量的RAM,它的资源消耗自然是有限的。一个vCPU不能使用一个以上的实际CPU周期,vRAM的每一页最多映射到物理RAM的一页(加上嵌套的页表)。KVM可以在运行时通过“热插拔”和“气球”vCPU和vRAM来调整虚拟机的大小,尽管这需要客户操作系统的支持,并且在云中很少使用。

因为每个虚拟机都是一个进程,所以所有普通的Linux资源管理工具,如调度和cgroups(稍后将详细描述)都适用于虚拟机。这简化了Hypervisor的实现和管理,但使Guest操作系统内的资源管理变得复杂。操作系统通常假定CPU一直在运行,内存具有相对固定的访问时间,但在KVM下,vCPU可以在不通知的情况下被取消调度,虚拟RAM可以被换出,从而导致难以调试的性能异常。虚拟机也有两个级别的分配和调度:一个在hypervisor中,另一个在Guest操作系统中。许多云提供商通过不过度使用资源、将每个vCPU固定到一个物理CPU、将所有虚拟RAM锁定到实际RAM来解决这些问题。(不幸的是,OpenStack还没有启用vCPU钉住功能,导致与私有公有云相比性能参差不齐。)这基本上消除了系统管理程序中的调度。这种固定的资源分配也简化了计费。

由于狭窄的接口,虚拟机自然的提供了一定级别的隔离和安全;VM与外部世界通信的唯一方式是通过有限数量的超hypercall或模拟设备,它们都由hypervisor控制。这不是灵丹妙药,因为已经发现了一些Hypervisor特权升级漏洞,它们可能允许Guest操作系统“打破”其VM“沙箱”。

虽然VM擅长隔离,但当在Guest之间或Guest和Hypervisor之间共享数据时,它们增加了开销。通常,这种共享需要相当昂贵的编组和hypercall。在云中,虚拟机通常通过映像文件支持的模拟块设备访问存储;创建、更新和部署这样的磁盘映像可能非常耗时,而包含大部分重复内容的磁盘映像集合可能会浪费存储空间。

2.3 Linux容器

与虚拟硬件上运行完整操作系统不同,基于容器的虚拟化通过修改操作系统以提供额外的隔离。通常,这包括向每个进程添加一个容器ID,并向每个系统调用添加新的访问控制检查。因此,容器可以看作是除了用户和组权限系统之外的另一个级别的访问控制。在实践中,Linux使用下面描述的更复杂的实现。

Linux容器是一个建立在内核命令空间特性上的概念,最初是用于处理高性能计算集群场景而产生的。这个特性可以被clone()系统调用访问,允许创建之前全局名称空间的独立实例。Linux实现了文件系统、PID、网络、用户、IPC和主机名名称空间。例如,每个文件系统名称空间都有自己的根目录和挂载表,类似于chroot(),但功能更强大。

名称空间可以通过许多不同的方式使用,但最常见的方法是创建一个隔离的容器,该容器对容器外部的对象屏蔽可见性或访问权。运行在容器内的进程看起来像是运行在普通的Linux系统上,尽管它们与位于其他名称空间中的进程共享底层内核。容器可以分层嵌套,尽管这种功能还没有得到充分的挖掘。

与运行完整操作系统的VM不同,容器可以只包含单个进程。像一个完整的操作系统一样运行init、inetd、sshd、syslogd、cron等的容器称为系统容器,而只运行应用程序的容器称为应用程序容器。这两种类型在不同的情况下都有用。由于应用程序容器不会在冗余管理进程上浪费RAM,因此它通常比同等的系统容器或VM消耗更少的RAM。应用程序容器通常没有独立的IP地址,这在地址缺乏的环境中是一个优势。

如果不希望完全隔离,那么很容易在容器之间共享一些资源。例如,绑定挂载允许一个目录出现在多个容器中,可能在不同的位置。这是在Linux VFS层中有效实现的。容器之间或容器与主机(实际上可能只是父名称空间)之间的通信与普通Linux IPC一样高效。

Linux控制组(cgroups)子系统用于对进程进行分组并管理它们的总资源消耗。它通常用于限制容器的内存和CPU消耗。一个容器可以通过简单地改变其相应的cgroup的限制来调整大小。Cgroups还提供了一种终止容器内所有进程的可靠方法。因为一个容器化的Linux系统只有一个内核,并且内核对容器有完全的可见性,所以只有一个级别的资源分配和调度。

容器资源管理一个未解决的问题是,在容器中运行的进程不知道它们的资源限制。例如,一个进程可以看到系统中所有的CPU,即使它只被允许运行在其中一个子集上运行;这问题,同样适用于内存。如果应用程序试图根据可用的系统总资源分配资源来自动调优自身,那么在资源受限的容器中运行时,它可能会过度分配资源。随着容器的成熟,这一限制可能会得到解决。

安全容器往往比管理Unix权限更简单,因为容器不能访问它不能看到的内容,因此意外的权限越界的可能性大大降低。当使用用户名称空间时,容器内的根用户不会被视为容器外的根用户,这增加了额外的安全性。容器中的主要安全漏洞类型是不感知名称空间的系统调用,因此可能会在容器之间引入意外泄漏。因为Linux系统调用API集是巨大的,审计与名称空间相关BUG的每个系统调用的工作仍在进行中。这样的错误可以通过使用seccomp]将系统调用列入白名单来减轻(以潜在的应用程序不兼容性为代价)。

有几个管理工具可用于Linux容器,包括LXC、systemd-nspawn、lmctfy、Warden和Docker。(有些人将Linux容器称为“LXC”,但这会引起混淆,因为LXC只是管理容器的众多工具之一)。由于其特性集和易用性,Docker迅速成为容器的标准管理工具和镜像格式。Docker的一个关键特性在大多数其他容器工具中都不存在,那就是分层文件系统映像,通常由AUFS (Another UnionFS)提供支持。AUFS提供了一个分层的文件系统堆栈,并允许在容器之间重用这些层,减少了空间使用,简化了文件系统管理。一个操作系统映像可以作为许多容器的基础,同时允许每个容器有自己的修改文件覆盖(例如,应用程序二进制文件和配置文件)。在许多情况下,Docker容器镜像比同等的VM磁盘镜像需要更少的磁盘空间和I/O。这使得在云中部署的速度更快,因为在虚拟机或容器启动之前,映像通常必须通过网络复制到本地磁盘。

尽管本文主要关注稳定状态的性能,但是其他的测试显示,容器的启动速度比VM快得多(在我们的硬件上容器启动速度小于1秒,而VM启动速度为11秒),因为与VM不同,容器不需要启动操作系统的另一个副本。理论上CRIU可以执行容器的动态迁移,但杀死一个容器并启动一个新的可能更快。

3 评价

性能有许多方面。我们关注的是与非虚拟化环境下执行相比的开销问题,因为它减少了用于生产工作的可用资源。因此,我们研究了一个或多个硬件资源被充分利用的场景,并测量了吞吐量和延迟等工作负载指标,以确定虚拟化的开销。

我们的所有测试都是在一台IBM System x3650 M4服务器上执行的,该服务器拥有两个2.4-3.0 GHz Intel Sandy Bridge-EP Xeon E5-2665处理器,共16核(加上超线程)和256 GB RAM。两个处理器/插槽通过QPI链路连接,使其成为一个NUMA系统。这是一个主流服务器配置,与流行的云提供商使用的配置非常相似。我们使用Ubuntu 13.10 (Saucy) 64位,Linux内核为3.11.0,Docker 1.0, QEMU 1.5.0和libvirt 1.1.1。为了一致性,所有的Docker容器使用Ubuntu 13.10的基础镜像,所有的虚拟机使用Ubuntu 13.10的云镜像。

通过使用性能cpufreq调控器为测试禁用电源管理。Docker容器不受cgroups的限制,所以它们可以消耗被测试系统的全部资源。同样,VM配置了32个vCPU和足够的RAM来容纳基准测试的工作集。在一些测试中,我们研究了普通KVM(类似于默认OpenStack配置)和高度调优的KVM配置(类似于EC2等公共云)之间的差异。我们使用微基准测试来分别测量CPU、内存、网络和存储开销。我们还测量了两个实际的服务器应用程序:Redis和MySQL。

3.1 CPU—PXZ

压缩是云工作负载中经常使用的组件。PXZ是一个使用LZMA算法的并行无损数据压缩实用程序。我们使用PXZ 4.999.9beta (build 20130528)来压缩enwik9,这是一个1GB的Wikipedia转储文件,经常用于压缩基准测试。为了专注于压缩而不是I/O,我们使用了32个线程,输入文件缓存在RAM中,输出通过管道传输到/dev/null。我们使用压缩级别2。

WeChat Image_20210520104143.jpg

表1 PXZ、Linkpack、Stream流和随机访问的结果。每个数据点是十次运行的算术平均值。在圆括号"()"中显示与裸机执行的偏差。标准偏差在方括号[]中标识

表1显示了PXZ在不同配置下的吞吐量。正如预期的那样,裸机和Docker的性能非常相似,而KVM的速度要慢22%。我们注意到,通过vCPU固定和暴露缓存拓扑来优化KVM对性能的影响很小。虽然需要进一步实验来确定KVM开销的来源,但我们怀疑这是由于嵌套分页的额外TLB压力造成的。PXZ可能受益于使用大页。

3.2 HPC—Linpack

Linpack解决了一个稠密的线性方程组,使用一种算法,执行LU因子分解与部分枢轴。绝大多数计算操作都是在一个标量与一个向量的双精度浮点乘法中进行的,然后将结果加到另一个向量上。基准测试通常基于线性代数库,该库针对现有的特定机器架构进行了大量优化。我们使用了一个优化的Linpack二进制(版本11.1.2.005),基于Intel Math Kernel Library (MKL)。英特尔MKL具有高度的自适应性,并基于可用的浮点资源(例如,可用的多媒体操作)和系统的缓存拓扑优化自身。默认情况下,KVM不会向VM公开拓扑信息,因此Guest操作系统认为它运行在统一的32个插槽系统上,每个插槽一个核心。

表1显示了Linpack在Linux、Docker和KVM上的性能。在Linux和Docker上的性能几乎是相同的——考虑到在执行过程中很少涉及操作系统,这并不奇怪。然而,未调优的KVM性能明显更差,这说明了采用KVM的工作负载抽象/隐藏硬件细节的成本。由于无法检测系统的确切问题所在,执行采用了更通用的算法,从而导致性能损失。通过调优KVM,将vCPU固定到相应的CPU上,并暴露底层缓存拓扑,可以提高性能,几乎与裸机不相上下。

我们希望这种方法成为其他类似调优、自适应执行的规范,除非系统拓扑被忠实地贯彻到虚拟化环境中。

3.3 内存带宽—STEAM

WeChat Image_20210520104330.jpg
表2 STEAM流组件

STREAM基准测试是一个简单的综合基准测试程序,它在对向量执行简单操作时测量可持续内存带宽。性能由系统的内存带宽决定,而工作集被设计成比缓存大得多。决定性能的主要因素是主存的带宽,以及处理TLB遗漏的成本(我们进一步减少了对大页的使用)。内存访问模式是规则的,硬件预取器通常会锁住访问模式,并进行数据预取。因此,性能取决于内存带宽而不是延迟。基准测试有四个组成部分:COPY、SCALE、ADD和TRIAD,这些在表II中描述。

表1显示了在三个执行环境中STREAM的性能。STREAM的所有四个组件都执行常规内存访问,一旦在TLB中保存了一个页表项,就会访问该页中的所有数据,然后再转到下一页。硬件TLB预取对于这种工作负载也非常有效。因此,在Linux、Docker和KVM上的性能几乎是相同的,中间数据显示在三个执行环境中只有1.4%的差异。

3.4 随机内存访问——随机访问

STREAM基准测试以常规的方式压测内存子系统,允许硬件预取器在将数据用于计算之前从内存中读取数据到缓存。相反,随机访问基准测试是专门为强调随机内存性能而设计的。基准测试将一大块内存初始化为它的工作集,这比缓存或TLB所能达到的范围大很多个数量级。读取、修改(通过一个简单的异或操作)并写回内存中的随机8字节单词。随机位置是通过使用不需要存储器操作的线性反馈移位寄存器产生的。因此,连续操作之间不存在依赖关系,允许多个独立操作在系统中流动。随机访问代表了具有大工作集和最小计算量的工作负载的行为,比如那些具有内存哈希表和内存数据库的工作负载。

和STREAM一样,随机访问使用大页面来减少TLB未命中的开销。因为它的随机内存访问模式和一个大于TLB范围的工作集,随机访问显著地使用硬件页表遍历器来处理TLB失败。如表1所示,在我们的双路服务器系统上,这对于虚拟化和非虚拟化环境都有相同的开销。

3.5 网络带宽——nuttcp

我们使用nuttcp工具来测量系统的网络性能,待测系统与另一台机器之间通过两张Mellanox ConnectX-2 EN网卡直连,CX2网卡提供10Gbps以太网链路连接的网络带宽。我们对10Gbps网络应用了标准的网络调优,比如启用TCP窗口扩展和增加Socket缓冲区大小。如图1所示,Docker将主机上的所有容器连接到网桥上,并通过NAT将网桥连接到网络上。在我们的KVM配置中,我们使用Virtio和vHost来最小化虚拟化开销。

WeChat Image_20210520104509.jpg
图1 网络配置

我们使用nuttcp来测量单个TCP连接上标准1500字节MTU的单向批量数据传输的实际吞吐量。在客户机到服务器的情况下,被测系统(SUT)充当发送器,在服务器到客户机的情况下,SUT充当接收器;有必要测量两个方向,因为TCP有不同的发送和接收代码路径。这三种配置在发送和接收方向上都达到9.3 Gbps,非常接近因为包头而产生的9.41 Gbps的理论极限。由于分片卸载,即使使用不同形式的虚拟化创建的额外层,批量数据传输也非常高效。这个测试中的瓶颈是NIC,使得其他资源大部分空闲。在这样一个I/O受限的场景中,我们通过测量发送和接收数据所需的CPU周期量来确定开销。图2显示了此测试的系统范围CPU利用率,使用perf stat -a进行测量。Docker使用桥接和NAT显著地增加了传输路径长度;Vhost-net在传输方面是相当有效的,但在接收端有很高的开销。不使用NAT的容器具有与本地Linux相同的性能。在实际的网络密集型工作负载中,我们预计这种CPU开销会降低整体的性能。

WeChat Image_20210520104505.jpg
图2 TCP批量传输效率

过去,Xen和KVM一直难以提供线速率的网络,因为迂回的I/O路径将每个数据包发送到用户空间。这导致了对诸如轮询驱动程序或管理程序旁路等复杂网络加速技术的大量研究。我们的结果表明,vHost允许虚拟机直接与主机内核通信,直接解决了网络吞吐量问题。如果有更多的网卡,我们预计该服务器可以在不使用任何外来技术的情况下驱动超过40Gbps的网络流量。

3.6 网络延迟——netperf

我们使用netperf请求-响应基准测试来测量往返网络延迟,使用与前一节中的nuttcp测试类似的配置。在这种情况下,被测试的系统运行netperf服务器(netserver),而另一台机器运行netperf客户机。客户端发送一个100字节的请求,服务器发送一个200字节的响应,客户端在发送另一个请求之前等待响应。因此,一次只有一个事务在运行中。

WeChat Image_20210520104652.jpg
Fig. 3. 网络往返延时(µs)

评论区

共 0 条评论
  • 这篇文章还没有收到评论,赶紧来抢沙发吧~

【随机内容】

返回顶部