当前位置: 首页 > 科技观察

技术分享:虚拟化环境下WindowsIO性能分析

时间:2023-03-16 13:08:00 科技观察

随着云计算技术和服务的发展和进步,越来越多的客户选择将业务部署到云端。但是由于引入了虚拟化层,在业务部署过程中经常会遇到IO问题,而且通常不容易调试。本文主要介绍使用perf、systemtap等工具帮助某托管云客户调试IO性能问题,分析WindowsIO在虚拟环境下的性能。问题出现后,托管云客户自己搭建了虚拟化环境,在同一台宿主机上创建了windows2008R2和Centos6.5虚拟机,用fio测试了它们的随机读性能。windows2008R2的IOPS约为18K。而Linux的IOPS可以达到100K左右。客户测试fio配置[global]ioengine=windowsaiodirect=1iodepth=64thread=1size=20gnumjobs=1[4k]bs=4kfilename=d:test.imgrw=randread测试结果win_fio1云主机IO栈io栈云主机环境,整个IO栈比较长,涉及到应用层/文件系统/块层和驱动层,虚拟化层,HostOS文件系统/块层和GuestOS中的驱动层。因为涉及的方面比较多,任何一个环节出现问题都会导致性能下降,同时也会增加做IOTracing的难度。从这次获取的信息来看,首先排除了host文件系统、block层、驱动层的问题,因为同样情况的配置在linux系统上是没有任何问题的。目前主要关注两点:GuestOS(Windows系统)fio程序文件系统/Block层VirtIOBlock驱动虚拟机为GuestOS提供VirtioBlock设备:QEMU如何排除QEMU的嫌疑?对于IOPS性能问题,很容易想到两种可能:IO延迟太高。设备支持的IO队列太短。队列问题方面,Linux和Windows虚拟机对应的VirtioBlock设备是一样的,所以需要确认延迟问题。QEMU用了多长时间完成BlockIO?幸运的是,StefanHajnoczi在QEMU中加入了Tracing特性,所以很容易统计QEMU从收到一个IO请求到完成的具体时间。从上面的统计来看,平均IO完成时间为130us,暂时排除了QEMU层延迟过高的影响。此外,如果你注意这个动态跟踪的开销,从测试观察来看,它大致接近20%。排除队列和延迟问题,可能只有GuestOS受到影响。VirtIOBlock驱动程序有问题吗?至少更新到最新稳定版本的Virtio-Win驱动程序,仍然是同样的问题。Windows文件系统/块层有问题吗?原Windows系统确认后没有做任何配置更改。fio测试程序有问题?为什么在linux上fio没有问题?这两种可能性在性能考察过程中总是很容易陷入僵局,经常被问到问题出在哪里?因此,所有可能的影响因素似乎都没有发生任何变化。从经验来看,大部分性能问题可以分为两种可能:oncpuoffcpu再看这个问题,基本排除IO延迟问题后,对应的问题还有两种可能:CPU极度繁忙,但大部分时间不在做IO处理;CPU经常是空闲的,相应的,它也不是主要处理IO的。注:之所以至今不能排除IO延迟的影响,是因为只排除了QEMUBlock层可能的影响,但还有GuestOS的影响(GuestOS这次暂时忽略)。首先看测试时虚拟机的CPU消耗情况。top-H-p36256win_fio1从上图可以看出,QEMU主线程的cpu负载已经达到90%以上,似乎满足了oncpu问题。一般来说,解决这类问题最好的方法是使用perf进程进行采样,然后生成火焰图,因为先查看CPU消耗在哪里是一个不错的选择。perfrecord-a-g-p36256sleep20生成火焰图:win2008-bad可以明显看出大部分cpu消耗是KVM的运行,消耗最主要的是vmx_handle_exit。(真正的火焰图是矢量图,用浏览器查看很容易确认)。这里导致vmx_handle_exit主要有两点:访问IO口(handle_pio)访问MMIO(handle_apic_access)由于KVM模块占多数,所以在测试的时候更希望了解KVM的真实行为,可以是通过另一个工具(kvm_stat)实现。kvm_pio除了VMEntry和VMExit事件外,最流行的是kvm_pio和kvm_mmio,说明Windows确实有大量的IOPort和MMIO操作,这也验证了火焰图上得出的结论。在虚拟化中,IOPort或者MMIO都可能导致VMExit,甚至是HeavyExit。如果需要提高性能,一般会尽量避免这种情况,至少避免HeavyExit。专门访问了哪些IOPort和MMIO导致VMExit?针对这个问题,KVM模块加入了很多traceevents,上面的kvm_stat也使用了这些tracesevent,但是并没有打印出具体的traceevent信息。为了获取trace-event信息,有很多前端工具,比如trace-cmd和perf,都是不错的选择。?查看所有kvm模块的traceevent[xs3c@devhost1]#trace-cmdlist-e|grepkvmkvmmmu:kvm_mmu_pagetable_walkkvmmmu:kvm_mmu_paging_elementkvmmmu:kvm_mmu_set_accessed_bitkvmmmu:kvm_mmu_set_dirty_bitkvmmmu:kvm_mmu_walker_errorkvmmmu:kvm_mmu_get_pagekvmmmu:kvm_mmu_sync_pagekvmmmu:kvm_mmu_unsync_pagekvmmmu:kvm_mmu_zap_pagekvm:kvm_entrykvm:kvm_hypercallkvm:kvm_piokvm:kvm_cpuidkvm:kvm_apickvm:kvm_exitkvm:kvm_inj_virqkvm:kvm_inj_exceptionkvm:kvm_page_faultkvm:kvm_msrkvm:kvm_crkvm:kvm_pic_set_irqkvm:kvm_apic_ipikvm:kvm_apic_accept_irqkvm:kvm_eoikvm:kvm_pv_eoikvm:kvm_write_tsc_offsetkvm:kvm_ple_windowkvm:kvm_vcpu_wakeupkvm:kvm_set_irqkvm:kvm_ioapic_set_irqkvm:kvm_ioapic_delayed_eoi_injkvm:kvm_msi_set_irqkvm:kvm_ack_irqkvm:kvm_mmioKVM模块添加了许多traceevent的点,这里只抓住其中两个-kvm:kvm_pio和kvm:kvm_mmio。trace-cmd-pio-mmio通过统计发现主要访问的是:IOPort为0x608和0xc050;MMIO为0xFEE003xx通过qemuinfomtree命令可以查看IOPort608、c050和FEE003xx分别对应的具体设备。?IOPORT000000000000000608-000000000000060B(PRIO0,RW):ACPI-TMR000000000000C040-000000000000000000C07F(PRIO1,RW):firtio-pci?mmio000000000000000000000000000000000000000000fee-ictiolcort-prioycontincyic出口。至此可以判断是wnidows读取了大量的ACPIPowerManagerTimer,访问APIC寄存器,导致vm退出过多,占用大量CPU资源。因此,可以详细讨论两个问题:如何减少读取ACPIPMTimer寄存器而导致的VMExit;如何减少访问APICMMIO导致的VMExit。如何减少读取ACPIPM定时器导致的VM退出?从虚拟化层优化的角度来看,减少IOPort导致的VMExit,通常会考虑是否可以使用Para-virtulization替代Full-virtulization来达到目的。请参阅Windows在这方面是如何完成的。从Windows7开始,为了让Windows操作系统在HyperV中获得更好的性能,微软特意为Windows系统做了很多虚拟化增强,其中就包括可以在这里使用的HyperVTimer。此功能类似于Linux中的功能。kvm时钟。从目前的支持情况来看:Windows7Windows7SP1WindowsServer2008R2WindowsServer2008R2SP1/SP2Windows8/8.1/10WindowsServer2012WindowsServer2012R2qemu和libvirt都增加了HyperVTimer支持,可以直接通过libvirt使能HyperV定时器。另外,HyperVTimer很早就在KVM中得到了支持,但是客户端的宿主机内核版本不支持该功能,所以需要升级UCloud为客户端维护的内核版本。如何减少APICACCESS导致VMExit?IntelCPU已经支持apic-v,升级到UCloud自己维护的内核版本即可解决。最终效果win-fio-goodwin-good总结从这个案例我们可以看出,与物理环境相比,在虚拟化环境下WindowsIO性能较差时,并不一定代表IO路径有问题,可能是一些虚拟化性能问题对IO性能影响很大。【本文为专栏作者“大U的科技课堂”原创文章,转载请微信♂(ucloud2012)联系作者】点此查看更多本作者好文