733 字
4 分钟
未命名
你说得非常对!我之前的分析不够准确。热迁移确实不是立即停机的,而是有一个预拷贝 + 停机拷贝的两阶段过程。让我重新分析正确的调用时机:
正确的热迁移停机时机
1. 热迁移的两个阶段
阶段 1:预拷贝阶段(VM 继续运行)
// migration/migration.c:3487-3495
while (migration_is_active()) {
if (urgent || !migration_rate_exceeded(s->to_dst_file)) {
// 🔄 持续拷贝脏页,VM继续运行
MigIterateState iter_state = migration_iteration_run(s);
if (iter_state == MIG_ITERATE_BREAK) {
break; // 脏内存足够少了,进入停机阶段
}
}
}
阶段 2:停机拷贝阶段(VM 停止)
// 只有当脏内存收敛到阈值以下时,才进入completion阶段
migration_completion(s);
2. 脏内存收敛判断逻辑
// migration/migration.c:3235-3238
if ((!pending_size || pending_size < s->threshold_size) && can_switchover) {
trace_migration_thread_low_pending(pending_size);
// 关键:只有脏内存少于阈值时,才调用completion
migration_completion(s);
return MIG_ITERATE_BREAK;
}
关键参数:
pending_size
:待传输的脏页大小s->threshold_size
:停机阈值(通常是 64 KB)can_switchover
:是否可以切换(没有阻塞操作)
3. 真正的停机时刻
// migration/migration.c:2806-2813
static void migration_completion(MigrationState *s)
{
if (s->state == MIGRATION_STATUS_ACTIVE) {
// 🎯 这里才是真正的停机调用
ret = migration_completion_precopy(s, ¤t_active_state);
}
}
↓
// migration/migration.c:2731
static int migration_completion_precopy(MigrationState *s, ...)
{
// 🔥 这里才调用VM停止
ret = migration_stop_vm(s, RUN_STATE_FINISH_MIGRATE);
}
4. 完整的时序流程
sequenceDiagram
participant User as 用户
participant Migration as 迁移线程
participant VM as 虚拟机
participant ITS as ITS设备
User->>Migration: migrate命令
Note over Migration: 启动迁移线程,VM继续运行
loop 预拷贝阶段
Migration->>Migration: migration_iteration_run()
Migration->>Migration: 检查pending_size
alt pending_size > threshold_size
Migration->>Migration: 继续拷贝脏页
Note over VM: VM持续运行,产生新脏页
else pending_size < threshold_size
Migration->>Migration: 脏内存收敛,准备停机
end
end
Migration->>Migration: migration_completion()
Migration->>VM: migration_stop_vm()
Note over VM: VM停止运行
VM->>ITS: vm_change_state_handler(running=false)
ITS->>ITS: 保存ITS表到客户机内存
Note over Migration: 传输剩余脏页和设备状态
Migration->>Migration: 迁移完成
5. 关键时间点
- T 0:用户发起迁移,VM 继续运行
- T 1-Tn:预拷贝阶段,反复传输脏页,VM 持续运行
- Tn+1:脏内存收敛到阈值以下
- Tn+2:VM 停机 ←
vm_change_state_handler
在这里被调用 - Tn+3:传输最后的脏页和设备状态
- Tn+4:迁移完成
6. ITS 表保存的准确时机
// 只有在脏内存收敛后的停机阶段,才会触发ITS表保存
migration_iteration_run()
→ pending_size < threshold_size
→ migration_completion()
→ migration_completion_precopy()
→ migration_stop_vm()
→ vm_stop_force_state()
→ do_vm_stop()
→ vm_state_notify(false, RUN_STATE_FINISH_MIGRATE)
→ vm_change_state_handler() // ITS表保存
所以你的理解完全正确!VM 并不是立即停机的,而是等待脏内存收敛到足够小的程度(通常几十 KB),才会进入停机阶段。只有在这个停机阶段,vm_change_state_handler
才会被调用,ITS 表才会被保存到客户机内存中。
这种设计确保了:
- 最小化停机时间:只在脏内存很少时才停机
- 数据一致性:在 VM 停止状态下保存 ITS 表,避免并发修改
- 迁移效率:大部分数据在 VM 运行时就已经传输完成