OpenStack虚拟机实时迁移实战:Live Migrate原理与排障

发布时间:2026/10/1 11:21:15
OpenStack虚拟机实时迁移实战:Live Migrate原理与排障 早上八点机房值班群弹出告警一台宿主机内存寿命告警硬件需要下电检修。可它上面还跑着二十多台云主机业务方甩过来一句话“搬走可以别停机。”这种时候OpenStack 运维手里那张底牌就叫 Live Migrate。Live Migrate 这词听着高级说穿了就是给一台正在运行的云主机“在行驶中换发动机”——虚拟机不用关机业务几乎无感知地从一个计算节点搬到另一个计算节点。这篇东西我按生产环境的实战角度把 Live Migrate 的原理、前置条件、操作命令和排障链路完整梳理一遍适合刚接触 OpenStack 虚拟化运维的新人也适合已经踩过不少坑、想系统回看一遍的老手。1. Live Migrate 到底“搬”的是什么预拷贝、中断窗口与共享存储1.1 实时迁移不是云主机整体“打包快递”很多刚做运维的朋友会误解实时迁移是不是把虚拟机的整块磁盘文件拷贝过去不是。日常最常见的实时迁移场景下云主机的磁盘其实位于共享存储比如 NFS、Ceph RBD源节点和目标节点能看到同一份磁盘数据。所以真正需要搬的只有两部分虚拟机内存里的页面状态以及 CPU 寄存器和设备状态。磁盘数据本身并不需要复制。这个机制和搬家做一个类比共享存储相当于“仓库”源宿主机和目标宿主机都在同一个仓库门口取货。你把正在写的一叠文件搬到隔壁办公桌只需要带上一支笔和一张纸而不是把整个仓库搬过去。只有当磁盘在本地节点、不在共享存储上时系统才会被迫在迁移时把磁盘也复制一份过去这就是另一套逻辑后面单独讲。1.2 OpenStack 调度中介与 QEMU 迁移动作命令行敲下去之后请求会先到 nova-api再到 nova-scheduler 选一个目标节点然后由源节点上的 nova-compute 服务调用 libvirt 的迁移接口把脏页状态持续拷贝到目标节点。整个过程分几个阶段预拷贝阶段QEMU 在内存不断变化的同时把内存页面迭代拷贝到目标节点。收敛阶段当剩余脏页速度低于网络传输速度时系统会短暂冻结虚拟机执行。切换阶段把最后的少量脏页、CPU 寄存器和设备状态传到目标节点。收尾阶段目标节点恢复虚拟机执行源节点销毁残留的域实例。切换阶段通常只有几十到几百毫秒这是业务“几乎无感知”的来源。如果配置、网络和存储都没问题一个 8 GB 内存的实例迁移完成时间通常在几十秒级别具体取决于脏页率、带宽和磁盘类型。1.3 为什么说“共享存储”是实时迁移的第一关键词前面已经暗示了实时迁移的底气是共享存储。但真实生产环境里我见过不少 OpenStack 集群的计算节点根本没有接共享存储全靠本地磁盘跑实例。这种情况不是不能迁而是要走块迁移Block Migration也就是把实例的根磁盘和临时盘也复制到目标节点再做状态切换。块迁移在迁移期间会持续复制磁盘数据业务写入量大时磁盘数据基本追不完反而更容易失败。所以在规划 OpenStack 架构时如果未来有 Live Migrate 的需求强烈建议把实例系统盘放到 Ceph RBD 或成熟共享存储上。Ceph RBD 天然支持多节点并发读写对实时迁移非常友好。如果必须用本地盘那就要在云主机初始化阶段想清楚这台机器未来有没有迁移需求迁移窗口和数据量能不能接受2. 动手前先“体检”CPU 型号、磁盘空间和网络连通性三座大山2.1 CPU 型号不统一迁移就是拆盲盒实时迁移要求源节点和目标节点的 CPU 指令集必须兼容。这里说的不是“同品牌就行”而是 QEMU 会去比较两端 CPU 的具体 feature 集合。Intel 和 AMD 混布、不同代际的 Intel CPU 混布的集群很容易在迁移时看到类似这样的日志libvirtError: internal error: unable to execute QEMU command migrate: Migration is not possible due to incompatible CPU要解决这个问题通常两个思路集群内尽量采购同型号、同代际的 CPU这是最省心的办法。在 nova.conf 里把 libvirt 的 CPU 模式设置为 custom指定一个两端 CPU 都支持的公共型号比如 SandyBridge、Broadwell 等。配置示例如下[libvirt] cpu_mode custom cpu_model Skylake-Client设置完要记得重启 nova-compute 服务并让实例重建或软重配才可能生效。已经运行的实例不会自动改虚拟 CPU 配置。如果条件允许也可以用cpu_mode host-model它会让 QEMU 自动选择宿主机最接近的模型。但对型号差异大的混合集群host-model 仍然有风险custom 指定公共模型才是可控方案。2.2 磁盘空间和块迁移的“隐形消耗”本地盘块迁移时目标节点需要和源节点一样大的磁盘空间来装下根磁盘快照。很多人迁移失败就是因为目标节点剩余空间比实例磁盘小几百 MB结果复制到 99% 的时候报No space left on device。这时候实例还可能处于 Migrating 中间态处理起来很尴尬。建议在迁移之前做一次“空间预计算”用du -sh或qemu-img info查看实例磁盘实际占用。确认目标节点可用空间至少为实例磁盘大小的 1.2 倍最好能有 1.5 倍因为迁移中还会产生临时文件、日志和内存页缓存。块迁移过程中磁盘的写入量会全部变成复制流量迁移期间的业务写放大不可忽视。比如业务正在跑一个 5 GB 的大文件导入迁移时间可能从 15 分钟被拖到 40 分钟以上。2.3 网络连通固定 IP 不丢才是“真 Live”迁移后虚拟机网卡 MAC 和固定 IP 必须保持不变请求才能无感切换到新节点。因此源节点和目标节点的二层网络必须互通特别是用了 VXLAN 或 VLAN 组网时要确保隧道有足够的 MTU且安全组、端口绑定规则不会拦截迁移后虚拟机发出的 ARP 报文。一个容易被忽略的点如果平台接入了外部控制器或防火墙策略迁移之后目标节点上的流量出现在另一台物理机下联交换机会把它当作“陌生 MAC”处理。所以生产网络最好是先允许迁移目标范围内的宿主机转发该租户网络流量。另外管理网络与存储网络也要单独跑通QEMU 迁移流通常走管理网或存储网如果带宽只有千兆内存 32 GB 并且脏页率高的实例迁移时会明显变慢。3. 实操演示命令、参数选择与迁移状态追踪这一节我直接用生产里常用的命令流程走一遍。假设有两个计算节点compute1是源节点compute2是目标节点。3.1 迁移前的环境盘点先确认集群规化和云主机分布# 查看所有计算节点 nova host-list # 列出当前节点上的所有云主机 nova list --all-tenants --host compute1 # 查看目标节点的资源余量 nova host-show compute2注意查看(gigabytes)、(vcpus)和(memory_mb)这几个资源量确认目标节点有足够余量承接。迁移动作本身对计算资源开销不算大但如果节点本身已经超售到极限目标节点上的其他实例性能会受影响。3.2 核心命令指定目标主机与块迁移策略传统 nova 命令# 指定目标节点不带块迁移适合共享存储 nova live-migration --host compute2 server_uuid # 指定目标节点并且块迁移本地磁盘 nova live-migration --block-migrate --host compute2 server_uuid新版 OpenStack CLI 的写法类似openstack server migrate --live server_uuid --wait需要说明的是不同发行版的 CLI 参数名略有差异尤其是openstack server migrate在旧版本里不一定支持--live参数。上手前先执行openstack server migrate --help看一眼确认你的客户端版本支持哪些选项。如果不指定--hostnova-scheduler 会自动选择一个满足资源条件的目标节点。我的建议是日常操作尽量显式指定目标节点。自动调度虽然方便但你可能并不清楚这台实例迁过去之后宿主机当前的运行负载和磁盘 I/O 压力。3.3 状态追踪别只盯着 OpenStack 面板提交迁移后第一时间确认status是否进入MIGRATINGwatch -n 2 openstack server show server_uuid -c status -c OS-EXT-SRV-ATTR:host正常情况下状态会从ACTIVE变为MIGRATING迁移完成后变回ACTIVE并且OS-EXT-SRV-ATTR:host字段变成目标节点。如果迁移过程中状态长时间停留在MIGRATING说明可能内存脏页收敛困难或者磁盘复制速度跟不上。迁移完成后登录实例执行uptime或检查会话是否连续。实时迁移成功后主机运行时间不会中断业务进程也不应该重启。如果发现实例的 uptime 清零了说明它不是被迁移而是被冷启动过需要回查操作过程。4. 踩坑复盘从 nova-compute 日志一路摸到 libvirt 底层迁移报错不可怕可怕的是不知道去哪里看日志。我平时排查的顺序固定如下看源节点 nova-compute.log 中的 Migration 相关错误。看目标节点 nova-compute.log 中是否有 libvirt 连接失败、资源不足等信息。看/var/log/libvirt/qemu/instance_name.log中 QEMU 自身的崩溃或迁移中断信息。用virsh list查看两个节点上该实例域是否残留。4.1 一个典型的迁移失败现场有次给客户节点做迁移命令执行后不到十秒就收到失败回执。源节点 nova-compute.log 里有这么一行LiveMigration failed: local disks and cannot be migrated原因非常直白目标与源之间没有共享存储实例根磁盘在本地但我没有加--block-migrate。加上了之后再次提交又出现新的报错Failed to get shared storage: path /data/nova/instances does not exist这说明目标节点计算服务虽然配置了同样的实例路径但挂载点不一致或者共享存储压根没挂上。最终检查发现是 NFS 客户端挂载参数里写的是旧 IP目标节点换过存储 IP 后没有同步更新 fstab。把挂载路径修正并重新 mount 后迁移才正常通过。这类问题在混合架构里非常常见和 CPU 型号、libvirt 版本不同造成的失败都属于“环境不一致”平时巡检根本测不出来一迁移就现形。4.2 高频故障与快速对照故障现象可能根因处理方向incompatible CPU源、目标 CPU 指令集不一致统一 CPU 型号使用 custom 公共模型local disks and cannot be migrated本地盘但未启用块迁移加上--block-migrateNo space left on device目标节点磁盘空间不足清理磁盘或扩展存储池迁移超过 20 分钟仍未完成预拷贝不收敛 / 脏页率过高开启自动收敛调整带宽限制Destination host is no longer available目标节点服务异常或网络不可达检查 libvirtd 与 qemu 版本状态迁移后实例 ping 不通二层网络隔离或安全组拦截检查 VLAN/VXLAN 连通与组策略迁移完成后主机时间被重置迁移请求实为冷迁移 / 冻结恢复异常回查操作命令和实例状态记录4.3 迁移失败后如何收拾残局迁移失败不一定代表实例挂了。多数情况下如果预拷贝阶段失败源节点上的 QEMU 进程还会继续运行实例不会中断。但如果切换阶段失败两端域的状态可能不一致。这时建议按下面顺序处理先确认实例当前实际运行在哪个节点登录源和目标节点分别执行virsh list。对比端口和进程。如果两端都有同名域立即冻结源节点域的调度避免双写磁盘。如果 nova 数据库里的实例状态还挂在Migrating可以手动复位nova reset-state --active server_uuid最后再决定是否重试迁移。重试前务必清理两端残留的临时文件尤其是/var/lib/nova/instances/instance_id下未完成的迁移目录。这里多提一句块迁移在复制数据期间源节点的磁盘写入流量并不会暂停。如果实例本身正在大量写盘那么失败后重试很可能会再次失败。稳妥的做法是让业务先减少写入或者做一个短暂维护窗口再迁移。5. 生产环境更稳的进阶姿势后拷贝、空间预算与例行演练5.1 预拷贝不收敛只能上“后拷贝”实时迁移最常见的“隐形失败”不是报错而是永远迁不完。预拷贝阶段反复复制脏页如果业务写入速度超过网络复制速度剩余脏页量永远不下降。nova 和 libvirt 提供了两种缓解策略自动收敛auto convergeQEMU 会主动降低虚拟 CPU 的执行速度让脏页产生速率降下来优先保证迁移完成。对性能敏感业务来说这相当于一次“主动降频”但比迁移失败强得多。后拷贝post-copy系统先快速把少量初始状态传到目标节点并启动实例后续按需从源节点拉取缺失的内存页。这个模式让迁移迅速结束但迁移期间源节点一旦故障内存状态可能丢失。生产环境建议谨慎开启至少保证源节点物理稳定性足够高。对应的 nova.conf 配置项[libvirt] live_migration_permit_auto_converge True live_migration_permit_post_copy True开启后nova 会根据具体情况自动选择合适策略。实测下来开启自动收敛就能解决 90% 以上的脏页不收敛问题后拷贝我一般只在跨机房低带宽场景才启用。5.2 带宽与时间的粗略预算有运维朋友问我一个 100 GB 磁盘的实例块迁移大概多久我习惯给一个非常粗略的估算公式迁移时长 ≈ 内存大小 × 脏页系数 ÷ 带宽 磁盘大小 ÷ 带宽举个例子32 GB 内存、100 GB 本地磁盘的实例走 1 Gbps 管理网络迁移。磁盘部分100 GB × 8 800 Gbit除以 1 Gbps 约等于 800 秒差不多 13 分钟。内存部分如果脏页率不高32 GB 内存可能只需要几十秒到两三分钟。合计大约 15 分钟且这是没有任何业务写入的理想情况。如果管理网实际带宽只有 500 Mbps这个时间直接翻倍。所以迁移大实例前先看一眼源节点sar -n DEV或nload确认网络空闲程度否则很容易影响同一网络上其他云主机的质量。5.3 例行迁移演练把“紧急救援”变成“常规动作”Live Migrate 最大的敌人不是技术复杂而是平时没演练。应急状态下手忙脚乱和日常操作时行云流水差距非常大。我的建议是每季度做一次例行演练选业务低峰期从集群里随机挑 10% 的云主机做一次“往返迁移”即从 compute1 迁到 compute2再迁回。记录每台实例的迁移时长、是否失败、失败原因。把迁移失败的“钉子户”登记下来专项处理——钉子户通常就是 CPU 模型不匹配、本地盘未配置共享存储、磁盘空间不足这类老问题。演练后更新维护文档把目标节点候选顺序、故障处理备注补齐。这样一来真到主机硬件告警、机房断电维护的时候你执行的不是“临场救灾”而是已经重复过无数次的“标准动作”。最后分享一个实战里最土但最有效的小习惯迁移期间不要只盯 OpenStack 面板同时在源节点和目标节点各开一个 SSH 窗口。源节点上盯nova-compute.log目标节点上跑virsh list确认域已经存活。Live Migrate 的完成标志不是控制台状态变绿而是目标节点上那个 QEMU 进程真正接管了虚拟机源节点上的进程彻底退出。记住这条底线无论平台版本怎么变你都不会被花哨的界面带偏。