虚拟化概念
Qemu-KVM虚拟机
– 核心由Qemu和KVM两部分组成,Qemu本身是一个独立的虚拟机
软件,运行在OS的用户态;KVM是Linux的内核模块,利用CPU
硬件虚拟化特性对CPU和内存虚拟化进行加速
– Libvirt是对KVM虚拟机进行管理的工具和应用编程接口
– Virsh是Linux下管理KVM虚拟机的命令行接口,它基于libvirt API
工作
– Virt-manager是一个Linux上的GUI程序,实现对KVM虚拟机的图
形化管理,也是基于libvirt API工作
** Libvirt API所管理的主要对象**
CPU虚拟化
术语表
-
虚拟机、客户机(Guest)、VM
-
Hypervisor、VMM(Virtual Machine Monitor)、虚拟机监视器
-
根模式(root mode)、非根模式(non-root mode)
-
GDT:全局描述符表
-
LDT:局部描述符表
-
IDT:中断描述符表
临界指令问题
VMM需要满足以下条件:
- 等价性
- 应用程序在VMM上的虚拟机执行,英语物理硬件上执行的行为相同。
- 资源控制
- 物理硬件有VMM全权控制,VM及VM上的应用程序不能直接访问硬件
- 执行效率
- 在虚拟机环境中应用程序的绝大多数指令能够在VMM不干预的情况下,直接在物理硬件上执行。
- 指令集满足约束
- 所有敏感指令都是特权指令
CPU特权级
OS内核的代码运行在最高运行级别ring0
上,可以使用特权指令,控制终端,修改页表和访问设备等等。应用程序的代码运行在最低运行级别ring3
上,不能做受控操作。
应用程序访问系统资源的时候,需要进行用户态到内核态的切换。
Trap&Emulation
- 基本思想:接触OS的特权指令十七运行在Ring1 或者Ring3下,将VMM运行在Ring0下,OS和应用程序中的非特权指令直接运行在物理CPU上。
- OS使用的特权指令在执行时会产生General Protection Fault,进而会被VMM的异常处理程序捕获,捕获后由VMM模拟特权指令的执行,之后再返回到OS执行客户机的下一条指令
遇到的挑战
- 特权指令
- 敏感指令:读写时钟寄存器、中断寄存器、访问存储保护系统、地址重定位系统以及所有的I/O指令,这些指令可以在非最高特权级执行。
临界指令:
CPU虚拟化实现方式–BT+DE
全局虚拟化:
- Guest OS不知道自己运行在虚拟机环境中,也不要需要修改
- VMM捕获并处理所有特权和敏感指令序列,二非特权指令则不修改直接运行在宿主CPU上。
- 全虚拟化能够提供最佳的隔离性和安全性
- 软件方式:“Binary Translation”+“Direct Execution” (VMware)
- 硬件辅助虚拟化:Intel VT-x、AMD-V(KVM)
半虚拟化:
- 修改Guest OS十七运行在较低特权级,调用Hypercall主动请求VMM代理器执行特权操作。
-
二进制翻译
-
Guest操作系统内核代码经过动态二进制翻译后在宿主机CPU的Ring 1特权级下执行
-
动态扫描Guest OS代码在需要VMM介入的地方插入trap,进而可以由VMM接管特权指令或敏感指令的模拟执行
-
-
直接执行
- Guest用户模式非特权指令直接在宿主机CPU Ring 3特权级下执行
CPU实现方式–半虚拟化
-
主要思想:通过修改Guest OS来解决X86架构下的临界指令问题,同时提升虚拟机的性能
-
不改变应用程序二进制接口(Application Binary Interface, ABI),因此应用程序不需要修改和重新编译
-
适合于开源操作系统(Linux、FreeBSD),但很难支持闭源操作系统,如Windows
-
特权指令、敏感指令相关的操作被转换为发送给VMM的Hypercall(超级调用),由VMM继续进行处理
典型的半虚拟化系统–XEN请添加图片描述
-
Xen位于操作系统和硬件之间(Ring 0),负责为上层运行的客户机操作系统内核(Ring 1)提供虚拟化的硬件资源,负责管理和分配这些资源,并确保上层虚拟机(称为域Domain)之间的相互隔离
-
Xen设置了一个特权域用以辅助Xen管理其他的域,并提供虚拟的I/O资源代理服务,该特权域称为Domain 0,而其余的域则称为Domain U
-
只有运行在Ring 1的代码(Guest OS)才能向Xen发送Hypercall请求,以防止应用程序(运行在Ring 3)的错误调用导致对系统的破坏
-
在32 位X86架构下,Hypercall通过int0x82陷阱(Trap)指令实现,因为传统操作系统本身并不使用int0x82 (Linux 使用int 0x80 作为系统调用指令,int 0x82 并未使用)。在 64 位的X86上是 syscall;(真正的)IDT被设置,以至于这只会从Ring 1 中所产生(中断)Xen Hypervisor不负责处理网络和磁盘等I/O请求,因此半虚拟化客户机(Domain U PV)必须通过Xen Hypervisor与Domain 0进 行通信,从而完成I/O操作请求
Xen VCPU调度
- 物理CPU信息
- 当前物理CPU上运行的VCPU
- 当物理CPU空闲时运行的idle VCPU
- 调度计时器,对当前运行的VCPU即使,当时间片到期时会触发物理CPU进行调度
- VCPU有4种状态
- RUNSTATE_RUNNING:VCPU此时正运行在物理CPU上
- RUNSTATE_RUNNABLE:VCPU目前处于可运行状态,但尚未被调度到物理CPU上
- RUNSTATE_BLOCKED:VCPU处于阻塞状态
- RUNSTATE_OFFLINE:特殊的不可执行状态,在VCPU睡眠或暂停的时候将处于该状态
Xen VCPU调度:
- BVT算法:Borrowed Virtual Time,是一种公平性优先的调度算法
- Credit算法:让每一个VCPU都可以公平地使用物理CPU的资源
- Sedf算法:Simple Earliest Deadline First,最早截止日期优先调度算法,可以根据每个VCPU负载的大小动态的调整VCPU的优先级
- Xen调度算法是以VCPU为单位进行调度的,而不是以Domain为单位。
- VCPU上的线程调度
- 物理CPU上的VCPU调度
Xen VCPU调度----Credit算法
- 根绝权重比例分享CPU的基于时间片的多级队列轮转调度算法。
- 算法为每一个Domain U设置了两个参数
Weight
:表示domain的权重,系统中各个domain的Weight比值决定了它们各自占用CPU的时间比例CAP
:表示domain可占用的最多物理CPU的比例(时间),比如CAP=50表示该domain只能占用半个物理CPU的时间,CAP=100表示能占用1个物理CPU的时间
- 每一个物理CPU上维护一个VCPU调度队列,队列中的VCPU分为3个优先级,从低到高依次为:OVER、UNDER、BOOST。优先级高的VCPU排列队列前边,低的排在后边
- UNDER级别和OVER级别依据VCPU的Credit值进行区分,Credit>0为UNDER,Credit<0为OVER
- Credit值根据domain的Weight值计算
具体步骤:
- 初始时,所有VCPU都处在UNDER级别
- 算法每隔10ms对当前运行的VCPU进行一次调整,将其Credit值减去100
- 每隔30ms算法根据系统中各个domain的Weight值重新计算各个domain中每个VCPU的Credit值,Credit值大于0的则设置为UNDER级,小于0的则设置为OVER级
- VCPU在执行I/O请求的过程中会因为等待domain 0处理的事件而进入BLOCK状态,当等待的事件处理完成后,domain 0通过事件通道唤醒该VCPU,此时为了降低该VCPU的响应时间,将此VCPU设置为BOOST级别,并插入到队列中相应优先级的尾部。
- 如果当前物理CPU上正在运行低于BOOST级的VCPU,该BOOST级VCPU就会抢占物理CPU;如果当前运行的VCPU同样为BOOST级别,则刚被唤醒的VCPU需要在队列中等待被调度
- BOOST级别是一个临时的状态,算法会每隔10ms判断一个VCPU是否处于BOOST级,如果是,则将其调整为UNDER级,因此VCPU在BOOST级最多持续10ms
- 算法对系统中所有的VCPU采用同样的时间片进行调度,无论VCPU处于什么样的级别
-
系统总的Credit=每个物理CPU能分配的Credit(预定义) * 物理 CPU个数
-
根据当前活跃的domain之间的weight比例来计算能够分配给 domain的Credit(credit_fair)
-
计算domain能够得到的Credit上限,即让其每个VCPU独占一个物 理CPU的情况下能够获得Credit(credit_peak)
-
根据domain的CAP来计算domain能够获得的Credit的上限 (credit_cap)
-
当creadit_cap < credit_peak,credit_peak=credit_cap,最后在 credit_peak和credit_fair里面取最小值作为domain的credit
-
最后,把domain的credit除以当前domain活动的VCPU数,就变 成domain的每个VCPU的credit,再根据credit值来设置VCPU所处 的级别
硬件辅助的CPU虚拟化
KVM VCPU 工作原理
KVM虚拟机线程模型
VCPU
-
VCPU的整个生命周期都在Qemu线程的上下文中,在Kernel(root模式)、User(root模式)、Guest(non-root模式)三种模式下转换
- 客户模式(Guest Mode)运行GuestOS,执行Guest非IO操作指令。
- 用户模式(User Mode)运行QEMU,实现IO模拟与管理。
- 内核模式(Kernel Mode)运行KVM内核,实现模式的切换(VM Exit/VM Entry),执行特权与敏感指令。
- 每个VCPU对应一个Qemu线程,在Linux上以普通线程进行调度