int32bit
作者int32bit·2018-05-17 21:02
研发工程师·民生银行

OpenStack高级特性简介

字数 9358阅读 8022评论 1赞 5

OpenStack中那些很少见但很有用的操作中介绍了一些很少提及但很有用的功能,本文在此基础上介绍几个OpenStack的几个高级特性。这里所谓的高级特性,是指那些非人人都需要的OpenStack通用默认配置,而是专门针对一些特定场景需求设定的。

1 虚拟机软删除

通常情况下,当用户删除虚拟机时,虚拟机会立即从hypervisor底层删除,不可撤回。为了防止人为误操作,Nova支持开启软删除(soft delete)功能,或者称为延迟删除,延迟删除时间通过Nova配置项/etc/nova/nova.confreclaim_instance_interval项指定,如下:
Jietu20180521-225139.png

Jietu20180521-225139.png

此时虚拟机执行普通删除操作时,nova不会立即删除虚拟机,而是会等待两分钟的时间,在此时间间隔内,管理员可以随时恢复虚拟机,只有在超过120秒后虚拟机才会真正执行删除操作,不可恢复。

为了演示该功能,我们删除一台虚拟机int32bit-test-2:
Jietu20180521-212005.png

Jietu20180521-212005.png

通过nova list命令并指定--deleted选项可以列出已删除的所有虚拟机实例:

Jietu20180521-212636.png

Jietu20180521-212636.png

通过nova restore命令可以恢复虚拟机:
Jietu20180521-213056.png

Jietu20180521-213056.png

可见,刚刚删除的虚拟机已经恢复了。

注意如果管理员通过nova force-delete命令强制删除虚拟机,虚拟机会立即从底层删除而无视延迟时间。

需要注意的是,由于这个功能早期设计的缺陷,开启虚拟机软删除功能必须保证所有计算节点和API节点配置一样并且时间同步,并且所有节点的延迟时间不可动态修改,这非常不灵活。我在我们内部私有云二次开发中改善了该功能,延时时间不再通过配置文件指定,而是通过虚拟机的admin metadata指定,这样就不再依赖于各个节点的配置项的同步与更新,并且可随时调整延时时间。

2 CPU拓扑以及核绑定

2.1 概述

OpenStack K版本引入了许多CPU高级特性功能,不仅支持自定义CPU拓扑功能,支持设置虚拟机CPU的socket、core、threads等,还支持CPU pinning功能,即CPU核绑定,甚至能够配置虚拟机独占物理CPU,虚拟机的vCPU能够固定绑定到宿主机的指定pCPU上,在整个运行期间,不会发生CPU浮动,减少CPU切换开销,提高虚拟机的计算性能。除此之外,OpenStack还支持设置threads policy,能够利用宿主机的SMT特性进一步优化虚拟机的性能。

接下来简单介绍下如何配置OpenStack的CPU高级特性。

2.2 规划CPU和内存

在配置之前,首先需要规划计算节点的CPU和内存,哪些CPU分配给虚拟机,哪些CPU给宿主机本身的进程预留,预留多少内存等。为了性能的最优化,还需要考虑宿主机CPU的NUMA架构。

在Linux环境下可以通过以下命令查看CPU信息:
Jietu20180521-213243.png

Jietu20180521-213243.png

由以上信息可知,该宿主机一共两个CPU(socket),每个CPU 10核(core),每个核可以开启两个超线程(thread),即一共有40个逻辑CPU,包含两个NUMA node,其中node0包括0,2,4,...,38,node1包括1,3,5,...,39。

预留CPU个数和内存需要根据实际情况调整,比如若计算节点和存储节点融合,则需要预留更多的CPU来保证存储服务的性能。

本例子仅作为测试使用,测试环境预留了4个逻辑CPU(1-3)和4GB物理内存给宿主机,剩下的资源全部分配给虚拟机使用。

配置虚拟机使用的CPU集合(cpuset)是通过计算节点的vcpu_pin_set配置项指定,目前支持以下三种语法格式:

  • 1,2,3 # 指定CPU号,逗号隔开。
  • 2-15, 18-31 # 使用-表示连续CPU序列,使用逗号分隔。
  • ^0,^1,^2,^3 # 使用^表示排除的CPU号,剩下的全部作为虚拟机使用。

以上三种语法格式可以组合使用。

compute节点Nova参考配置如下:
Jietu20180521-213814.png

Jietu20180521-213814.png

如果需要配置虚拟机CPU独占,则还需要配置内核参数isolcpu来限制其他进程使用指定的CPU。比如我们需要把CPU 2,3,6,7作为CPU pinning给虚拟机独占,设置如下:
Jietu20180521-213834.png
Jietu20180521-213834.png

重新安装grub:
Jietu20180521-213852.png
Jietu20180521-213852.png

重启宿主机,下次系统启动时会默认添加如下内核参数:
Jietu20180521-214029.png
Jietu20180521-214029.png

在nova-scheduler节点上,需要配置默认filter,filters中必须包含AggregateInstanceExtraSpecFilterNUMATopologyFilter这两个filter:
Jietu20180521-214056.png
Jietu20180521-214056.png

配置完重启所有的nova-scheduler服务:
Jietu20180521-214948.png
Jietu20180521-214948.png

2.3 创建主机集合

在实际环境中肯定不是所有的计算节点都开启这些高级功能,并且CPU特性也有差别,我们可以通过主机集合(host aggregate)把所有相同的CPU配置放到一个集合中,通过主机集合(host aggregate)区分哪些计算节点开启CPU核绑定功能,哪些不开启。

首先创建pinned-cpu主机集合:
Jietu20180521-215109.png

Jietu20180521-215109.png

增加metadata区分pinned:
Jietu20180521-215123.png
Jietu20180521-215123.png

把配置开启了CPU核绑定功能的两个host加到该主机集合中:
Jietu20180521-215135.png
Jietu20180521-215135.png

此时nova scheduler只要接收到包含pinned=true元数据的请求就会自动从包含pinned=true元数据的主机中调度。

2.4 创建flavor

目前Nova并不支持启动时直接指定主机集合的metadata(hint只支持指定server group),需要通过flavor的extra specs配置,并与主机集合的metadata匹配,不匹配的主机将被过滤掉,不会被选择作为候选主机。

flavor支持很多内置的extra specs,通过内置extra specs,可以配置虚拟机的CPU拓扑、QoS、CPU pinning策略、NUMA拓扑以及PCI passthrough等,更详细的介绍可参考官方文档。这里我们只关心CPU拓扑和核绑定功能。

如下是设置CPU topology的语法,自定义CPU的socket数量、core数量以及超线程数量:
Jietu20180521-215321.png

Jietu20180521-215321.png

注意以上配置项不需要全部设置,只需要设置其中一个或者几个,剩余的值会自动计算。

CPU核绑定配置语法如下:
Jietu20180521-215427.png

Jietu20180521-215427.png

其中CPU-POLICY合法值为shareddedicated,默认为shared,即不进行CPU核绑定,我们需要把这个值设置为dedicated
CPU-THREAD-POLICY和SMT有关,合法值为:

  • prefer: 宿主机不一定需要符合SMT架构,如果宿主机具备SMT架构,将优先分配thread siblings。
  • isolate: 宿主机SMT架构不是必须的,如果宿主机不具备SMT架构,每个vCPU将绑定不同的pCPU,如果宿主机是SMT架构的,每个vCPU绑定不同的物理核。
  • require: 宿主机必须满足SMT架构,每个vCPU在不同的thread siblins上分配,如果宿主机不具备SMT架构或者core的空闲thread siblings不满足请求的vCPU数量,将导致调度失败。

通常设置成默认值prefer或者isolate即可。

接下来开始创建flavor,设置为8个CPU、2GB内存以及20GB磁盘空间:
Jietu20180521-215617.png

Jietu20180521-215617.png

设置CPU Policy:
Jietu20180521-215628.png
Jietu20180521-215628.png

添加pinned相关的extra specs用于匹配主机集合metadata,保证调度时只选择开启了核绑定的宿主机:
Jietu20180521-215638.png
Jietu20180521-215638.png

配置CPU拓扑为2 sockets 2 cores 2 threads:
Jietu20180521-215659.png
Jietu20180521-215659.png

查看flavor的extra specs信息:
Jietu20180521-215725.png
Jietu20180521-215725.png

2.5 功能验证

使用新创建的Flavor创建虚拟机:
Jietu20180521-220023.png

Jietu20180521-220023.png

使用nova show命令查看虚拟机所在的宿主机,在该宿主机上查看虚拟机的xml文件:
Jietu20180521-220034.png
Jietu20180521-220034.png

其中306abd22-28c5-4f91-a5ce-0dad03a35f4为虚拟机的uuid。

在xml文件中可以看到如下内容:
Jietu20180521-220048.png

Jietu20180521-220048.png

即vCPU与pCPU的绑定关系。

进入虚拟机中查看CPU信息结果如下:
Jietu20180521-221143.png

Jietu20180521-221143.png

和我们配置的结果一样(2 sockets * 2 cores * 2 threads)。
在虚拟机上执行高密度计算,测试的Python脚本如下:
Jietu20180521-221450.png
Jietu20180521-221450.png

使用shell脚本同时跑50个进程,保证CPU满载运行:
Jietu20180521-221505.png
Jietu20180521-221505.png

使用sar命令查看宿主机CPU使用情况:
Jietu20180521-221851.png
Jietu20180521-221851.png

结果如下:
webwxgetmsgimg.jpeg
webwxgetmsgimg.jpeg

从CPU使用情况看宿主机的pCPU 4-5,8-9,24-25,28-29使用率100%,并且整个过程中没有浮动,符合我们的预期结果,说明CPU核绑定成功。

3 虚拟化嵌套

3.1 开启虚拟化嵌套

默认情况下我们创建的KVM虚拟机的CPU特性中没有包含vmx,这意味着不能在虚拟机中再创建开启KVM硬件加速的虚拟机,即不支持虚拟化嵌套。值得庆幸的是,目前除了VirtualBox(题外话:VirtualBox在9年前就有人提出要支持嵌套,只是一直没有实现,参考ticket #4032),主流的hypervisor比如VMware、KVM、Xen都支持已经虚拟化嵌套。也就是说,我们可以实现在支持KVM的宿主机创建同样支持KVM的虚拟机。

这里以KVM为例,首先查看系统是否开启了KVM嵌套功能:
Jietu20180521-222934.png

Jietu20180521-222934.png

如果输出为N则表明没有开启KVM嵌套功能,可以通过修改/etc/modprobe.d/kvm-intel.conf配置文件开启该功能:
Jietu20180521-222651.png
Jietu20180521-222651.png

重新加载kvm-intel内核模块:
Jietu20180521-222701.png
Jietu20180521-222701.png

3.2 配置计算节点

OpenStack支持虚拟化嵌套,修改计算节点的nova配置文件/etc/nova/nova.conf,设置cpu_mode = host-passthrough,然后重启nova-compute服务即可。

需要注意的是,使用host-passthrough的虚拟机迁移功能受限,只能迁移到相同配置的宿主机。

4 使用virtio-scsi驱动

4.1 virtio-blk VS virtio-scsi

虚拟机的虚拟硬盘默认使用半虚拟化驱动virt-blk,此时硬盘在虚拟机的设备名称形如/dev/vda/dev/vdb等。

事实上,virt-blk有点老了,其本身也存在许多问题,比如:

  • virt-blk的存储设备和PCI设备一一对应,而我们知道系统中至多可以有32个PCI总线,这说明虚拟机最多可以挂32个虚拟硬盘。
  • virt-blk的设备名称为vd[a-z],而现代的物理机通常都会使用SCSI控制器,设备名称为sd[a-z],这意味着物理机迁移到虚拟机中可能存在问题,比如fstab中使用的设备名挂载而不是uuid,系统就会起不来。
  • WIKI所言,virt-blk实现的指令不是标准的,并且可扩展差,实现一个新的指令,必须更新所有的guest。
  • 云计算架构模式下,为了节省存储空间,用户更倾向于使用精简置备(thin provision),virtio-blk不支持discard特性,关于discard特性后面讲。

因此,建议使用virtio-scsi半虚拟化驱动代替virtio-blk,这是因为:

  • 实现的是标准的SCSI指令接口,不需要额外实现指令,在虚拟机里看到的设备名称和物理机一样(sd[a-z]),解决了前面提到的物理机和虚拟机设备名不一样的问题。
  • 一个SCSI控制器可以接256个targets,而一个target可以接16384个LUNs,也就是说一个controller理论上可以挂载256 * 16384 == 4194304个虚拟机硬盘,这100%足够了。
  • virtio-scsi支持直通模式(passthrough),也就是说可以把物理机的硬盘直接映射给虚拟机。
  • virtio-scsi支持前面提到的discard特性。

4.2 块设备的discard功能

前面提到块设备的discard特性,这个主要和精简置备有关,就拿Ceph RBD说,我们知道当我们分配一个20GB的image时,Ceph并不会真正分配20GB的存储空间,而是根据需要逐块分配,这和Linux的sparse稀疏文件的原理是一样的,这个特性节省了物理存储空间,实现了硬盘的超售。然而,Ceph只知道上层文件系统需要空间时就分配,而并不知道上层文件系统如何使用存储资源的(实际上也不关心)。而实际上,我们的文件系统肯定是频繁创建文件、删除文件的,删除文件后按理说是可以释放物理存储资源的,然而Ceph并不知道,所以不会回收,占据的存储空间会越来越多,直到空间达到真实的分配空间大小(20GB),而文件系统层可能并没有真正使用那么多空间,这就造成了存储空间利用率下降的问题。比如,我们创建了一个5GB的文件,Ceph底层会分配5GB的空间,此时我们把这个5GB的文件删除,分配的这5GB空间并不会释放。好在Linux支持fstrim,如果块设备支持discard特性,文件系统会发送flush通知给底层块设备(RBD),块设备会回收空闲资源。Sébastien Han写了一篇博客关于ceph discard的,参考ceph and krbd discard

正如前面所言,virt-blk是不支持discard的,而virt-scsi支持,所以如果关心底层存储的空间利用率,建议使用virt-scsi,并在挂载设备中指定discard参数(或者写到fstab中):
Jietu20180521-223453.png

Jietu20180521-223453.png

但是需要注意的是,任何事物都具有两面性,既有优点,也存在缺点:

  • virio-scsi相对virtio-blk IO路径会更复杂,性能可能会有所下降,参考virtio-blk vs virtio-scsi
  • 通过mount命令挂载虚拟硬盘时开启discard特性会降低文件系统的读写性能。

4.3 OpenStack使用virtio-scsi驱动

前面讲了那么多关于virio-blk以及virtio-scsi,那怎么在OpenStack中使用virtio-scsi呢?很简单,只需要设置Glance镜像的property就可以了:
Jietu20180521-223504.png

Jietu20180521-223504.png

通过这个配置不仅使根磁盘会使用virtio-scsi驱动,挂载新的Cinder volume也会默认使用virtio-scsi驱动。

需要注意的是,制作OpenStack镜像时一定要保证initrd中包含virtio-scsi驱动,否则操作系统会由于在初始化时不识别SCSI块设备导致启动失败:
Jietu20180521-223518.png

Jietu20180521-223518.png

如果镜像的initrd没有virtio驱动,可以编辑/etc/sysconfig/kernel文件,配置INITRD_MODULES参数:
Jietu20180521-223535.png
Jietu20180521-223535.png

然后重新生成initrd文件:
Jietu20180521-223549.png
Jietu20180521-223549.png

启动虚拟机后,如果根硬盘的设备名称为/dev/sda,则说明使用的是virtio-scsi驱动。

5 使用qemu-guest-agent

5.1 qemu-guest-agent简介

我们都知道OpenStack虚拟机启动时是通过cloud-init完成初始化配置的,比如网卡配置、主机名配置、注入用户密码等。而虚拟机启动之后处于运行状态时,外部如何与虚拟机通信呢,这就是qemu-guest-agent要完成的事,这其实在如何构建OpenStack镜像一文中已经介绍过,这里直接搬过来。

qemu-guest-agent是运行在虚拟机的一个daemon服务,libvirt会在宿主机本地创建一个unix socket,并模拟为虚拟机内部的一个串口设备,从而实现了宿主机与虚拟机通信,这种方式不依赖于TCP/IP网络。

如下是开启qemu-guest-agent的虚拟机xml配置信息:
Jietu20180521-223856.png

Jietu20180521-223856.png

以上宿主机的socket文件为org.qemu.guest_agent.0.instance-00003c2c.sock,在虚拟机内部映射为/dev/virtio-ports/org.qemu.guest_agent.0

通过这种方式,宿主机只要发送指令到该socket文件中就会在虚拟机对应的串口设备中收到,虚拟机内部的qemu-guest-agent会轮询查看这个串行设备是否有指令,一旦接收到指令就可以执行对应的脚本,从而实现了宿主机控制虚拟机执行命令的功能,其中最常用的指令就是通过libvirt修改虚拟机密码。更多关于qemu-guest-agent请参考官方文档

5.2 在OpenStack中应用

首先在制作镜像时需要安装qemu-guest-agent服务:
Jietu20180521-223909.png

Jietu20180521-223909.png

在glance镜像中添加hw_qemu_guest_agent property:
Jietu20180521-223919.png
Jietu20180521-223919.png

可以通过Nova的nova set-password <server>子命令验证修改虚拟机的密码功能。

需要注意的是,Nova默认修改的是管理员用户的密码,Linux系统为root,Windows系统为Administrator,因此上传镜像时需要指明镜像是什么操作系统类型:
Jietu20180521-223944.png

Jietu20180521-223944.png

当然你也可以通过os_admin_user属性配置修改其他用户的密码,比如配置修改密码时指定用户不是root,而是ubuntu用户:
Jietu20180521-223953.png
Jietu20180521-223953.png

6 网卡多队列

默认情况下网卡中断由单个CPU处理,当有大量网络包时单个CPU处理网络中断就可能会出现瓶颈。通过网卡多队列技术可以把网卡的中断分摊到多个CPU中。阿里云官方文档测试表明在网络PPS和网络带宽的测试中,与1个队列相比,2个队列最多可提升50%到1倍,4个队列的性能提升更大。

OpenStack支持配置网卡多队列(要求内核版本大于3.0),配置方法如下:
Jietu20180521-224307.png

Jietu20180521-224307.png

队列长度固定为虚拟机的核数。

创建虚拟机查看网卡信息:
Jietu20180521-224543.png

Jietu20180521-224543.png

网卡信息表明支持的最大队列(Combined)为2,目前设置为1,可以通过ethtool工具修改配置:
Jietu20180521-224632.png
Jietu20180521-224632.png

为了保证中断自动均衡到所有的CPU,建议开启irqbalance服务:
Jietu20180521-224641.png
Jietu20180521-224641.png

7 watchdog

在一些分布式集群中,我们可能期望虚拟机crash时自动关机,防止出现集群脑裂。或者当负载过高时自动执行重启,使服务恢复正常。

OpenStack支持配置虚拟watchdog,首先制作镜像时需要安装并开启watchdog服务:
Jietu20180521-224747.png

Jietu20180521-224747.png

配置如下glance image属性:
Jietu20180521-224758.png
Jietu20180521-224758.png

其中支持的action列表如下:

  • reset: 强制重启。
  • shutdown: 安全关机。
  • poweroff: 强制关机。
  • pause: 停止虚拟机。
  • 'none': 不执行任何操作。
  • 'dump': 导出dump core。

参考官方文档可以查看更详细的配置。

8 GPU虚拟化

OpenStack从Q版本开始支持GPU虚拟化,由于测试环境中没有GPU,因此本文仅参考官方文档描述配置过程。

首先在安装有GPU(假设为nvidia-35)的计算节点中修改nova配置文件:
Jietu20180521-224811.png

Jietu20180521-224811.png

重启nova-compute服务:
Jietu20180521-224820.png
Jietu20180521-224820.png

创建一个flavor,通过resources:VGPU=1extra specs指定虚拟GPU个数:
Jietu20180521-224837.png
Jietu20180521-224837.png

使用该flavor创建的虚拟机就会分配一个虚拟GPU。

需要注意的是,如果使用libvirt driver,对于分配了vGPU的虚拟机:

  • 不能执行挂起(suspend)操作,这是因为libvirt不支持vGPU的热插拔功能。
  • 冷迁移(migrate)、拯救(rescue)或者通过resize指定另一个设置了GPU的flavor,虚拟机都将不会再分配GPU,可以通过再执行一次rebuild操作恢复。

9. 参考文献

  1. 维基百科NUMA.
  2. NUMA架构的CPU -- 你真的用好了么?.
  3. OpenStack官方文档--Flavor.
  4. CPU pinning and numa topology awareness in OpenStack compute.
  5. Simultaneous multithreading - Wikipedia.
  6. isolcpus、numactl and taskset.
  7. Virtio-scsi.
  8. ceph and krbd discard.
  9. virio-blk vs virio-scsi.
  10. virtual gpu.
  11. libvirt watchdog.
  12. enable netsted virtualization kv centos 7.
  13. inception how usable are nested kvm guests.
  14. more recommandations ceph openstack.
  15. 阿里云网卡多队列文档.

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

5

添加新评论1 条评论

xjtu2019xjtu2019研发工程师苏研
2019-03-05 14:58
学习了,长见识了,向楼主学习
Ctrl+Enter 发表

本文隶属于专栏

新品解读
不同的趋势领域,总会不断有新的产品进行发布。但是新的产品价值如何结合用户需求被解读出来,让更多的企业用户迅速建立对产品优劣势的价值了解。能够把企业群体的需求进行抽练,并且同时让产品的价值对接后还能通俗易懂的解读出来,作者往往不是来自某一个人,而是一个团队。

作者其他文章

相关文章

相关问题

相关资料

X社区推广