运维的同事常常遇到这么四个问题:
本文将从以上四个问题入手,结合 Kilo 版本 Nova 源码,在默认 Hypervisor 为 Qemu-kvm 的前提下(不同 Hypervisor 的资源统计方式差别较大 ),揭开 OpenStack 统计资源和资源调度的面纱。
云计算的本质在于将硬件资源软件化,以达到快速按需交付的模式。最基本的计算、存储、网络基础元素并没有因此改变。就计算而言,CPU、RAM 和 DISK等依旧是必不可少的核心资源。
从源码和数据库相关表可以得出,Nova 统计的某个计算节点的计算资源可分为四类
本文重点关注 CPU、RAM 和 DISK 三类资源。
从 源码 可以看出,Nova 每分钟统计一次资源,方式如下:
那么问题来了,按照上述收集资源的方式,free_ram_mb, free_disk_gb 不可能为负数啊!别急,Nova-compute 在上报资源至数据库前,还根据该节点上的虚拟机又做了一次资源统计。
首先分析为什么需要再次统计资源以及再次统计哪些资源。从 源码 可以发现,Nova 根据该节点上的虚拟机再次统计了 RAM、DISK 和 PCI 资源。
为什么要再次统计 RAM 资源?以启动一个内存大小为 4G 的虚拟机为例,虚拟机启动前后,我们对比宿主机上可用内存,发现宿主机上的 free memory 有所减少(本次测试仅仅减少 1G 不到),却没有减少到 4G,如果此时在虚拟机运行很吃内存的应用,可发现宿主机上的可用内存迅速减少。试想,以 64G 的服务器为例,假设每个虚拟机(4G)启动后,宿主机仅减少 1G 内存,服务器可以成功创建 64 个虚拟机,但是当这些虚拟机在跑大量业务时,服务器的内存迅速不足,轻着影响虚拟机效率,重者导致虚拟机 shutdown等。除此以外,宿主机上的内存并不是完全分给虚拟机,系统本身等应用也需要使用内存资源。因此必须重新统计 RAM 资源,统计的方式为:
free_memory = total_memory - CONF.reserved_host_memory_mb - 虚拟机理论内存总和
CONF.reserved_host_memory_mb:内存预留,比如预留给其它应用
虚拟机理论内存总和:即所有虚拟机 flavor 中的内存总和
为什么要重新统计 DISK 资源?原因与 RAM 大致相同。为了节省空间, qemu-kvm 常用 QCOW2 格式镜像(详见 Copy On Write),以创建 DISK 大小为 100G 的虚拟机为例,当虚拟机创建后,查看对于虚拟机镜像文件大小,发现往往只有几百 KB,当虚拟机有大量数据写入时磁盘时,宿主机上对应的虚拟机镜像文件会迅速增大。而 os.statvfs 统计的是当前的磁盘使用量,并不能反映磁盘的的潜在使用量。因此必须重新统计 DISK 资源,统计的方式为:
free_disk_gb = local_gb - CONF.reserved_host_disk_mb / 1024 - 虚拟机理论磁盘总和
CONF.reserved_host_disk_mb:磁盘预留
虚拟机理论磁盘总和:即所有虚拟机 flavor 中得磁盘总和
当允许资源超配时,采用上述统计方式就有可能出现 free_ram_mb, free_disk_gb 为负。
即使 free_ram_mb 或 free_disk_gb 为负,虚拟机依旧有可能创建成功。事实上,当 nova-scheduler 在调度过程中,某些 filter 允许资源超配,比如 CPU、RAM 和 DISK 等 filter,它们默认的超配比为:
以 ram_filter 为例,在根据 RAM 过滤宿主机时,过滤的原则为:
memory_limit = total_memory * ram_allocation_ratio
used_memory = total_memory - free_memory
当 memory_limit - used_memory < flavor[‘ram’],表示内存不足,过滤该宿主机;否则保留该宿主机。
相关代码如下(稍有精简):
def host_passes(self, host_state, instance_type):
"""Only return hosts with sufficient available RAM."""
requested_ram = instance_type[‘memory_mb‘]
free_ram_mb = host_state.free_ram_mb
total_usable_ram_mb = host_state.total_usable_ram_mb
memory_mb_limit = total_usable_ram_mb * CONF.ram_allocation_ratio
used_ram_mb = total_usable_ram_mb - free_ram_mb
usable_ram = memory_mb_limit - used_ram_mb
if not usable_ram >= requested_ram:
LOG.debug("host does not have requested_ram")
return False
上节我们知道,宿主机上 RAM 和 DISK 的使用率往往要小于虚拟机理论使用的 RAM 和 DISK,实际上还有剩余的 RAM 和 DISK,在剩余资源充足的条件下,libvirt 将成功创建虚拟机。
随想:内存和磁盘超配虽然能提供更多数量的虚拟机,当该宿主机上所有虚拟机的负载都很高时,轻着影响虚拟机性能,重则引起 qemu-kvm 相关进程杀,即虚拟机被关机。因此对于线上稳定性要求高的业务,建议不要超配 RAM 和 DISK,适当超配 CPU。建议这几个参数设置为:
本节用于回答问题四,当所有宿主机的资源均使用过多,即超出限定的超配值时(total_resource * allocation_ratio),nova-scheduler 将过滤这些宿主机,当未找到符合要求的宿主机时,该虚拟机将创建失败。
创建虚拟机的 API 支持指定 host 创建虚拟机,当指定 host 时,nova-scheduler 采取特别的处理方式:不再判断该 host 上的资源是否满足需求,直接将请求发给该 host 上的 nova-compute。
相关代码如下(稍有精简):
def get_filtered_hosts(self, hosts, filter_properties,
filter_class_names=None, index=0):
"""Filter hosts and return only ones passing all filters."""
...
if ignore_hosts or force_hosts or force_nodes:
...
if force_hosts or force_nodes:
# NOTE(deva): Skip filters when forcing host or node
if name_to_cls_map:
return name_to_cls_map.values()
return self.filter_handler.get_filtered_objects()
当该 host 上实际可用资源时满足要求时,libvirt 依旧能成功创建虚拟机。
原文地址:http://blog.csdn.net/wsfdl/article/details/45418727