在上期,我们提出了一个概念 “数据中心税”。
所谓的“数据中心税”,指的是数据中心计算、存储、网络等基础资源虚拟化后带来的开销。
这方面的开销,造成了云计算的六次危机。
它们分别是:
2. VirtIO每次收发需要二次内核/用户态切换,带来的性能危机;
3. VHost进行内核/用户态切换引起的性能危机;
4. NFV场景下,即使使用VHost-user+DPDK实现用户面网络虚拟化,网络收发还需要过OVS-DPDK,引起的性能与时延危机;
5. SR-IOV直通给NFV实现,但无法提供交换功能,带来的转发路径依赖危机;
6. 网卡的OVS卸载无法实现更多灵活数据面功能,带来的数据平面功能危机;
在这几期专题中,我们将为大家介绍工程师们,如何通过软硬件融合技术,解决这六次危机的。
由于业界主流的云计算平台都是基于Linux和KVM的,让我们再一次钻进在Linux中,看一下KVM为虚拟机提供的网络虚拟化实现。
虚拟机运行的一条铁律是:不应当对操作系统内核做任何修改,只增加必要的虚拟化硬件驱动,就可以使得虚拟机和在物理机上一样地运行。
最初,KVM为虚拟机提供的是rtl8139和E1000E这两种网卡。以E1000E为例,它实际上是Hypervisor为虚拟机提供的一个模拟(Emulator)设备,模拟的是这个家伙:
它是一块Intel 82574网卡,速率为1Gb/s。
实际上,在宿主机上一般并不存在这块网卡,也就是说,虚拟机看见的E1000E网卡,完全是宿主机欺骗虚拟机操作系统(GuestOS)的产物。
当GuestOS调用E1000E网卡驱动,进行数据包收发的时候,GuestOS以为自己操作的是真正的Intel 82574网卡,写入的是其PCI配置空间指定的BAR IO空间 (不知道什么是PCI配置空间和BAR?请看这里) 。
显然,由于实际上并没有这个硬件的存在,虚拟机执行的这条读写指令会导致VM_EXIT,也就是退出到了QEMU。(不知道什么是VM_EXIT?请看这里)
QEMU将模拟Intel 82574网卡的行为,最后将这个数据包发送到Linux Bridge的TAP口。Linux Bridge会根据数据包的目的MAC地址,将数据包转发到其他VM,或从物理网卡转发出去,如下图所示:
当QEMU开始发送这个数据包,会再通过VM_Entry将CPU交还给虚拟机。容易忽略的是,网卡在发送完毕数据包(Transmit Done)后,还需要通知操作系统,让调用socket函数的进程知道发送完毕,可以开始发送下一个数据包,而不要一直被阻塞住。显然,这个行为还会触发一次中断,使得虚拟机的vCPU再次进行一次用户态到内核态的切换。
小结一下:如果KVM的虚拟机使用E1000E这样的全虚拟化网卡,每次收发数据包都将触发一次VM_Exit,并产生一次Transmit Done中断。
E1000E的数据传输速率为1Gbps,理论上每秒钟发送数据包次数可达1488095个 (不知道这个数字怎么来的可以看这里) 。显然,触发1488095个VM_Exit的开销,会吃掉大量所有的CPU指令周期,在超分的时候矛盾会更加突出。
当然了,这样的开销(也就是最初的“数据中心税”),是不可接受的。这就造成了云计算系统的第一次危机。
经济学家凯恩斯指出,在生产力发展出现瓶颈,出现经济危机的时候,需要轻徭薄赋,为经济的恢复创造条件。因此,我们需要对QEMU进行改进,降低“数据中心税”!
因此,工程师们对QEMU进行了改进,让虚拟机在读写网卡的时候不触发VM_Exit。
我们发现,触发VM_Exit的根本原因是对不存在的物理硬件进行IO操作。那么,如果我们修改GuestOS的网卡驱动,把数据收发动作改为通过内存中的队列进行数据包收发呢?
这种机制被叫做VirtIO-net,即virtio实现的网络设备。
VirtIO的实现方式为前后端驱动模式。简单地说,就是在GuestOS上安装前端驱动,而QEMU在宿主机上提供后端实现。
这种方式的实现如下图:
如图,GuestOS在发送中断中退出到KVM,随后KVM会回到QEMU,QEMU通过syscall再进入内核态,调用TAP的驱动发送数据包。
这样一来,发送数据包不会触发VM_EXIT,只是会发生2次用户态到内核的切换,以及2次内核切换回用户态。
显然,这样的IO路径仍然有较大的开销,并且涉及到2次数据从用户态到内核态的复制。特别地,在Linux下,virtio网卡的速率被定义为10Gbps,其收发数据包理论最大速率是E1000E的10倍。这就造成了更重的数据中心税,从而引发了第二次危机。
解决第二次危机的手段是对virtio-net进行改进,也就是vhost方案。
vhost就是将virtio的实现,从QEMU中挪到hostOS的内核里面,如下图所示:
vhost方案和virtio相比,少了一次进出内核,让kvm.ko直接与virtio backend通信,也减少了一次数据的拷贝,大大提高了虚拟网卡的性能。
我们发现,这种实现下,virtio backend在内核实现,因此,也成为vhost-kernel。
当数据中心服务器接入网络标准,从25G以太网演进到100G以太网的时候,工程师们发现,即使采用了vhost-kernel,性能还是会出现瓶颈。这就引发了第三次危机。
如何解决第三次危机呢?
请看下期。