從存儲熱遷移流程了解 QEMU block layer

文章目錄

  • 存儲熱遷移流程
    • 總體流程
    • 代碼路徑
  • 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. # …