文章目录

  • 存储热迁移流程
    • 总体流程
    • 代码路径
  • QEMU Block layer
    • 架构简述
    • Block Job
      • 结构体设计
      • 状态转换
    • Mirror block job
      • 拓扑结构
      • 构建过程
      • 数据结构

存储热迁移流程

总体流程

Libvirt migrate 命令提供 copy-storage-all 选项支持存储热迁移,相应地,Libvirt 热迁移 API
(virDomainMigrateToURIX) 提供 VIR_MIGRATE_NON_SHARED_DISK flag 支持上层应用发起存储热迁移。下图为存储热迁移的简要流程图:
在这里插入图片描述
步骤如下:

  1. Libvirt 解析热迁移 API 的 flags 参数携带有 VIR_MIGRATE_NON_SHARED_DISK,首先通过 drive-mirror qmp 命令发起存储热迁移。
  2. QEMU 收到 drive-mirror 命令,内部按照 block job 的规程实现源端磁盘数据拷贝到目的端的工作。直到源端磁盘没有脏数据且 in flght IO 也没有,QEMU 发布一个 BLOCK_JOB_READY 事件,表示自己已经完成磁盘的数据迁移动作,随时可以接受终止命令。 在此之前,QEMU 会将源端磁盘的增量 IO 同步到目的端。
  3. Libvirt 在发起存储热迁移后等待 QEMU 的 BLOCK_JOB_READY 事件,收到该事件后发起内存热迁移。可以看到,内存热迁移是在 block job 处于 ready 状态后发起的。之后 Libvirt 监听 switchover 事件等待热迁移完成。
  4. QEMU 收到 migrate 命令后,发起内存热迁移。热迁移满足进入最后一轮条件后,发布 migration pre-switchover 事件。
  5. Libvirt 收到 switchover 事件后,首先是发送 bllock-job-cancel 命令终止 drive-mirror 的 block job,等待 QEMU 的 BLOCK_JOB_COMPLETED 事件。
  6. QEMU 收到 bllock-job-cancel 命令后,将新产生的增量 IO 和 in flight IO 同步到目的磁盘,发布终止 BLOCK_JOB_COMPLETED 标志 drive-mirror 完成。
  7. Libvirt 收到 BLOCK_JOB_COMPLETED 事件后,发送 migrate-continue 命令通知 QEMU 进行 switchover。等待 QEMU 发布 migration completed 事件。
  8. QEMU 收到 migrate-continue 命令,发起热迁移 switchover,完成后发布迁移完成事件。
  9. Libvirt 收到完成事件,迁移结束。
    热迁移的 switchover 的简要逻辑参考下图:
    在这里插入图片描述

代码路径

  • Libvirt 关键路径与逻辑
client:
cmdMigrateif (vshCommandOptBool(cmd, "copy-storage-all"))flags |= VIR_MIGRATE_NON_SHARED_DISK;virDomainMigrateToURI3virDomainMigrateUnmanagedParams -> virDomainMigrateUnmanagedProto3
rpc:
qemuDomainMigratePerform3qemuMigrationSrcPerformqemuMigrationSrcPerformPhaseqemuMigrationSrcPerformNativeqemuMigrationSrcRun
关键函数:
qemuMigrationSrcRunif (flags & VIR_MIGRATE_NON_SHARED_DISK) {migrate_flags |= QEMU_MONITOR_MIGRATE_NON_SHARED_DISK;cookieFlags |= QEMU_MIGRATION_COOKIE_NBD;}if (migrate_flags & (QEMU_MONITOR_MIGRATE_NON_SHARED_DISK |QEMU_MONITOR_MIGRATE_NON_SHARED_INC)) {/* 调用 drive-mirror 发起存储热迁移,等待 QEMU BLOCK_JOB_READY 事件 */qemuMigrationSrcNBDStorageCopy...}/* 调用 migrate 发起内存热迁移 */qemuMonitorMigrateToFd/* 等待 QEMU migrate pre-switchover 事件 */qemuMigrationSrcWaitForCompletion/* 内存热迁移进入 switchover 前夕,终止存储热迁移 */if (mig->nbd) {qemuMigrationSrcNBDCopyCancel}/* 调用 migrate-continue 触发热迁移 switchover */qemuMigrationSrcContinue/* 等待 QEMU migrate completed 事件 */qemuMigrationSrcWaitForCompletion
  • QEMU 关键路径与逻辑
qmp_drive_mirrorbs = qmp_get_root_bsaio_context = bdrv_get_aio_context(bs)target_bs = bdrv_openbdrv_try_change_aio_context(target_bs, aio_context, NULL, errp)blockdev_mirror_commonmirror_start/* 传入 mirror_job_driver,发起 mirror job */mirror_start_job
job 创建关键函数:
mirror_start_job/* 实例化 mirror filter driver,生成一个 BlockDriverState */mirror_top_bs = bdrv_new_open_driver(&bdrv_mirror_top, filter_node_name,BDRV_O_RDWR, errp)/* 清空源端磁盘上处于队列中的待落盘 IO,等待其结束 */bdrv_drained_begin(bs)/* 将 mirror filter 加到源磁盘的 root bs 之上,接管源磁盘的 IO 回调处理 */ret = bdrv_append(mirror_top_bs, bs, errp)/* 允许源端磁盘上有 IO 排队 */bdrv_drained_end(bs)/* 创建一个 job 并建立一个基于 job block 树:/* 将 mirror filter 作为树的第一个叶子节点,命名为 "main node" */block_job_create/* block job 已跟踪 mirror filter,解引用 */bdrv_unref(mirror_top_bs)/* 新建一个目的端磁盘的 BlockBackend */s->target = blk_new/* 将新建的 BlockBackend 的 root bs 指向目的磁盘 bs */blk_insert_bs(s->target, target, errp)/* 在 job block 树上添加第二个叶子节点,命令为 "source" */ret = block_job_add_bdrv(&s->common, "source", bs, 0,BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE |BLK_PERM_CONSISTENT_READ,errp)/* 在 job block 树上添加第二个叶子节点,命令为 "target" */block_job_add_bdrv(&s->common, "target", target, 0, BLK_PERM_ALL,&error_abort)/* 调用 job 的 run 方法: mirror_run */job_start

QEMU Block layer

架构简述

  • Block layer 层次
    Block layer 介于响应 Guest IO 的 block device 之下、主机存储介质之上的一层 QEMU 组件,它负责处理 Guest IO 并最终将 IO 数据按照预期存储到主机存储介质上。如下图所示:
    在这里插入图片描述
    直接将 Guest IO 透传到主机存储介质不行吗?QEMU 为什么要引入 Block layer 软件层增加处理逻辑?
    前者的答案是可以;后者的答案是在保证修改影响最小的前提下引入对高级存储特性的支持,比如磁盘级别的限速、加密、镜像、备份等。 存储的特性在 Block layer 内部提供的基础软件框架上实现并对外(Guest、host) 保持行为不变。
  • Block layer 功能
    基于 Block layer 的层次分析,我们可以推断 Block layer 需要具备以下基本功能:
  1. 接收 Guest IO 数据流
  2. 定义 Guest IO 数据流在 Block layerr 的行为
  3. 将 Guest IO 数据流写入主机存储介质或从中读出
    基于当前 QEMU 的 Block layer 实现以及上面的推断,Block layer 的具体功能包括:
  4. 操纵 Guest IO 数据流实现存储特性,比如:加密、限速和备份等
  5. 翻译镜像格式,即按照约定的镜像格式将 IO 数据与 metadata 数据写入主机存储介质或从中读出,这里的镜像格式包括 qcow2、raw 等。
  6. 将 Block layer 层加工后的 IO 数据按照访问协议写入主机存储介质或从中读出,这里的协议包括 nbd、iscsi、file 等。
  • Block layer tree
    基于对 Block layer 层的功能分析,QEMU 将 Blocker layer 软件基础框架抽象为树,其中树的根离 Guest 最近,树的叶子节点离 Host 最近,每个层次中节点角色不同,实现的功能也不同,如下:
    在这里插入图片描述

Block Job

结构体设计

QEMU 设计了 Job 结构体,job 生命周期各阶段通过状态来描述, job 有如下状态,参考官方文档:

  1. undefined – Erroneous, default state. Should not ever be visible.
  2. created – The job has been created, but not yet started.
  3. running – The job is currently running.
  4. paused – The job is running, but paused. The pause may be requested by either the QMP user or by internal processes.
  5. ready – The job is running, but is ready for the user to signal completion. This is used for long-running jobs like mirror that are designed to run indefinitely.
  6. standby – The job is ready, but paused. This is nearly identical to paused. The job may return to ready or otherwise be canceled.
  7. waiting – The job is waiting for other jobs in the transaction to converge to the waiting state. This status will likely not be visible for the last job in a transaction.
  8. pending – The job has finished its work, but has finalization steps that it needs to make prior to completing. These changes will require manual intervention via job-finalize if auto-finalize was set to false. These pending changes may still fail.
  9. aborting – The job is in the process of being aborted, and will finish with an error. The job will afterwards report that it is concluded. This status may not be visible to the management process.
  10. concluded – The job has finished all work. If auto-dismiss was set to false, the job will remain in this state until it is dismissed via job-dismiss.
  11. null – The job is in the process of being dismantled. This state should not ever be visible externally.
  • QEMU 设计了 JobDriver 结构体,Job 通过执行 JobDriver 中的方法将 Job 从一个状态驱动到另一个状态。
  • BlockJob 继承 Job 结构体,BlockJobDriver 继承 JobDriver,用于实现块设备的 Job。QEMU BlockJob 和 BlockJobDriver 结构体为基础,实现了块设备的高级特性,比如 mirror、duplicate 等。
  • Job、JobDriver、BlockJob、BlockJobDriver 4 个结构体的定义和关系如下:
    在这里插入图片描述

状态转换

  1. Job 的通用状态转换如下图,其中 event 表示 QEMU 内部的状态转换:
    在这里插入图片描述
    有几个点需要特别解释:
  • READY 状态对于 drive-mirror 来说是一种完成的状态,drive-mirror job 进入 READY 状态时会发送同时发送 BLOCK_JOB_READY 事件。READY 状态的 drive-mirror job 可以随时可以接收 block-job-cancel 命令,这里的 block-job-cancel 命令并非字面意义上的取消任务,而是结束。QEMU 会在 block-job-cancel 命令的处理逻辑中发布 BLOCK_JOB_COMPLETED 事件,表示 drive-mirror job 结束。
  • job-pause 停止任务时,处于 RUNNING 状态的任务会变为 PAUSED;处于 READY 状态的任务会变成 STANDBY。
  • job-finalize 的作用是让处于工作完成(PENDING)状态的 job 通过用户命令进入 QEMU 定义上的任务完成,设计这样一个接口可以方便上层应用在 QEMU job 进入完成状态之前可以执行一些准备命令。如果应用没有需要,可以在发起 block job 时设置 auto-finalize 为 true 让 QEMU 跳过等待用户下发 job-finalize 的步骤,直接进入 QEMU 定义的完成状态(CONCLUDED)。
  • job-dismiss 的作用是清理 QEMU 内部维护的 Job 数据结构,没有其它实质动作,job-dismiss 下发后 job 将不再能够通过 qmp block-job-query 查询到。
  1. Block job 状态转换如下图所示,以 drive-mirror 功能为例:
    在这里插入图片描述

Mirror block job

拓扑结构

在这里插入图片描述
处于 mirror 状态的 Block layer tree 拓扑如上:

  • MirrorBlockJOb 结构体继承自 BlockJob
  • MirrorBlockJOb 包含源、目的两端的 BlockBackend
  • 目的端 BlockBackend 通过 MirrorBlockJOb 结构体的 target 的跟踪
  • 源端 BlockBackend 通过 mirror node 间接引用 —— mirror node 作为 filter node 被插入到源端 BlockBackend 和 root bs 之间,代替 root bs 作为源端 BlockBackend 的子节点,Mirror node 子节点指向先前的 root bs

构建过程

drive-mirror 实现中涉及到的 mirror block layer tree 的构建逻辑分四个步骤,如下:

  1. 初始阶段,打开源端和目的端磁盘的 bs (BlockDriverState)
  • 根据参数中源磁盘的 node-name 打开源磁盘
BlockDriverState *bs = qmp_get_root_bs(arg->device, errp) 
  • 获取包含源磁盘 bs 的 IO 回调上下文
AioContext *aio_context = bdrv_get_aio_context(bs)
  • 根据参数中目标磁盘的 node-name 打开目标磁盘
target_bs = bdrv_open(arg->target, NULL, options, flags, errp)
  • 将源磁盘的 IO 回调设置到目标磁盘上
bdrv_try_change_aio_context(target_bs, aio_context, NULL, errp)

在这里插入图片描述

  1. 插入 mirror filter node 到源磁盘的 block layer tree
  • 打开一个基于 bdrv_mirror_top BlockDriver 驱动的 bs
BlockDriverState *mirror_top_bs = bdrv_new_open_driver(&bdrv_mirror_top, filter_node_name,BDRV_O_RDWR, errp)
  • 将 mirror filter node 插入到源磁盘 BlockBackend 与 bs 之间,取代 bs 作为 BlockBackend 的子节点
bdrv_append(mirror_top_bs, bs, errp)
  • 创建 BlockJob
MirrorBlockJob *s = block_job_create(job_id, driver, NULL, mirror_top_bs,BLK_PERM_CONSISTENT_READ,BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |BLK_PERM_WRITE, speed,creation_flags, cb, opaque, errp)
  • BlockJob 维护了 mirror filter node,因此删除 qmp_drive_mirror 函数的引用
bdrv_unref(mirror_top_bs)

在这里插入图片描述

  1. 创建目标磁盘的 BlockBackend
  • 基于源端磁盘的 IO 上下文新建一个 BlockBackend
s->target = blk_new(s->common.job.aio_context, target_perms, target_shared_perms)
  • 将新建的 BlockBackend 指向目标磁盘
blk_insert_bs(s->target, target, errp)

在这里插入图片描述

  1. BlockJob 管理源端磁盘和目标端磁盘
  • 将源端磁盘添加到 BlockJob 维护的 tree
block_job_add_bdrv(&s->common, "source", bs, 0,BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE |BLK_PERM_CONSISTENT_READ,errp)
  • 将目标端磁盘添加到 BlockJob 维护的 tree
block_job_add_bdrv(&s->common, "target", target, 0, BLK_PERM_ALL, &error_abort)

在这里插入图片描述

数据结构

我们通过分析一个正在 drive-mirror 虚机的 QEMU 进程 core 文件进一步了解 Block layer 相关数据结构。

  • 查询当前虚机正在运行的所有 Job
    在这里插入图片描述

  • 查询第一个 BlockJob 维护所有的 BdrvChild 节点
    在这里插入图片描述

  • 在源磁盘 Block layer 中查询 mirror filter node 的叶子节点
    在这里插入图片描述

可以看到,mirror filter node 下一级 node 属性为 child_of_bds,而 BlockJob 维护的的 node 属性为 child_job,BdrvChild klass 的不同决定了做添加和删除节点操作时调用的回调函数(attach、detach、drain)不同

  • 查看源端磁盘完整的 Block layer node
    在这里插入图片描述

可以看到 mirror node 的 backing 指向了 format node,format node 的 file 指向了 protocol node

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/914691.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/914691.shtml
英文地址,请注明出处:http://en.pswp.cn/news/914691.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【设计模式】命令模式 (动作(Action)模式或事务(Transaction)模式)宏命令

命令模式(Command Pattern)详解一、命令模式简介 命令模式(Command Pattern) 是一种 行为型设计模式(对象行为型模式),它将一个请求封装为一个对象,从而使你可以用不同的请求对客户进…

HTML5智能排班日历:动态排班一目了然

这个日历将具备以下功能: 显示一个标准的月度日历视图。可以自由切换上一个月和下一个月。在日历的每一天自动显示当天值班的人员。您可以很方便地在文件中修改值班人员列表和排班的起始日期。包括:动态生成日历网格处理月份切换根据排班规则计算并显示每天的值班人员<!DO…

深度剖析C++生态系统:一门老牌语言如何在开源浪潮中焕发新生?

&#x1f4dd;个人主页&#x1f339;&#xff1a;慌ZHANG-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 一、前言&#xff1a;C的“长寿秘诀”是什么&#xff1f; C 诞生已超过 40 年。它经历了桌面应用、互联网爆发、移动时代&#xff0c;再…

60个功能OfficeBox 万彩办公大师:PDF 格式转换 OCR识别免费无广告

各位办公小能手们&#xff01;今天给大家介绍个超厉害的免费办公工具套装——OfficeBox万彩办公大师&#xff0c;是广州万彩科技整出来的。软件下载地址安装包 它里面有60多个没广告的绿色组件&#xff0c;简直像个百宝箱&#xff01;涵盖了PDF处理、格式转换、OCR识别、屏幕录…

拥抱主权AI:OpenCSG驱动智能体运营,共筑新加坡智能高地

2025年7月11日&#xff0c;由Linux基金会AI & Data、TikTok及LF Edge联合主办的 【LF AI & Data Day Singapore 2025】 在新加坡TikTok总部盛大启幕。本次大会以“Agent for SWE”为核心议题&#xff0c;汇聚全球顶尖AI开发者、企业领袖及开源社区先锋。作为国家主权AI…

单片机学习笔记.根据芯片数据手册写驱动程序(这里使用的是普中开发版,以DS1302为例)

硬件原理图部分&#xff1a; VCC2:是主电源 VCC1&#xff1a;是备用电源&#xff0c;此处没有使用VCC1 查芯片数据手册的网站&#xff1a; ALLDATASHEETCN.COM - 电子元件和半导体及其他半导体的数据表搜索网站。https://www.alldatasheetcn.com/ 1.由原理图可知对应引脚&…

Capture One24下载与保姆级安装教程!

软件下载 软件名称&#xff1a;Capture One24 软件语言&#xff1a;简体中文 软件大小&#xff1a;1.06G 系统要求&#xff1a;Windows7或更高&#xff0c;32/64位操作系统 硬件要求&#xff1a;CPU2.5GHz&#xff0c;RAM4G或更高 下载通道丨下载&#xff1a;https://too…

微信小程序(数据库)

const dbwx.cloud.database()//连接数据库db.collection("test").doc("b69f67c0626fac9000e123fc1ff07a42&#xff08;为要查询数据的id&#xff09;").get({success:res>{console.log(res)}})或getData(){db.collection("test").doc("&…

Apache CXF 漏洞曝光:存在拒绝服务与数据泄露双重风险

Apache软件基金会近日披露了一个影响多个Apache CXF版本的安全漏洞&#xff08;CVE-2025-48795&#xff09;。Apache CXF是开发者广泛使用的开源Web服务框架&#xff0c;用于构建基于SOAP和REST的应用程序。漏洞双重威胁该漏洞具有双重危害性&#xff1a;一方面可能通过内存耗尽…

Android 应用自动更新:从理论到实战的硬核指南

目录 1. 自动更新的核心逻辑:为什么它对用户体验至关重要? 自动更新的本质 为什么它如此重要? 2. 版本检测:如何优雅地发现“新大陆”? 设计版本检测的逻辑 实现版本检测的 API 请求 用户体验优化 3. 下载新版本:稳妥地获取安装包 下载的两种方式 注意事项 用户…

每日面试题05:ArrayList和LinkedList的底层原理

ArrayList与LinkedList深度解析&#xff1a;从底层原理到实战选择在Java的List接口实现中&#xff0c;ArrayList和LinkedList是最常用的两种选择。面试中“它们的区别”几乎是必问题&#xff0c;但仅仅停留在“数组vs链表”的层面显然不够。本文将从​​底层数据结构、内存布局…

python的慈善捐赠平台管理信息系统

前端开发框架:vue.js 数据库 mysql 版本不限 后端语言框架支持&#xff1a; 1 java(SSM/springboot)-idea/eclipse 2.NodejsVue.js -vscode 3.python(flask/django)–pycharm/vscode 4.php(thinkphp/laravel)-hbuilderx 数据库工具&#xff1a;Navicat/SQLyog等都可以 摘要 本文…

三十二、【核心功能改造】数据驱动:重构仪表盘与关键指标可视化

三十二、【核心功能改造】数据驱动:重构仪表盘与关键指标可视化 前言准备工作第一部分:后端实现 - 统计 API1. 创建 `DashboardStatsView`2. 注册统计 API 路由3. 后端初步测试第二部分:前端实现 - 重构仪表盘页面1. 创建 `api/dashboard.ts` API 服务2. 重构 `HomeView.vue…

神经网络与深度学习Python入门

一、神经网络基础 1. 神经元模型 在神经网络中&#xff0c;最基本的单元是神经元&#xff08;Neuron&#xff09;&#xff0c;也称为节点或单元。它模拟了生物神经系统中的神经元行为。一个典型的神经元模型包含多个输入&#xff08;x1,x2,…,xnx_1, x_2, \ldots, x_nx1​,x2​…

Android System WebView:Android生态的核心组件

在Android生态系统中&#xff0c;Android System WebView&#xff08;简称WebView&#xff09;扮演着至关重要的角色。它是Chrome浏览器的内核&#xff0c;为Android设备提供了强大的网页浏览和Web内容展示功能。无论是日常浏览网页、使用基于Web的应用程序&#xff0c;还是进行…

Element Plus和Ant Design Vue深度对比分析与选型指南

在 Vue3生态中&#xff0c;Element Plus和Ant Design Vue&#xff08;以下简称 AntD Vue&#xff09;是两款最主流的 UI 组件库。它们分别脱胎于 Element UI&#xff08;Vue 2 版本&#xff09;和 Ant Design&#xff08;React 生态&#xff09;&#xff0c;经过多年迭代已成为…

AJAX 开发中的注意点

关键词&#xff1a;AJAX、异步请求、前端开发、跨域、错误处理、安全、性能优化 ✅ 引言 在现代 Web 应用中&#xff0c;AJAX 是实现前后端数据交互的重要手段。然而&#xff0c;在实际开发过程中&#xff0c;如果不注意一些常见问题&#xff0c;可能会导致应用出现安全性漏洞…

类之间的纵向关系——继承

继承定义&#xff1a;被继承的类叫做基类&#xff08;父类&#xff09;&#xff0c;继承的类叫派生类&#xff08;子类&#xff09;&#xff0c;在派生类类名后面加&#xff1a; 继承方式 基类class CFather{}; class CSon:public CFather{};父类(基类)与子类(派生类)之间的关系…

bytetrack漏检补齐

bytetrack漏检补齐1.人流慢速运动&#xff0c;跟踪效果比较好&#xff0c;偶尔有漏检&#xff0c;跟踪可以自动补齐。2.快速运动&#xff0c;频繁遮挡&#xff0c;效果可能不好*如果漏检&#xff0c;倒着跟踪&#xff0c;把丢失的检测框拷贝出来&#xff0c;保留进行跟踪。有时…

安装Keycloak并启动服务(macOS)

前提&#xff1a;电脑已经安装Java 17 1、下载Keycloak 2、下载完后解压缩&#xff0c;使用文本编辑器修改配置文件&#xff08;keycloak/conf/keycloak.conf&#xff09; # Basic settings for running in production. Change accordingly before deploying the server. # …