Skip to the content.

Virtio Balloon Debug

非常好,那么如何可以自动的利用这个东西呢?

static bool get_free_page_hints(VirtIOBalloon *dev)
{
    /* 等待 VM 恢复运行 */
    while (dev->block_iothread) {
        qemu_cond_wait(&dev->free_page_cond, &dev->free_page_lock);
    }

iothread 中的调用路线为:

这也是一个异步的事件了: virtio_balloon_free_page_hint_notify : 这就是 callback

iothread 是一定必须使用的吗?

看上去的确是如此的? 是必须要 balloon 的才可以的

        s->free_page_bh = aio_bh_new_guarded(iothread_get_aio_context(s->iothread),
                                             virtio_ballloon_get_free_page_hints, s,
                                             &dev->mem_reentrancy_guard);

第三个问题,如果过程中,balloon 发生了变化,如何办?

还需要梳理一下在热迁移中的位置才可以: migration_bitmap_sync_precopy

是划分为多个阶段的啊

那些 thread 可能会使用 bitmap_mutex 这个东西?

通知 guest 发送,需要等 guest 返回吗?

还是没懂,为什么需要在 sync 的时候不可以

理解一下这个东西

因为 memory_region_clear_dirty_bitmap() 清掉的是“当前已经记录的 dirty 状态”,不是永久禁止跟踪。 如果 guest 之后又写这个页,dirty logging 会重新把它记脏,下一轮 migration_bitmap_sync() 还能重新发现它。 所以 free-page hint 本质上是在说:

“截至现在,这页可视为 free,不值得迁移;如果以后又被用到,再重新记脏、再迁移。”

告诉你可以跳过,但是 clear_bmap 没有消失的。

migration 的通知机制就是为了

各通知目前的用途:

 Reason                发送位置                              virtio-balloon 行为
━━━━━━━━━━━━━━━━━━━━  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 SETUP                 migration setup                       无操作
────────────────────  ────────────────────────────────────  ──────────────────────────────────
 BEFORE_BITMAP_SYNC    同步脏页 bitmap 前                    停止 guest 上报 free page
────────────────────  ────────────────────────────────────  ──────────────────────────────────
 AFTER_BITMAP_SYNC     同步完成后                            重新启动 free-page hint
────────────────────  ────────────────────────────────────  ──────────────────────────────────
 COMPLETE              precopy 切换完成                      无操作
────────────────────  ────────────────────────────────────  ──────────────────────────────────
 CLEANUP               migration 成功、失败或取消后的清理    通知 guest free-page hint 已结束
────────────────────  ────────────────────────────────────  ──────────────────────────────────
 MAX                   不发送                                仅作为枚举上界

核心目的,是防止 guest 异步上报空闲页和 migration dirty bitmap 同步产生竞态:

停止 free-page hint
        ↓
同步 dirty bitmap
        ↓
重新开启 free-page hint

另外,如果允许 postcopy,virtio-balloon 回调会直接跳过这个优化, 因为清掉 dirty bitmap 中的空闲页可能导致目标端 page fault 永久等待。 也就是说,这套 notifier 名字虽然很通用,但当前基本就是为 virtio-balloon free-page-hint 服务的; SETUP 和 COMPLETE 目前甚至没有 实际消费者行为。

基本调用流程

这里的 sync 指的是 migration_bitmap_sync_precopy() 里的 dirty log 同步,也就是把底层脏页记录拉进 QEMU 的迁移位图 rb->bmap 也就是 migration/ram.c:migration_bitmap_sync_precopy()

  1. PRECOPY_NOTIFY_BEFORE_BITMAP_SYNC
  2. migration_bitmap_sync(…)
  3. PRECOPY_NOTIFY_AFTER_BITMAP_SYNC

遇到的问题和解决办法

可以。假设有一个 guest 物理页 P,migration bitmap 中:

考虑没有 notifier 协调时的简化时序:

Guest/balloon线程          KVM dirty log          Migration线程
      │                         │                       │
1. P 当前空闲
2. 异步上报“P 是空闲页”
      │
3. P 被重新分配并写入 ────────► P = dirty
      │
      │                                      4. 同步 dirty bitmap
      │                                         migration bitmap[P] = 1
      │
5. 迟到的 free-page hint 被处理
   migration bitmap[P] = 0
      │
      │                                      6. 看到 P=0,不发送 P

问题在第 5 步:这个 hint 描述的是“此前观察到 P 空闲”,但处理时 dirty bitmap 已经同步了更新的数据。 旧 hint 把刚同步出来的 dirty bit 又清掉,目标虚拟机就可能拿不到 P 的最新内容。

反方向也可能产生性能问题:

free-page hint:P 已空闲,清成 0
                  ↓
dirty bitmap 同步又合入旧的 dirty 记录,把 P 设成 1
                  ↓
本来可以跳过的空闲页仍然被发送

所以 QEMU 把 free-page hint 严格放在两次 bitmap sync 之间:

同步 dirty bitmap
        ↓
AFTER_BITMAP_SYNC (注意,这里是 after ,开启了 dirty 跟踪了)

启动 free-page hint
        ↓
guest 上报空闲页,QEMU 将会跳过这些页面 *
        ↓
BEFORE_BITMAP_SYNC
停止上报,并等 hint 处理线程退出
        ↓
下一次同步 dirty bitmap

对 * 标记的位置的分析:

  1. AFTER_BITMAP_SYNC 后是开机了 dirty 跟踪的
  2. 如果 free-page hint 报告了页面可以跳过,但是依旧在页面中 dirty write 了,那么 dirty 会记录到 KVM dirty bit 中,会在下一轮还是会记录下来

这样下一次同步开始以后,就不会有“上一轮迟到的 hint”再次清除同步结果。对应代码是:

这里不仅仅是 C 语言层面的数据竞争——bitmap_mutex 已经避免了同时修改数据结构; 更关键的是跨 guest、KVM dirty log 和 migration 线程的“事件先后顺序”竞争。 notifier 建立的是语义上的同步边界。

其他算法的考虑

1.对于 swap out 到共享存储页面也可以使用此方法

也就是如果检测到页面在 swap 中,那么就跳过

热迁移的速度问题

这个热迁移的速度明显不对,这里的时间是显示 Time 为 3053 ms ,但是 Throughput 为 1342.70 问题是,这个虚拟机占用了 20G 的内存的

(qemu) info migrate
Status: 		completed
Time (ms): 		total=3053, setup=3, down=27
RAM info:
  Throughput (Mbps): 	1342.70
  Sizes: 		pagesize=4 KiB, total=24 GiB
  Transfers: 		transferred=488 MiB, remain=0 B
    Channels: 		precopy=480 B, multifd=484 MiB, postcopy=0 B
    Page Types: 	normal=643781, zero=4956544
  Page Rates (pps): 	transfer=2166058
  Others: 		dirty_syncs=3

我估计是使用了 migration hint 功能,所以大部分都跳过了

本站所有文章转发 CSDN 将按侵权追究法律责任,其它情况随意。