O006、CPU和内存虚拟化原理
前面我们成功的把KVM跑起来了,有了些感性认识,这个对于初学者非常重要。不过还不够,我们多少要了解一些KVM的实现机制,这对后面工作会很有帮助。
CPU 虚拟化
KVM 的虚拟化 是需要CPU硬件支持的。还记得我们在前面的章节讲过用命令来查看CPU是否支持KVM虚拟化吗?
root@ubuntu:~# egrep -o '(vmx|svm)' /proc/cpuinfo
vmx
vmx
vmx
vmx
如果输出有 vmx 或者 svm ,就说明当前的CPU 支持 KVM 。 CPU 厂商 intel 和 AMD 都支持虚拟化,除非是非常老的 CPU。
一个 KVM 虚拟在宿主机中其实就是一个qemu-kvm 进程,与其他 Linux进程一样被调度。比如我们在实验机上运行的虚机 kvm1 ,在宿主机的ps中就可以看到他的进程。
root@ubuntu:~# ps -ef | grep kvm1
libvirt+ 4988 1 9 20:39 ? 00:00:05 qemu-system-x86_64 -enable-kvm -name kvm1 -S -machine pc-i440fx-xenial,accel=kvm,usb=off -cpu Haswell-noTSX -m 100 -realtime mlock=off -smp 1,sockets=1,cores=1,threads=1 -uuid 3a40949c-5e76-43b2-9a5c-60ebb442798d -no-user-config -nodefaults -chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/domain-kvm1/monitor.sock,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc,driftfix=slew -global kvm-pit.lost_tick_policy=discard -no-hpet -no-shutdown -global PIIX4_PM.disable_s3=1 -global PIIX4_PM.disable_s4=1 -boot strict=on -device ich9-usb-ehci1,id=usb,bus=pci.0,addr=0x6.0x7 -device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,addr=0x6 -device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,addr=0x6.0x1 -device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pci.0,addr=0x6.0x2 -device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x5 -drive file=/var/lib/libvirt/images/cirros-0.3.3-x86_64-disk.img,format=qcow2,if=none,id=drive-ide0-0-0 -device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 -netdev tap,fd=30,id=hostnet0 -device rtl8139,netdev=hostnet0,id=net0,mac=52:54:00:47:ab:ab,bus=pci.0,addr=0x3 -chardev pty,id=charserial0 -device isa-serial,chardev=charserial0,id=serial0 -chardev spicevmc,id=charchannel0,name=vdagent -device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=com.redhat.spice.0 -spice port=5900,addr=127.0.0.1,disable-ticketing,image-compression=off,seamless-migration=on -device qxl-vga,id=video0,ram_size=67108864,vram_size=67108864,vgamem_mb=16,bus=pci.0,addr=0x2 -device intel-hda,id=sound0,bus=pci.0,addr=0x4 -device hda-duplex,id=sound0-codec0,bus=sound0.0,cad=0 -chardev spicevmc,id=charredir0,name=usbredir -device usb-redir,chardev=charredir0,id=redir0 -chardev spicevmc,id=charredir1,name=usbredir -device usb-redir,chardev=charredir1,id=redir1 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x7 -msg timestamp=on
虚机中的每一个虚拟 vCPU 则对应 qemu-kvm 进程中的一个线程。见下图
在这个例子中,宿主机有两个物理CPU,上面起了两个虚机 VM1 和 VM2 。VM1 有两个 vCPU,VM2有4个vCPU。可以看到VM1 和 VM2分别有2个和4个线程在两个物理CPU上调度。
这里也演示了另一个知识点,即虚机的vCPU总数可以超过物理CPU数量,这个叫 CPU overcommit (超配)。KVM允许 overcomit ,这个特性使得虚机能够充分利用宿主机的CPU资源,但前提是在同一时刻不是所有的虚机都满负荷运行。当然,如果每个虚机都很忙,反而会影响整体性能,所以在使用 overcommit的时候,需要对虚机的负载情况有所了解,需要测试。
内存虚拟化
KVM 通过内存虚拟化共享物理系统内存,动态分配给虚机。见下图
为了在一台机器上运行多个虚机,KVM需要实现 VA (虚拟内存) -> PA (物理内存) -> MA (机器内存)之间的地址转换。虚机OS控制 VA - PA ,物理机OS 控制 PA - MA。
内存也是可以 overcommit 的,即所有虚机的内存之和可以超过宿主机的物理内存,但使用时也需要充分测试,否则会影响性能。