转自:http://blog.csdn.net/julykobe/article/details/27571387

注:本文内容均来自网络,我只是在此做了一些摘抄和整理的工作,来源均有注明。

0、虚拟化

虚拟化简介

我们首先简要介绍一下虚拟化,阐述 QEMU 的搭建背景。

本文中介绍的虚拟化实际上指的是平台虚拟化。在物理硬件上,控制程序可能是主机操作系统或管理程序(见图 1)。在某些情况下,主机操作系统就是管理程序。来宾操作系统位于管理程序中。在某些情况下,来宾操作系统与控制程序使用相同的 CPU,而在另外一些情况下,则可能不同(比如 PowerPC 来宾操作系统在 x86 硬件上运行)。

图 1. 平台虚拟化的基本架构

您可以通过多种方法实现虚拟化,但是最常见的有三种。第一种称为本地虚拟化(或全虚拟化)。在这种虚拟化中,管理程序实现基本的隔离元素,将物理硬件与来宾操作系统相分离。这种技术首次出现于 1966 年 IBM® CP-40 虚拟机/虚拟内存操作系统中,另外 VMware ESX Server 也使用了此技术。

另一种流行的虚拟化技术称为半虚拟化。在半虚拟化中,控制程序实现了管理程序的应用程序接口(API),它将由来宾操作系统使用。Xen 和 Linux Kernel-based Virtual Machine (KVM) 都使用了半虚拟化技术。

第三种有用的技术称为仿真。仿真,顾名思义,通过模拟完整的硬件环境来虚拟化来宾平台。仿真可通过多种方法实现,即使在同一个解决方案中也是如此。通过仿真实现虚拟化的技术有 QEMU 和 Bochs。


 

1、KVM

概念:

KVM是Kernel-based Virtual Machine的缩写。从Linux kernel 2.6.20开始就包含在Linux内核代码之中,使用这个或者更高版本内核的Linux发行版,就直接可以使用KVM。KVM依赖于host CPU的虚拟化功能的支持(Intel-VT & AMD-V),类似于Xen的HVM,对于guest OS的内核没有任何的要求,可以直接支持创建Linux和Windows的虚拟机。

     下图解释了KVM的运行原理:
KVM支持用户态(Userspace)进程通过KVM内核(Kernel)模块利用CPU的虚拟化技术创建虚拟机。虚拟机的vCPU映射到进程中的线程,虚拟机的RAM映射到进程的内存地址空间,IO和外围设备通过进程进行虚拟化,也就是通过QEMU。所以我们看到在OpenStack中创建一个虚拟机就对应一个计算节点的QEMU进程。
刚才说到guest OS RAM的地址空间映射到qemu-kvm进程的内存地址空间,这样进程就可以很容易的对于guest OS的RAM进行控制,当guest需要使用RAM时,qemu-kvm就在自己的进程内存空间中划分一段给guest用。对于guest OS设置了MaxMemory和CurrentMemory之后,guest OS的RAM上限也就有了,就是MaxMemory,如果当前的guest实际使用不了那么多RAM,就可以将CurrentMemory调小,将多余的内存还给host,guest中看到的内存大小就是CurrentMemory,这就是Memory Balloon特性。
架构:
     KVM由两部分组成,一部分称为KVM Driver。已经成为Linux内核的一个模块,负责虚拟机的创建、虚拟机内存的分配、虚拟CPU寄存器的读写以及虚拟CPU的运行等;另一部分是稍微修过的Qemu,用于模拟PC硬件的用户空间组件、提供I/O设备模型以及访问外设的途径。
     
   图1揭示了KVM的基本结构(Libkvm是KvM提供给Qemu的应用程序接口)。KVM Driver加入到标准的Linux内核中,被组织成Linux中的标准字符设备(/dev/kvm),用户模式的Qemu可以通过一系列的ioctl系统调用访问这个字符设备从而创建和运行虚拟机。KVMDriver的加入使得整个Linux内核成为一个虚拟机监控器(Virtual Machine Monitor),并且在原有Linux操作系统两种执行模式(用户模式和内核模式)的基础上,增加了一种客户模式(拥有自己的内核模式和用户模式),这三种模式不同的分工分别是:
客户模式:执行非I/0的客户代码。虚拟机就运行在客户模式下。
内核模式:实现到客户模式的切换,处理由于I/O或其他指令引起的从客户模式的退出。KVM Driver工作在这种模式下。
用户模式:代表客户执行I/0指令。Qemu运行在这种模式下。
我们把运行于虚拟机内的操作系统称为Guest OS,把底层的Linux操作系统称为Host OS。在KVM模型中,每一个Guest OS对Linux来说是一个标准的进程,可以使用Linux的进程管理指令管理,例如用taskset指定运行于某个特定的CPU,也可以用kill终止虚拟机的运行。
     从图2中我们可以清楚的看到KVM的基本工作原理。首先在用户模式的Qemu通过ioctl系统调用,进入内核模式。KVM Driver为虚拟机创建虚拟内存和虚拟CPU之后执行VMI.AUNCH指令进入客户模式,装载GuestOS,而后执行客户代码。如果Guest OS发生外部中断或者影子页表缺页之类的事件,暂停Guest OS的运行,退出客户模式进入内核做一些必要的处理,而后重新进入客户模式。继续执行客户代码;如果发生I/0事件或者信号队列中有信号到达,就会进入用户模式处理。
     KVM采用全虚拟化技术(可以通过给当前内核打kvm-paravirt-patches补丁来支持半虚拟化),Guest OS不需要修改就可以直接在在其上运行,弥补了半虚拟化技术的不足。

2、QEMU

概念:
     刚才讲KVM的时候一直说进程可以通过KVM模块创建虚拟机,那个所谓的进程其实就是QEMU。KVM团队维护了一个QEMU的分支版本(qemu-kvm),使QEMU可以利用KVM在x86架构上加速,提供更好的性能。qeum-kvm版本的目标是将所有的特性都合入上游的QEMU版本,之后这个版本会废弃,直接使用QEMU主干版本。
     其实,之前还有Xen维护的QEMU版本,叫做qemu-xen,由于所有的特性都已经合入QEMU1.0,所以Xen现在直接使用了QEMU。
     #"之前在安装OpenStack的时候,都需要安装一个包kvm,我个人认为这个包其实就是QEMU,KVM是已经包含在Linux Kernel里了,所以不需要再安装。包名称使用kvm有点混淆概念。这点在Ubuntu的包描述上可以看出来。"
     在Nova的配置文件中有一个virt_type配置项,可以配置成kvm也可以是qemu,这里的kvm其实指的也是qemu-kvm。如果要配置成kvm,需要host的CPU支持Intel-VT和AMD-V技术,并且要载入kvm内核模块,由于有硬件加速,创建的guest OS的性能要优于qemu;qemu配置项指的就是完全的QEMU虚拟化,没有硬件加速,主要用于比较老式的CPU和操作系统环境,或者是在虚拟机中创建虚拟机的情况,当然完全的QEMU虚拟化性能要比qemu-kvm差一些
     QEMU的功能大致分为两类:
  • 模拟(emulator)
  • 虚拟化(virtualizer)

模拟:就是在一种CPU架构上模拟另一种CPU架构,运行程序。例如:在x86环境上模拟ARM的运行环境,执行ARM程序,或者在PowerPC环境上模拟x86指令集。
     虚拟化:就是在host OS上运行guest OS的指令,并为guest OS提供虚拟的CPU、RAM、IO和外围设备。

我们在OpenStack中使用的就是QEMU的虚拟化功能。
QEMU进程直接使用了KVM的接口/dev/kvm,向KVM发送创建虚拟机和运行虚拟机的命令。框架代码如下:
open("/dev/kvm")
ioctl(KVM_CREATE_VM)
ioctl(KVM_CREATE_VCPU)
for (;;) {
ioctl(KVM_RUN)
switch (exit_reason) {
case KVM_EXIT_IO:  /* ... */
case KVM_EXIT_HLT: /* ... */
}
}
     虚拟机运行起来之后,当guest OS发出硬件中断或者其它的特殊操作时,KVM退出,QEMU可以继续执行,这时QEMU根据KVM的退出类型进行模拟IO操作响应guest OS。
     由于QEMU是一个普通的用户态进程,而guest OS的运行又在QEMU当中,所以host不能绕过QEMU直接观察guest OS。但是QEMU提供了一系列的接口可以导出guest OS的运行情况,内存状态和IO状态等。
     以下就是一个QEMU进程:
109       1673     1  1 May04 ?        00:26:24 /usr/bin/qemu-system-x86_64 -name instance-00000002 -S -machine pc-i440fx-trusty,accel=tcg,usb=off -m 2048 -realtime mlock=off -smp 1,sockets=1,cores=1,threads=1 -uuid f3fdf038-ffad-4d66-a1a9-4cd2b83021c8 -smbios type=1,manufacturer=OpenStack Foundation,product=OpenStack Nova,version=2014.2,serial=564d2353-c165-6238-8f82-bfdb977e31fe,uuid=f3fdf038-ffad-4d66-a1a9-4cd2b83021c8 -no-user-config -nodefaults -chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/instance-00000002.monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc -no-shutdown -boot strict=on -device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 -drive file=/opt/stack/data/nova/instances/f3fdf038-ffad-4d66-a1a9-4cd2b83021c8/disk,if=none,id=drive-virtio-disk0,format=qcow2,cache=none -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 -drive file=/opt/stack/data/nova/instances/f3fdf038-ffad-4d66-a1a9-4cd2b83021c8/disk.config,if=none,id=drive-ide0-1-1,readonly=on,format=raw,cache=none -device ide-cd,bus=ide.1,unit=1,drive=drive-ide0-1-1,id=ide0-1-1 -netdev tap,fd=26,id=hostnet0 -device virtio-net-pci,netdev=hostnet0,id=net0,mac=fa:16:3e:db:86:d4,bus=pci.0,addr=0x3 -chardev file,id=charserial0,path=/opt/stack/data/nova/instances/f3fdf038-ffad-4d66-a1a9-4cd2b83021c8/console.log -device isa-serial,chardev=charserial0,id=serial0 -chardev pty,id=charserial1 -device isa-serial,chardev=charserial1,id=serial1 -vnc 127.0.0.1:1 -k en-us -device cirrus-vga,id=video0,bus=pci.0,addr=0x2 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5

 
架构:
 

QEMU 支持两种操作模式:用户模式仿真和系统模式仿真。用户模式仿真 允许一个 CPU 构建的进程在另一个 CPU 上执行(执行主机 CPU 指令的动态翻译并相应地转换 Linux 系统调用)。系统模式仿真 允许对整个系统进行仿真,包括处理器和配套的外围设备。

在 x86 主机系统上仿真 x86 代码时,使用 QEMU 加速器 可以实现近似本地的性能。这让我们能够直接在主机 CPU 上执行仿真代码(在 Linux 上通过 kernel 模块执行)。

但是从技术角度看,QEMU 的有趣之处在于其快速、可移植的动态翻译程序。动态翻译程序 允许在运行时将用于目标(来宾)CPU 的指令转换为用于主机 CPU,从而实现仿真。这可以通过一种强制方法实现(将指令从一个 CPU 映射到另一个 CPU),但是情况并非总是这样简单,在某些情况下,根据所翻译的架构,可能需要使用多个指令或行为更改。

QEMU 实现动态翻译的方法是,首先将目标指令转换为微操作。这些微操作是一些编译成对象的 C 代码。然后构建核心翻译程序。它将目标指令映射到微操作以进行动态翻译。这不仅可产生高效率,而且还可以移植。

QEMU 的动态翻译程序还缓存了翻译后的代码块,使翻译程序的内存开销最小化。当初次使用目标代码块时,翻译该块并将其存储为翻译后的代码块。 QEMU 将最近使用的翻译后的代码块缓存在一个 16 MB 的块中。 QEMU 甚至可以通过在缓存中将翻译后的代码块变为无效来支持代码的自我修改。

 

3、libvirt

Libvirt 库是一种实现 Linux 虚拟化功能的 Linux® API,它支持各种虚拟机监控程序。
 
libvirt是一个统一的虚拟化管理接口,当前支持的虚拟化实现如下:
  • The KVM/QEMU Linux hypervisor
  • The Xen hypervisor on Linux and Solaris hosts.
  • The LXC Linux container system
  • The OpenVZ Linux container system
  • The User Mode Linux paravirtualized kernel
  • The VirtualBox hypervisor
  • The VMware ESX and GSX hypervisors
  • The VMware Workstation and Player hypervisors
  • The Microsoft Hyper-V hypervisor
  • The IBM PowerVM hypervisor
  • The Parallels hypervisor
  • The Bhyve hypervisor
第一个就是QEMU,libvirt的virsh是可以传递QEMU的监控命令的,我希望实现的那个blueprint就是用libvirt去传递QEMU的监控命令,开启QEMU的内存使用统计,然后再通过libvirt获取虚拟机的内存使用情况。[by 参考1原文作者]
架构:
     
libvirt 比较和用例模型

图中还显示了 libvirt 所用术语对照。这些术语很重要,因为在对 API 命名时会用到它们。两个根本区别在于,libvirt 将物理主机称作节点,将来宾操作系统称作域。这里需要注意的是,libvirt(及其应用程序)在宿主 Linux 操作系统(域 0)中运行。
 
控制方式:
     使用 libvirt,我们有两种不同的控制方式。第一种如 图 1 所示,其中管理应用程序和域位于同一节点上。 在本例中,管理应用程序通过 libvirt 工作,以控制本地域。当管理应用程序和域位于不同节点上时,便产生了另一种控制方式。在本例中需要进行远程通信(参见 图 2)。该模式使用一种运行于远程节点上、名为 libvirtd 的特殊守护进程。当在新节点上安装 libvirt 时该程序会自动启动,且可自动确定本地虚拟机监控程序并为其安装驱动程序(稍后讨论)。该管理应用程序通过一种通用协议从本地 libvirt 连接到远程 libvirtd。对于 QEMU,协议在 QEMU 监视器处结束。QEMU 包含一个监测控制台,它允许检查运行中的来宾操作系统并控制虚拟机(VM)各部分。
     
图 使用 libvirtd 控制远程虚拟机监控程序

虚拟机监控程序支持:
 
     为支持各种虚拟机监控程序的可扩展性,libvirt 实施一种基于驱动程序的架构,该架构允许一种通用的 API 以通用方式为大量潜在的虚拟机监控程序提供服务。这意味着,一些虚拟机监控程序的某些专业功能在 API 中不可见。另外,有些虚拟机监控程序可能不能实施所有 API 功能,因而在特定驱动程序内被定义为不受支持。图 3 展示了 libvirt API 与相关驱动程序的层次结构。这里也需要注意,libvirtd 提供从远程应用程序访问本地域的方式。
 
表 1. libvirt 支持的虚拟机监控程序
虚拟机监控程序 描述
Xen 面向 IA-32,IA-64 和 PowerPC 970 架构的虚拟机监控程序
QEMU 面向各种架构的平台仿真器
Kernel-based Virtual Machine (KVM) Linux 平台仿真器
Linux Containers(LXC) 用于操作系统虚拟化的 Linux(轻量级)容器
OpenVZ 基于 Linux 内核的操作系统级虚拟化
VirtualBox x86 虚拟化虚拟机监控程序
User Mode Linux 面向各种架构的 Linux 平台仿真器
Test 面向伪虚拟机监控程序的测试驱动器
Storage 存储池驱动器(本地磁盘,网络磁盘,iSCSI 卷)
 
 

参考:
  1. Kvm Qemu Libvirt:http://kiwik.github.io/openstack/2014/05/04/KVM-QEMU-libvirt/#
  2. KVM虚拟机分析: http://wenku.baidu.com/link?url=1sEgxHLl-pYpSavmRJXwFq3QYHENQPvEX7QMUQ7zf9UL1Qkio1YNUVKhF-697vqk4O7DDjuEPc0NLbHfoiMbOkGo4zdmRjVjftWlkNa1AJy
  3. 使用QEMU进行系统仿真: https://www.ibm.com/developerworks/cn/linux/l-qemu/
  4. Libvirt虚拟化库剖析: https://www.ibm.com/developerworks/cn/linux/l-libvirt/
  5. Libvirt架构及源码分析(一) : http://blog.chinaunix.net/uid-20940095-id-3813601.html

KVM,QEMU,libvirt入门学习笔记【转】相关推荐

  1. dubbo入门学习笔记之入门demo(基于普通maven项目)

    注:本笔记接dubbo入门学习笔记之环境准备继续记录; (四)开发服务提供者和消费者并让他们在启动时分别向注册中心注册和订阅服务 需求:订单服务中初始化订单功能需要调用用户服务的获取用户信息的接口(订 ...

  2. Crypto++入门学习笔记(DES、AES、RSA、SHA-256)

    Crypto++入门学习笔记(DES.AES.RSA.SHA-256) 背景(只是个人感想,技术上不对后面的内容构成知识性障碍,可以skip): 最近,基于某些原因和需要,笔者需要去了解一下Crypt ...

  3. 机器学习入门学习笔记:(4.2)SVM的核函数和软间隔

    前言 之前讲了有关基本的SVM的数学模型(机器学习入门学习笔记:(4.1)SVM算法).这次主要介绍介绍svm的核函数.软间隔等概念,并进行详细的数学推导.这里仅将自己的笔记记录下来,以便以后复习查看 ...

  4. 机器学习入门学习笔记:(3.2)ID3决策树程序实现

    前言 之前的博客中介绍了决策树算法的原理并进行了数学推导(机器学习入门学习笔记:(3.1)决策树算法).决策树的原理相对简单,决策树算法有:ID3,C4.5,CART等算法.接下来将对ID3决策树算法 ...

  5. 机器学习入门学习笔记:(2.3)对数几率回归推导

    理论推导   在以前的博客(机器学习入门学习笔记:(2.1)线性回归理论推导 )中推导了单元线性回归和多元线性回归的模型.   将线性回归模型简写为:y=ωTx+by = \omega^Tx+b:   ...

  6. 机器学习入门学习笔记:(2.2)线性回归python程序实现

      上一篇博客中,推导了线性回归的公式,这次试着编程来实现它.(机器学习入门学习笔记:(2.1)线性回归理论推导 )   我们求解线性回归的思路有两个:一个是直接套用上一篇博客最后推导出来的公式:另一 ...

  7. 汇编入门学习笔记 (十二)—— int指令、port

    疯狂的暑假学习之  汇编入门学习笔记 (十二)--  int指令.port 參考: <汇编语言> 王爽 第13.14章 一.int指令 1. int指令引发的中断 int n指令,相当于引 ...

  8. node入门-学习笔记

    文章目录 node入门-学习笔记 node 启动node服务 重构express-run node入门-学习笔记 node 为什么后端要用node, 因为它是js js运行时环境 主要使用expres ...

  9. 计算机指令int,汇编入门学习笔记 (十二)—— int指令、端口

    疯狂的暑假学习之  汇编入门学习笔记 (十二)--  int指令.端口 参考: <汇编语言> 王爽 第13.14章 一.int指令 1. int指令引发的中断 int n指令,相当于引发一 ...

最新文章

  1. DateTime时间格式转换为Unix时间戳格式
  2. AGG第四课 局限性
  3. ssh客户端使用及下载
  4. 斐讯K2 22.4.6.3 非telnet 页面直刷 Breed 详细方法
  5. 利用helloworld来检测VPS的对外端口是否打开
  6. leetcode剑指 Offer 63. 股票的最大利润(动态规划)
  7. 字典排序什么意思_字典排序问题
  8. 【codevs30123037】线段覆盖4、5,姗姗来迟
  9. 程序员的遗憾:为什么我没早学数据分析?
  10. freemarker+springMvc简单实例
  11. 2月28日 PCA降维,SVD压缩,中心化、归一化、标准化、k-l变换
  12. STM32定时器输出pwm波
  13. 30款前端特效源码分享
  14. 《人格心理学》读书笔记
  15. 浏览器地址栏的组成部分
  16. 5个提供flickr高级图片搜索的网站
  17. Win7下安装DirectShow
  18. java拨号上网,Android实现pppoe拨号上网(二)具体步骤
  19. 两本参考书,垒四百块砖的日子
  20. ElasticSearch的基本操作第三章

热门文章

  1. IE与firefox区别
  2. Django项目部署:使用uwsgi和nginx的方式
  3. Nginx的正则表达式
  4. 《C++ Primer》读书笔记
  5. iOS开发之解析XML格式数据
  6. linux 环境下git的安装与配置
  7. 中英文组织机构名过滤
  8. sysvol共享没有出现的处理办法!
  9. python getopt模块_python里argparse模块和getopt模块的区别
  10. 基础总结篇之九:Intent应用详解