一、Xenopsd概述

XenopsdXenServer的虚拟机管理器。 Xenopsd负责:启动,停止,暂停,恢复,迁移虚拟机;热插拔虚拟磁盘(VBD);热插拔虚拟网卡(VIF);热插拔虚拟PCI设备;设置VM控制台;运行的引导程序;设置QoS参数;配置SMBIOS表;处理事故等。

以下列出了完整的功能列表;

通用功能

  • 可插拔的后端包括:

  • XC:通过libxclibxenguest驱动的Xen

  • xenlight:通过libxenlightlibxc驱动的Xen

  • libvirt的:通过libvirt驱动的Xen

  • QEMU:通过运行QEMU进程推动KVM

  • 仿真器:用于模拟组件的测试操作

  • 支持在同一台主机、不同的虚拟机上运行多个实例和后端;

  • 通过命令行(见联机帮助页)和配置文件进行大量的配置;

  • 命令行工具,便于虚拟机管理和故障排除;

  • 用户可设置的并发度虚拟机快速启动;

虚拟机管理功能

  • VM启动/关机/重启;

  • VM挂起/恢复/迁移;

  • VM暂停/恢复;

  • VM休眠/重新开始;

  • 对于OEM锁定虚拟机定制SMBIOS表;

  • 第三方扩展挂钩:

  • 预启动

  • 预销毁

  • 后销毁

  • 预重启

  • 每个虚拟机xenguest工具更换;

  • 禁止VM重新循环引导;

  • vCPU在线热插拔;

  • vCPUPCPU亲和力设置;

  • vCPUQoS设置;

  • DMC内存气球支持;

  • 对于存储驱动程序域的支持;

  • 在线实时更新VM的影子内存;

  • 启动来宾虚拟磁盘/网卡以及热插拔

  • 启动来宾虚拟机的光驱以及弹出

  • 对于可移动磁盘的支持;

  • 磁盘QoS配置;

  • NIC QoS配置;

  • 持续RTC时间管理;

  • 监测和控制的双向代理来宾通信;

  • 网络载体配置;

  • 网卡端口锁定;

  • 通过TCPUnix域套接字连接文本和VNC控制台;

  • PV内核和虚拟内存白名单;

  • 配置虚拟机显存;

  • 在系统crash(崩溃转储)动作发生后执行:关闭虚拟机操作;

  • 将网卡在网桥/交换机之间随时转换的能力;

  • 通告VM的内存占用;

  • PCI直通;

  • 离散仿真器支持(如“demu”);

  • 键盘和鼠标支持;

  • QEMU根域;

  • Cirrusstdvga显卡支持;

  • HVM串行控制台(用于调试);

  • vGPU支持;

  • 解决'spurious page faults'内核bug

  • 解决'machine address size'内核bug

主机

  • 屏蔽CPU电气特性和指令构建异构池;

  • 主机控制台;

  • 管理程序版本和报告;

  • 主机CPU查询;

APIs

  • JSON-RPC API版本的功能显示;

  • 客户端可以断开连接,然后重新连接以获取最新的虚拟机同步状态而不会丢失更新;

  • 所有操作都有任务控制,包括:

  • 异步取消:子进行和xenstore授权表

  • 进度更新

  • 子任务

  • 每个任务的调试日志

  • 异步事件监视;

  • VM指标显示;

  • 内存使用情况;

  • 内存气球调整;

  • 影子内存使用情况;

  • 通道传递(通过发送短消息(2))为有效内存复制镜像。

XenServer的架构之Xenopsd组件架构与运行机制_虚拟机

XenopsdDom0中如上图所示,其主要说明如下:

安全性:Xenopsd虽说是虚拟机管理器,但是它却不能够管理Dom0虚拟机,而且也没有权限管理Dom0虚拟机,因此不用担心它本身对于虚拟机的操作会涉及到Dom0虚拟机。这也意味着可以与其他的虚拟机管理器,如“XL”“libvirt”共存。

独立性:Xenopsd运行在Dom0中。尤其是在资源池的情况下,资源池中的每台主机Dom0中运行着XenopsdMaster中的XenopsdSlave中的Xenopsd都是独立运行的,一些Slave本地主机的组件(如网络)管理不需要经过MasterXenopsd进行过问,Slvae主机本地自己进行管理就好了。

默认情况下Xenopsd监控所有的取消操作。并确保系统在一个取消操作之后,始终处于可控状态。同时Xenopsd提供诊断API和工具,以允许其内部状态被检查和修改。

 

二、Xenopsd架构

Xenopsd实例在主机上运行,并管理其上的虚拟机。图为3种不同的Xenopsd实例:2个名为“xenopsd-XC”1个名为“xenopsd-xenlight”对于Xenopsd实例的管理有两种方式,一种是使用Xenopsd实例的命令行工具,另外一种就是和XAPI进行交互。

XenServer的架构之Xenopsd组件架构与运行机制_第三方_02

每个实例负责管理一组独立的VM。每个VM不能够同时被多个Xenopsd实例管理。每个Xenopsd实例在主机上拥有一个唯一的名称。例如一个比较典型的名字叫:org.xen.xcp.xenops.classic以及org.xen.xcp.xenops.xenlight。同时XAPI将虚拟机与各个Xenopsd实例的名称相关联。

那么在一个主机上运行就会运行着多个Xenopsds实例。因为虚拟硬件通过不同的技术实现(libxclibxl以及qemu),如果是libxc技术实现的虚拟硬件版本的虚拟机,其单独需要一个独立的Xenopsds实例运行管理,同理,基于libxlqemu技术实现的虚拟硬件版本各自需要不同的Xenopsds实例运行管理。即合我们开头所述的那样,在一台主机上必然需要运行多个Xenopsds实例。那么这些实现虚拟硬件的技术有什么区别呢?

实际上libxclibxl都是Xen的一部分,只有QEMU等用户空间程序是根据第三方开源程序修改集成的。libxc是一个C语言库,它提供了一些简单易用的API,使用户程序可以方便的和Hypervisor进行通信。它的工作原理很简单,主要封装了Dom0中的/proc/xen/privcmd/dev/xen/evtchn以及/dev/xen/gntdev提供的IOCTL接口。也就是说,我们本来可以直接通过上面这些内核级设备驱动进行相关的操作控制,但有了libxc之后,只需要调用其相应接口函数,由它负责数据结构的解析/封装,然后再与底层hypervisor通信。这就是为什么说xe发出命令之后,到达xenopsd,而xendopsd需要调用libxc再处理后才与底层hypervisor通信:libxc是一个接口库。

libxl实质上是和xenopsd是一样的,属于虚拟机管理器的范畴和类别。以前的开源Xen有许多的虚拟机管理器,最开始是使用的Xend,其命令行工具集主要是xm,而libxl就是为了代替xend而出现的。其libxl的命令行管理工具是xl。也就是说在这里面,一些针对于虚拟机的管理操作,xenopsd没有必要在进行重新开发,重复制造轮子,只需要调用libxlAPI去实现调用就好。因为libxl现在默认本身就集成在Xen中。因此我们可以这样理解,虚拟硬件的想不通版本分别由不同的管理工具实现其管理。统一到最终上层是和xenopsd进行交互。运行多个xenopsd对应不同的虚拟硬件版本管理工具是有好处的。其好处在于可以根据不同虚拟硬件版本的虚拟机进行分组和隔离。同时也保证我们可以对旧版本的虚拟硬件虚拟机进行滚动升级,我们只需要切换虚拟机的不同虚拟硬件版本支持,关联到其对应的Xenopsd实例运行虚拟机即可。如果虚拟机升级之后存在问题,我们可以再次重新启动回到原来的Xenopsd实例。

所以Xen其实是一个很庞大的东西,由于其历时原因和版本关系,光光针对于虚拟机的管理就存在多个组件。而KVM则相对简单,只有内核部分以及作为模拟器的QEMUKVM工具栈常见的是libvirt,它不属于KVM的一部分,其他的什么扩展功能也不是很多。Libvirt其实也是Xen的虚拟机管理工具,libxl在代替xendxm之后,开发还是存在一些缺陷,比如managed domain 一个XML RPC接口没有,那么要使用这些高级的功能就得去调用Libvirt这个虚拟机管理器来实现。而Xen现在面临的问题,也是和架构有关。由于组件多,各个组件分属不同的社区,所以开发起来反而有点掣肘的感觉。而Xen最要警惕的就是复杂度问题。

讲到这儿继续这个插入这个话题,后面再说正题。XenServer整个系统由hypervisorDom0以及其上运行的DomU组成。hypervisor负责所有特权操作,Dom0负责管理和驱动硬件,DomU运行用户的任务。Xen基本上是属于一个微内核系统。而现在的XenServer社区和Xen社区,其主要任务除了进行Bug修复以及必要的功能更新之外,最主要的工作就是进行相关组件的解耦合。把一些关键的组件从Dom0中分离到各自的独立虚拟机中,分解之后的好处就是隔离性更加好,关键组件可以独立重启。想想Dom0重启而DomU还可以正常运行。网卡驱动有bug崩溃?反正在独立Domain里面,不会把整个系统搞垮。这样就意味着各个组件之间有更加好的独立性,服务可靠性以及性能都会提高。这样也意味着可以得到更好的安全性。当然分解也有一个限度,不能无限制的随意分解。现在各个组件之间的兼容、上下游之间的兼容已经很让人头痛,若以后处理不好,只会更加恶化。

Xen在过去之所以屡屡丢失阵地,我认为和Citrix公司的策略脱不开关系。在开源软件的世界,有着同样的目的的几个产品互相竞争是很正常的事情,比如XenKVM就是如此。首要条件是产品能够达到基本的标准,产品本身是基础,不好后面就没有戏。构建经营生态圈是非常费时费力的一个事情。

Xen在过去几年在社区方面失去了很多阵地,究其原因就是Citrix公司方面对于社区不够重视,收购产品之后都忙着赚真金白银了。比如说在Ubuntu 8.04的时候Xen是被直接打包到系统中的,但是9.x版本到11.x版本里面,由于Citrix公司方面没有专门聘请packager,没有人去维护这个package,它就被移除了。而且其里面的组件复杂不说,还分别属于不同的开源项目和组织进行维护,再加上Citrix公司收购之后对开源的Xen维护投入不够,没有好好的去经营基于Xen的开源生态圈。而且从收购Cloud.com之后的CloudSatck之后就可以看出来,Citrix公司对于开源的生态圈构建并没有什么好的计划和维护经验。这可能和该公司长期做闭源的产品思维有关系。

上述谨代表个人观点,该回归正题了。如最开始的架构图所示,Xenopsd实例在和下层的libxc或者libxl进行通信调用的时候,还会和另一个组件XenStore进行通信,那么XenStore是做什么的呢?XenStoreXen提供的一个域间共享的存储系统,它以字符串形式存放了管理程序和前、后端驱动程序的配置信息。Dom0管理所有的数据,而DomU通过共享内存,向Dom0请求与自己相关的键值,以此实现域间通信。XenStore所进行的域间通信,在底层仍然是通过共享内存和事件通道机制进行的。但是前面已经提到,想要共享内存或者建立事件通道,必须事先进行通信。那么XenStore自身是怎样建立起这些通道的呢?有必要研究一下XenStore的启动过程。

XenServer的架构之Xenopsd组件架构与运行机制_第三方_03

XenStore包含两个模块:Dom0用户空间的xenstored服务主模块,和DomU里的XenBus内核模块;此外,还有各种通信接口。各个部分的功能如下:

XenstoredDom0用户空间的一个服务,负责管理xenstore的数据(tdb),并且处理所有的请求。

XenBus:内核模块,提供DomU内核访问xenstoreAPI,提供用户空间的xenfs接口(/proc/xen/xenbus)。Dom0Xenbus还要初始化xenstored的运行环境。

共享页面:每一个Domain(包括Dom0自身)都有一个与Dom0通信的共享页面(共享环),这个页面同时被映射到了xenstored的内存空间。也就是说这个页面可以同时被xenstoredDom0内核、和对应的DomU内核读写。Xenstored会随时监控页面,只要环被任意一方更新,xenstored就会直接处理消息,不需要内核模块干预。

其运行原理和启动过程如下:Dom0libxl调用libxc,创建新的domU,并分配了属于DomU的共享页面和事件通道,并且通知Xenstored建立domU的管理数据结构;在分配好以后再由XenStore映射回来。这样DomU一启动,就可以从start_info结构体中获取共享内存的地址,与Dom0进行通信了。然而,这样做就意味着Dom0包办了所有的操作,并且要考虑架构相关的因素,精确地控制DomU的内存分布,所以程序变得非常的复杂和难以维护。同时,DomU的内核将请求放入共享环,这时Dom0xenstored会直接检测到这个改变并执行操作,最后把结果返回共享页面。DomU的用户空间需要通过/proc/xen/xenbus来操作XenStore

最后,XenopsdXAPI的通信,是通过一个XAPI全局库:XCP-IDL来处理。这个库的消息框架默认使用HTTP但支持二进制帧格式,其消息编码:默认支持使用JSON,但也是支持XML的。

下面详细描述xenopsd在内部如何进行运作。其下关系图显示xenopsd内部架构:

XenServer的架构之Xenopsd组件架构与运行机制_第三方_04

在图中的顶部我们可以看见有两个RPC的调用请求:一个用于启动虚拟机,另一个获取最新的事件或者更新。该RPC调用被Xenops_server模块接收,并分解成微操作(标有“μ op”)。这些微操作表示的类似行动为:

  • 创建一个VM(新的虚拟机)

  • 创建一个VM(基于XenCenter的系统模板或者现有虚拟机的模板进行的复制)

  • 启动设备模型:设备模型由QEMU实例模拟启动

  • 热插拔设备:这涉及到对XenStore的前端和后端树进行操作

  • 恢复VM(恢复VM之前保存在暂停下的状态)

这些微操作中的每一个通过在“后端插件”的接口函数调用来表示。这些微操作会加入一个处理队列,每个微操作命令对应虚拟机的一个队列。在虚拟机上有一个线程池(其实就是vCPU的分配,你分配的vCPU越多,对应底层的pCPU越多,线程数越多)从虚拟机队列中拉取微操作指令,并调用相应的后端功能。

激活使用后端(只能每个Xenopsd对应一个后端)执行微操作。该Xenops_server_xen后端在上面的图片中我们谈到libxclibxlQEMU来创建和销毁VM

后端除了和libxclibxlQEMU集成协作外,还和其他XAPI服务进行协作,分别是:

  • XCP-rrdd服务:xenopsd的后端与XCP-rrdd记下来协作,拉取虚拟机的数据源,XCP-rrdd会将虚拟机的I/O吞吐量和vCPU利用率等数据传递给它;

  • Squeezed服务:xenopsd的后端与Squeezed服务协作,通过管理控制动态调整虚拟机的内存;

  • SMAPIv2服务:xenopsd的后端与SMAPIv2服务协作,对存储磁盘进行管理;

Xenopsd后端还负责监视正在运行的VM,并对VM的状态进行更新和管理。在Xenops_server_xen后端,是通过XenStoreVM进行监视的:

  • 通过发布的共享环事件

  • 设备热插拔状态变化

当一个要求VM重新启动的事件发生时,对应的操作将会在共享环中被更新。那么该事件就会被Xenopsd后端看到并作为信号向上传播到Xenops_server。并提示这个VM有一个问题需要注意而不是这台VM需要重新启动。此时xenopsd需要对该台VM的状态进行刷新读取,并存储在自己的配置数据库中,以回复XAPI对于该VM状态的请求。为什么这么设计是因为:

  • Xenopsd不允许针对于VM的操作指令重复使用相同的队列,只能一个操作一个队列,操作完成就被关闭;

因为如果针对VM的操作队列有多个,当前一秒这个队列运行完毕,下一秒运行另外一个队列的时候,VM现在就可能处于不同的状态了。也就是通知消息和状态读取分离,避免xenopsdVM的状态读取错误。

最后一点关于xenopsd需要说明的是,其对虚拟机的处理有三类相关的元数据:

  • 系统元数据:这是创建并启动一个虚拟机的数据信息。包括所有关于存储在XenStore的硬盘和网卡信息。

  • VM:这是当虚拟机启动或重启时使用的配置。就像是一个虚拟机的配置文件

  • VmExtra:这是虚拟机运行时的配置。当我们对VM的配置进行更改时。它往往不能立即生效,而是以前的配置运行。如果我们需要立即生效,那么就需要重新启动VM,重新启动VM之后,会更新VmExtra的配置信息,VM会生效最新的配置信息。

系统元数据以及VMVmExtra元数据由Xenopsd存储在Dom0的文件系统中,即Metadata