Nova 深度解析:OpenStack 计算服务核心原理与二次开发
架构总览
Nova 是 OpenStack 最核心的组件,负责虚拟机的全生命周期管理。它本身是一个分布式系统,由多个进程协作完成工作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 外部请求 │ ▼ nova-api ← REST API 入口,参数校验,配额检查 │ RPC call ▼ nova-conductor ← 数据库操作代理,防止 compute 直连 DB │ RPC call ▼ nova-scheduler ← 选择目标宿主机(FilterScheduler) │ RPC cast ▼ nova-compute ← 实际执行,调用 libvirt/hypervisor │ ├── nova-novncproxy ← VNC 控制台代理 └── nova-metadata ← 虚拟机元数据服务(cloud-init 用)
|
进程职责
| 进程 |
职责 |
是否有状态 |
| nova-api |
HTTP API 服务,写 DB 创建 instance 记录 |
无状态,可多实例 |
| nova-conductor |
DB 操作代理,复杂编排逻辑 |
无状态,可多实例 |
| nova-scheduler |
资源过滤与打分,选宿主机 |
无状态,可多实例 |
| nova-compute |
宿主机上的 agent,管理本机 VM |
有状态,每宿主机一个 |
Cell v2 架构
从 Queens 版本起,Nova 正式采用 Cell v2 架构解决大规模集群的扩展性问题:
1 2 3 4 5 6 7 8 9
| nova_api DB(全局) ├── cell_mappings 表(记录所有 Cell) └── instance_mappings 表(记录 VM 在哪个 Cell)
nova_cell0 DB(失败的调度记录)
nova_cell1 DB(Cell 1 的 VM 数据) nova_cell2 DB(Cell 2 的 VM 数据) ...
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| nova-api(全局) │ ├── nova-conductor(cell0,处理调度失败) │ ├── Cell 1 │ ├── nova-conductor │ ├── nova-scheduler │ └── nova-compute × N │ └── Cell 2 ├── nova-conductor ├── nova-scheduler └── nova-compute × N
|
核心优势:每个 Cell 独立的 DB 和 MQ,单 Cell 故障不影响其他 Cell,支持万级宿主机规模。
虚拟机创建完整流程
源码追踪:_build_and_run_instance
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
@wrap_exception() def build_and_run_instance(self, context, instance, ...): network_info = self._build_networks_for_instance(context, instance, ...)
block_device_info = self._prep_block_device(context, instance, ...)
self.driver.spawn( context, instance, image_meta, injected_files, admin_password, network_info=network_info, block_device_info=block_device_info )
|
libvirt Driver 层
1 2 3 4 5 6 7 8 9 10 11 12
|
def spawn(self, context, instance, image_meta, ...): self._create_image(context, instance, disk_info, ...)
xml = self._get_guest_xml(context, instance, network_info, ...)
guest = self._create_guest(xml, ...) guest.launch()
|
libvirt XML 示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <domain type='kvm'> <name>instance-00000001</name> <memory unit='KiB'>2097152</memory> <vcpu placement='static'>2</vcpu> <os> <type arch='x86_64' machine='pc-i440fx-2.11'>hvm</type> <boot dev='hd'/> </os> <devices> <disk type='file' device='disk'> <driver name='qemu' type='qcow2' cache='none'/> <source file='/var/lib/nova/instances/uuid/disk'/> <target dev='vda' bus='virtio'/> </disk> <interface type='bridge'> <source bridge='brq...'/> <model type='virtio'/> </interface> </devices> </domain>
|
调度器深度解析
FilterScheduler 工作流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
def select_destinations(self, context, spec_obj, ...): alloc_reqs, provider_summaries = self._get_all_host_states(...)
hosts = self.host_manager.get_filtered_hosts(hosts, spec_obj)
weighed_hosts = self.host_manager.get_weighed_hosts(hosts, spec_obj)
return weighed_hosts[:num_instances]
|
内置 Filters
| Filter |
作用 |
ComputeFilter |
过滤掉 nova-compute 服务不可用的节点 |
RamFilter |
内存不足的节点过滤掉 |
DiskFilter |
磁盘不足的节点过滤掉 |
CoreFilter |
CPU 不足的节点过滤掉 |
AvailabilityZoneFilter |
按 AZ 过滤 |
ComputeCapabilitiesFilter |
按宿主机 extra_specs 过滤 |
ImagePropertiesFilter |
按镜像属性过滤(如 hw_architecture) |
NUMATopologyFilter |
NUMA 拓扑感知调度 |
AggregateInstanceExtraSpecsFilter |
按主机聚合的 metadata 过滤 |
自定义 Filter 示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| from nova.scheduler import filters
class GPUFilter(filters.BaseHostFilter): """只选择有 GPU 的宿主机"""
def host_passes(self, host_state, spec_obj): extra_specs = spec_obj.flavor.extra_specs if extra_specs.get('resources:VGPU', 0) == 0: return True
return host_state.stats.get('has_gpu', False)
|
热迁移(Live Migration)原理
热迁移是生产中最复杂、最容易出问题的操作。
迁移流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 源宿主机 nova-compute 目标宿主机 nova-compute │ │ │ 1. pre_live_migration() │ │ ──────────────────────────► │ │ │ 准备网络、磁盘 │ 2. 开始内存传输(libvirt) │ │ ══════════════════════════► │ 持续同步内存脏页 │ │ │ 3. 内存脏页收敛后,暂停源VM │ │ ──────────────────────────► │ │ │ 最后一次内存同步 │ 4. post_live_migration() │ │ ◄────────────────────────── │ │ │ │ 5. 清理源 VM │
|
关键源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
def live_migration(self, context, dest, instance, ...): self._live_migration_operation(context, instance, dest, ...)
def _do_live_migration(self, context, dest, instance, ...): self.driver.live_migration( context, instance, dest, post_method=self.post_live_migration, recover_method=self.rollback_live_migration, ... )
|
迁移失败常见原因
| 原因 |
排查方式 |
| 目标节点内存不足 |
检查 Placement 资源分配 |
| 网络不通 |
检查两节点间 libvirt migration port(16509/49152-49261) |
| 共享存储未挂载 |
检查 NFS/Ceph 挂载状态 |
| CPU 型号不兼容 |
检查 cpu_mode 配置,建议用 host-model |
| 内存脏页无法收敛 |
VM 内存写入过于频繁,考虑冷迁移 |
虚拟机状态机
1 2 3 4 5 6 7
| BUILD ──► ACTIVE ──► SHUTOFF │ │ │ │ REBOOT REBUILD │ │ │ │ MIGRATING RESIZING │ │ │ └──► ERROR ◄──────────┘
|
状态存储在 instances.vm_state 和 instances.task_state 两个字段:
vm_state:稳定状态(active/stopped/error)
task_state:过渡状态(spawning/migrating/deleting)
生产级二次开发实践
1. 扩展虚拟机元数据
2. 自定义虚拟机创建 Hook
1 2 3 4 5 6 7 8
|
def _build_and_run_instance(self, context, instance, ...): self._pre_create_hook(instance) self.driver.spawn(...) self._post_create_hook(instance)
|
3. 性能优化关键配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| [DEFAULT]
max_concurrent_builds = 10
[scheduler] discover_hosts_in_cells_interval = 300
[libvirt] num_pcie_ports = 28 virt_type = kvm cpu_mode = host-passthrough
|
关键监控指标
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| groups: - name: nova rules: - alert: NovaComputeDown expr: openstack_nova_agent_state{service="nova-compute"} == 0 for: 2m labels: severity: critical
- alert: NovaHighBuildFailureRate expr: rate(openstack_nova_server_status{status="ERROR"}[5m]) > 0.1 for: 5m labels: severity: warning
- alert: NovaSchedulerNoValidHost expr: increase(nova_scheduler_attempts_total{result="failure"}[5m]) > 10 labels: severity: warning
|