为了提高硬盘,网络的性能,需要支持半虚拟化
在全虚拟化状态下,Guest OS不知道自己是虚拟机,于是像发送普通的IO一样发送数据,被Hypervisor拦截,转发给真正的硬件
在半虚拟化状态下,Guest需要安装半虚拟化驱动,Guest OS知道自己是虚拟机,所以数据直接发送给半虚拟化设备,经过特殊处理,发送给真正的硬件
半虚拟化驱动的例子:virtio, Vmware Tools
然而要虚拟的设备多种多样,要支持的硬件多种多样,需要统一的接口,这就是virtio的使命
不同的虚拟设备和不同的虚拟机可以有不同的前端驱动
不同的硬件设备可以有不同的后端驱动
两者之间的交互遵循virtio的标准
virtio层是虚拟队列接口,virtio-net网络驱动程序使用两个虚拟队列(一个用于接收,另一个用于发送),而virtio-blk块驱动程序仅使用一个虚拟队列。
Transport(virtio-ring)实现了环形缓冲区(ring buffer),用于保存前端驱动和后端处理程序执行的信息,并且它可以一次性保存前端驱动的多次I/O请求,并且交由后端去动去批量处理。
我们首先来看硬盘虚拟化virtio_blk
qemu-system-x86_64 -enable-kvm -name ubuntutest -m 2048 -balloon virtio -drive file=ubuntutest.qcow2,if=virtio -vnc :19 -net nic,model=virtio -net tap,ifname=tap0,script=no,downscript=n -monitor stdio
使用virtio_blk驱动的硬盘显示为/dev/vda,使用IDE硬盘显示为/dev/had,使用SATA硬盘显示/dev/sda
virtio-blk-data-plane:进一步提高性能,每个device单独的线程,仅支持raw disk,不支持storage migration
我们再来看网络设备虚拟化virtio_net
ethtool -i eth0
TSO是通过网络设备进行TCP段的分割,从而来提高网络性能的一种技术
GSO(Generic Segmentation Offload) 应用于其他的传输层协议,如TCPv6,UDP
应用层可以使用ethtool -K eth0 tso off|on命令对支持TSO特性的网络设备进行TSO功能的关闭和启用
使用virtio_net性能低,可尝试关闭这两个选项
使用Virtio的性能比较如下:
有了virtio性能会好很多。
所以性能优化的第一个最佳实践是:使用半虚拟化驱动virtio,对于block storage,使用virtio_blk,对于network,使用virtio_net
在CPU方面
每个Guest相当于一个进程,Guest中的每个vcpu相当于一个线程
Host CPU支持进程间切换,SMP可以并行执行多个进程,从而可以进行CPU超配
CPU的超配增加了进程上下文切换,从而可能带来性能问题
为了保证Guest进行能够得到足够的时间片,常常使用cgroup的cpu.cfs_period_us和cpu.cfs_quota_us来控制
Cfs全称Completely Fair Scheduler是Linux Kernel的调度策略
cfs_period_us的意思是cgroup对CPU的调度的干预周期,cfs_quota_us是指则一个周期内这个进程得到的时间片长度。比如cfs_period_us=100000说明100毫秒cgroup进行一次干预,cfs_quota_us=25000表示在100毫秒里面,这个进程能够得到25毫秒的时间片,如果对cgroup进行的修改,则要等到下个100毫秒才起作用
Processor Pin: 可以讲vCPU pin到一个或者一组共享cache的物理CPU上,由于cache共享,则很多命令和数据都被缓存,从而提高性能。缺点是即便其他物理CPU空闲,由于绑定到了这个CPU,也得不到运行
CPU和Cache拓扑模型/sys/devices/system/cpu
virsh vcpupin guest# vproc# pproc#,pproc#
在内存方面
KSM全称Kernel Same Page Merging
Qemu向KSM注册内存,KSM对内存进行扫描,域名出售平台将相同的内存区域设为共享,并且copy on write
# cat /boot/config-3.13.0-27-generic | grep KSM CONFIG_KSM=y
共享内存节约内存空间,但是内存扫描同时影响性能
使用virtio_balloon
尽量不要使用swap,/proc/sys/vm/swappiness设为0
多核的两种方式:SMP和NUMA
SMP的问题主要在CPU和内存之间的通信延迟较大、通信带宽受限于系统总线带宽,同时总线带宽会成为整个系统的瓶颈
NUMA(Non-Uniform Memory Access):每个处理器有其可以直接访问其自身的“本地”内存池,使CPU和这块儿内存之间拥有更小的延迟和更大的带宽。而且整个内存仍然可做为一个整体,可以接受来自任何CPU的访问。
禁止zone_reclaim_mode:/proc/sys/vm/zone_reclaim_mode
当操作系统分配内存时,发现CPU本节点的内存已满,如果reclaim=true,则将会回收一部分本地内存,否则将分配其他节点的内存
使用KSM和Huge Page都会造成reclaim
建议开启大页Huge pages,从而提高地址转换的效率
普通页:PDPT -> PD -> Page Table -> In Page Offset
Translation Lookaside Buffer (TLB)是一个从虚拟地址到物理地址转换的一个Cache
Huge Page不但使得每次地址转换比较快,而且使得TLB每个记录较小,相同的内存的情况下,保存的记录较多,Cache命中率较高
大页:PDPT -> PD -> In Page Offset
在网络方面
使用tap作为网卡配置
使用virtio_net
使用PCI passthough可以提高性能,但是影响虚拟机迁移
可以使用DPDK或者SR-IOV
在存储方面
尽量使用block device,性能更好,无需管理HOST文件系统,无需管理稀疏文件,I/O Cache以4K为边界。
如果不能使用block device,则只好使用Image File。易管理,易移动,但需要HOST文件系统,需要管理稀疏文件
Partition问题:标准分区软件分区是以512byte一个Cylinder为边界的,Linux系统的I/O Cache是以4K为边界的,所以Linux下的标准文件系统将分区format的时候,会将文件以4k为边界进行存储,从而每次缓存正好缓存整个page(大小4k)
Image File作为一个文件,在Host文件系统中一定是以4k为边界的,然而一个Image File对于Guest来讲是整块硬盘,对其分区的时候往往不是以4K为边界的,从而Guest上读取文件的时候,本来是读取缓存的4K一个page,映射到Host文件系统上,变成了两个Page。写入也要更新两个页。
Host使用ext3文件系统,因为ext4的barrier会影响性能
使用raw image,比qcow2性能要好
选择正确的cache策略:
Page Cache: Host和Guest在FS和Block层都有自己的Page Cache,我们无法控制Guest里面的设置,但是可以配置Host Page Cache
Disk Write Cache在Hypervisor层
Cache Mode有以下四种,推荐使用none
I/O Scheduler推荐使用Deadline I/O scheduler