压缩qcow2镜像带来的性能损失简单分析
本文拟对压缩qcow2镜像所带来的虚拟机性能损失进行简单分析
背景
生产中发现使用压缩镜像启动的虚拟机开机总是会慢一些。
qcow2镜像的压缩方式为:qemu-img convert -p -c -O qcow2 zero_disk.qcow2 compress_disk.qcow2
分析
qemu代码:https://download.qemu.org/qemu-9.2.0.tar.xz
主要看下使用qcow2后端的guest在读操作时后端操作qcow2文件的一个流程。
block/qcow2.c
后端driver指定读写回调:qcow2_co_preadv_part、qcow2_co_pwritev_part
BlockDriver bdrv_qcow2 = {.format_name = "qcow2",.instance_size = sizeof(BDRVQcow2State),.bdrv_probe = qcow2_probe,.bdrv_open = qcow2_open,.bdrv_close = qcow2_close,.bdrv_reopen_prepare = qcow2_reopen_prepare,.bdrv_reopen_commit = qcow2_reopen_commit,.bdrv_reopen_commit_post = qcow2_reopen_commit_post,.bdrv_reopen_abort = qcow2_reopen_abort,.bdrv_join_options = qcow2_join_options,.bdrv_child_perm = bdrv_default_perms,.bdrv_co_create_opts = qcow2_co_create_opts,.bdrv_co_create = qcow2_co_create,.bdrv_has_zero_init = qcow2_has_zero_init,.bdrv_co_block_status = qcow2_co_block_status,.bdrv_co_preadv_part = qcow2_co_preadv_part,.bdrv_co_pwritev_part = qcow2_co_pwritev_part,.bdrv_co_flush_to_os = qcow2_co_flush_to_os,.bdrv_co_pwrite_zeroes = qcow2_co_pwrite_zeroes,.bdrv_co_pdiscard = qcow2_co_pdiscard,.bdrv_co_copy_range_from = qcow2_co_copy_range_from,.bdrv_co_copy_range_to = qcow2_co_copy_range_to,.bdrv_co_truncate = qcow2_co_truncate,.bdrv_co_pwritev_compressed_part = qcow2_co_pwritev_compressed_part,.bdrv_make_empty = qcow2_make_empty,.bdrv_snapshot_create = qcow2_snapshot_create,.bdrv_snapshot_goto = qcow2_snapshot_goto,.bdrv_snapshot_delete = qcow2_snapshot_delete,.bdrv_snapshot_list = qcow2_snapshot_list,.bdrv_snapshot_load_tmp = qcow2_snapshot_load_tmp,.bdrv_measure = qcow2_measure,.bdrv_co_get_info = qcow2_co_get_info,.bdrv_get_specific_info = qcow2_get_specific_info,.bdrv_co_save_vmstate = qcow2_co_save_vmstate,.bdrv_co_load_vmstate = qcow2_co_load_vmstate,.is_format = true,.supports_backing = true,.bdrv_co_change_backing_file = qcow2_co_change_backing_file,.bdrv_refresh_limits = qcow2_refresh_limits,.bdrv_co_invalidate_cache = qcow2_co_invalidate_cache,.bdrv_inactivate = qcow2_inactivate,.create_opts = &qcow2_create_opts,.amend_opts = &qcow2_amend_opts,.strong_runtime_opts = qcow2_strong_runtime_opts,.mutable_opts = mutable_opts,.bdrv_co_check = qcow2_co_check,.bdrv_amend_options = qcow2_amend_options,.bdrv_co_amend = qcow2_co_amend,.bdrv_detach_aio_context = qcow2_detach_aio_context,.bdrv_attach_aio_context = qcow2_attach_aio_context,.bdrv_supports_persistent_dirty_bitmap =qcow2_supports_persistent_dirty_bitmap,.bdrv_co_can_store_new_dirty_bitmap = qcow2_co_can_store_new_dirty_bitmap,.bdrv_co_remove_persistent_dirty_bitmap =qcow2_co_remove_persistent_dirty_bitmap,
};
block/qcow2.c
读取时走读回调:qcow2_co_preadv_task_entry
static int coroutine_fn GRAPH_RDLOCK
qcow2_co_preadv_part(BlockDriverState *bs, int64_t offset, int64_t bytes,QEMUIOVector *qiov, size_t qiov_offset,BdrvRequestFlags flags)
{BDRVQcow2State *s = bs->opaque;int ret = 0;unsigned int cur_bytes; /* number of bytes in current iteration */uint64_t host_offset = 0;QCow2SubclusterType type;AioTaskPool *aio = NULL;while (bytes != 0 && aio_task_pool_status(aio) == 0) {/* prepare next request */cur_bytes = MIN(bytes, INT_MAX);if (s->crypto) {cur_bytes = MIN(cur_bytes,QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);}qemu_co_mutex_lock(&s->lock);ret = qcow2_get_host_offset(bs, offset, &cur_bytes,&host_offset, &type);qemu_co_mutex_unlock(&s->lock);if (ret < 0) {goto out;}if (type == QCOW2_SUBCLUSTER_ZERO_PLAIN ||type == QCOW2_SUBCLUSTER_ZERO_ALLOC ||(type == QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN && !bs->backing) ||(type == QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC && !bs->backing)){qemu_iovec_memset(qiov, qiov_offset, 0, cur_bytes);} else {if (!aio && cur_bytes != bytes) {aio = aio_task_pool_new(QCOW2_MAX_WORKERS);}ret = qcow2_add_task(bs, aio, qcow2_co_preadv_task_entry, type,host_offset, offset, cur_bytes,qiov, qiov_offset, NULL);if (ret < 0) {goto out;}}bytes -= cur_bytes;offset += cur_bytes;qiov_offset += cur_bytes;}out:if (aio) {aio_task_pool_wait_all(aio);if (ret == 0) {ret = aio_task_pool_status(aio);}g_free(aio);}return ret;
}
qcow2_co_preadv_task
/** This function can count as GRAPH_RDLOCK because qcow2_co_preadv_part() holds* the graph lock and keeps it until this coroutine has terminated.*/
static int coroutine_fn GRAPH_RDLOCK qcow2_co_preadv_task_entry(AioTask *task)
{Qcow2AioTask *t = container_of(task, Qcow2AioTask, task);assert(!t->l2meta);return qcow2_co_preadv_task(t->bs, t->subcluster_type,t->host_offset, t->offset, t->bytes,t->qiov, t->qiov_offset);
}
之后会判断当前读的cluster是什么类型的,如果是压缩的镜像,会走到QCOW2_SUBCLUSTER_COMPRESSED
static int coroutine_fn GRAPH_RDLOCK
qcow2_co_preadv_task(BlockDriverState *bs, QCow2SubclusterType subc_type,uint64_t host_offset, uint64_t offset, uint64_t bytes,QEMUIOVector *qiov, size_t qiov_offset)
{BDRVQcow2State *s = bs->opaque;switch (subc_type) {case QCOW2_SUBCLUSTER_ZERO_PLAIN:case QCOW2_SUBCLUSTER_ZERO_ALLOC:/* Both zero types are handled in qcow2_co_preadv_part */g_assert_not_reached();case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:case QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC:assert(bs->backing); /* otherwise handled in qcow2_co_preadv_part */BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);return bdrv_co_preadv_part(bs->backing, offset, bytes,qiov, qiov_offset, 0);case QCOW2_SUBCLUSTER_COMPRESSED:return qcow2_co_preadv_compressed(bs, host_offset,offset, bytes, qiov, qiov_offset);case QCOW2_SUBCLUSTER_NORMAL:if (bs->encrypted) {return qcow2_co_preadv_encrypted(bs, host_offset,offset, bytes, qiov, qiov_offset);}BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_AIO);return bdrv_co_preadv_part(s->data_file, host_offset,bytes, qiov, qiov_offset, 0);default:g_assert_not_reached();}g_assert_not_reached();
}
qcow2_co_preadv_compressed
static int coroutine_fn GRAPH_RDLOCK
qcow2_co_preadv_compressed(BlockDriverState *bs,uint64_t l2_entry,uint64_t offset,uint64_t bytes,QEMUIOVector *qiov,size_t qiov_offset)
{BDRVQcow2State *s = bs->opaque;int ret = 0, csize;uint64_t coffset;uint8_t *buf, *out_buf;int offset_in_cluster = offset_into_cluster(s, offset);qcow2_parse_compressed_l2_entry(bs, l2_entry, &coffset, &csize);buf = g_try_malloc(csize);if (!buf) {return -ENOMEM;}out_buf = qemu_blockalign(bs, s->cluster_size);BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_COMPRESSED);ret = bdrv_co_pread(bs->file, coffset, csize, buf, 0);if (ret < 0) {goto fail;}if (qcow2_co_decompress(bs, out_buf, s->cluster_size, buf, csize) < 0) {ret = -EIO;goto fail;}qemu_iovec_from_buf(qiov, qiov_offset, out_buf + offset_in_cluster, bytes);fail:qemu_vfree(out_buf);g_free(buf);return ret;
}
最后调用解压缩
/** qcow2_co_decompress()** Decompress some data (not more than @src_size bytes) to produce exactly* @dest_size bytes using the compression method defined by the image* compression type** @dest - destination buffer, @dest_size bytes* @src - source buffer, @src_size bytes** Returns: 0 on success* a negative error code on failure*/
ssize_t coroutine_fn
qcow2_co_decompress(BlockDriverState *bs, void *dest, size_t dest_size,const void *src, size_t src_size)
{BDRVQcow2State *s = bs->opaque;Qcow2CompressFunc fn;switch (s->compression_type) {case QCOW2_COMPRESSION_TYPE_ZLIB:fn = qcow2_zlib_decompress;break;#ifdef CONFIG_ZSTDcase QCOW2_COMPRESSION_TYPE_ZSTD:fn = qcow2_zstd_decompress;break;
#endifdefault:abort();}return qcow2_co_do_compress(bs, dest, dest_size, src, src_size, fn);
}
总结
从上面的流程分析可以看出,当qcow2被压缩后,guest每次需要读取原qcow2文件中的内容时,都会让host后端进行一次解压缩,这会消耗cpu
参考
https://github.com/qemu/qemu
相关文章:

压缩qcow2镜像带来的性能损失简单分析
本文拟对压缩qcow2镜像所带来的虚拟机性能损失进行简单分析 背景 生产中发现使用压缩镜像启动的虚拟机开机总是会慢一些。 qcow2镜像的压缩方式为:qemu-img convert -p -c -O qcow2 zero_disk.qcow2 compress_disk.qcow2 分析 qemu代码:https://down…...

Kali操作系统简单介绍
Kali是一个集成了各种安全工具的操作系统 安全问题的根源 1.分层思想:网络和软件开发的分层方法 2.安全问题:分层思想导致的片面认识和系统脆弱性 3.人的因素:安全问题的最终根源是人的错误 传统安全建设 1.防护型安全建设:关闭不…...

LabVIEW物联网开发实战:专栏总述
本专栏以LabVIEW为开发平台,讲解物联网通信组网原理与开发方法,覆盖RS232、TCP、MQTT、蓝牙、Wi-Fi、NB-IoT等协议。 结合实际案例,展示如何利用LabVIEW和常用模块实现物联网系统的快速开发与原型设计,助你从基础到实战࿰…...

高效处理PDF文件的终极工具:构建一个多功能PDF转换器
在日常工作中,处理PDF文件几乎是每个人都不可避免的任务。无论是从PDF中提取数据、合并多个PDF文件,还是处理文件中的敏感信息和图像,PDF文件的处理都可能成为繁琐且耗时的工作。如果你是数据分析师、工程师,或者从事文档管理的工…...

Y3编辑器教程6:触发器进阶案例
文章目录 一、地形制作1.1 地形制作流程1.2 关卡白盒1.3 场景美化1.4 优化场景 二、触发结构三、玩家指引(函数封装)3.1 项目拆解3.2 功能实现3.2.1 绘制UI界面3.2.2 UI的读取显示和刷新3.2.3 交互功能3.2.4 最终实现 四、NPC对话系统4.1 项目拆解4.2 UI…...

react Ant Design
一、通过项目模版创建一个react项目 set NPM_CONFIG_REGISTRYhttps://registry.npmmirror.com pnpm create vite antd-demo cd antd-demo pnpm install pnpm install antd --save 打开项目: 修改:welcome.tsx import React from react; import { Butto…...

汽车电子零部件(14):APA(自动泊车辅助)/RPA(远程遥控泊车)/AVP(自动代客泊车)
APA: Automated Parking Assist (APA) systems,自动泊车辅助系统,是自动驾驶汽车的一个关键功能。自动泊车辅助系统(APA)利用超声波雷达、视觉传感器和ADAS处理器来定位合适的停车位。它识别适合车辆大小的停车位,规划停车路线,并控制方向盘、变速箱和油门踏板以辅助停…...

Hot100刷题计划-Day2-滑动窗口、双指针、数组、链表、动态规划
LeetCode Hot 100 是最常被考察的题目集合,涵盖了面试中常见的算法和数据结构问题。刷 Hot100可以让你在有限的时间内集中精力解决最常考的问题。不仅要写出代码,还要理解问题的本质、优化解法和复杂度分析。 滑动窗口 438. 找到字符串中所有字母异位词…...

[react 3种方法] 获取ant组件ref用ts如何定义?
获取ant的轮播图组件, 我用ts如何定义? Strongly Type useRef with ElementRef | Total TypeScript import React, { ElementRef } from react; const lunboRef useRef<ElementRef<typeof Carousel>>(null); <Carousel autoplay ref{lunboRef}> 这样就…...

考前倒计时98天
2024年12月21日到2025年3月29日共有 98 天 一、计算机基础 思维分类特征强调学科代表理论思维(推理思维)推理和演绎推理数学实验思维(证实思维)观察和总结自然规律归纳物理学计算思维(构造思维)设计和构造…...

iterm2 focus时灰色蒙层出现的解决办法
问题描述: 当前我的iterm2版本是3.5.10,是我最近才更新的,然后就出现以下页面显示问题,如图所示: 我个人对终端、编辑器等使用存在洁癖,尤其是页面显示效果不满意更是不能忍受,之前找了很久没有…...

合并K个升序链表(最优解)
题目来源 23. 合并 K 个升序链表 - 力扣(LeetCode) 题目描述 给你一个链表数组,每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中,返回合并后的链表。 示例 1: 输入:lists [[1,4,5],[1,3,…...

kubernates实战
使用k8s来部署tomcat 1、创建一个部署,并指定镜像地址 kubectl create deployment tomcat6 --imagetomcat:6.0.53-jre82、查看部署pod状态 kubectl get pods # 获取default名称空间下的pods kubectl get pods --all-namespaces # 获取所有名称空间下的pods kubect…...

How to run Flutter on an Embedded Device
basysKom GmbH | How to run Flutter on an Embedded Device https://github.com/sony/flutter-embedded-linux/wiki/Building-Flutter-Engine-from-source flutter源码下载(最新)-CSDN博客 flutter_engine 交叉编译【自定义编译器(最新)】_flutter。engine 修改-CSDN博客 …...

airflow docker 安装
mkdir -p /root/airflow cd /root/airflow && mkdir -p ./dags ./logs ./plugins ./configcd /root/airflow/ wget https://airflow.apache.org/docs/apache-airflow/2.10.4/docker-compose.yaml nano docker-compose.yamlAIRFLOW__CORE__LOAD_EXAMPLES: false #初始化…...

浅析InnoDB引擎架构(已完结)
大家好,我是此林。 今天来介绍下InnoDB底层架构。 1. 磁盘架构 我们所有的数据库文件都保存在 /var/lib/mysql目录下。 由于我这边是docker部署的mysql,用如下命令查看mysql数据挂载。 docker inspect mysql-master 如下图,目前只有一个数…...

华为云计算HCIE笔记02
第二章:华为云Stack规划设计 交付总流程 准备工作:了解客户的基本现场,并且对客户的需求有基本的认知。 HLD方案BOQ报价设备采购和设备上架 2.安装部署流程 硬件架构设计 硬件设备选配 设备上架与初始化配置 准备相关资料(自动下载…...

鸿蒙项目云捐助第十讲鸿蒙App应用分类页面二级联动功能实现
鸿蒙项目云捐助第十讲鸿蒙App应用分类页面二级联动功能实现 在之前的教程中完成了分类页面的左右两侧的列表结构,如下图所示。 接下来需要实现左侧分类导航项的点击操作,可以友好的提示用户选择了哪一个文字分类导航项。 一、左侧文字分类导航的处理 …...

STM32低功耗模式结合看门狗
STM32低功耗模式结合看门狗 前言 最近做到一个需求要使用STM32的低功耗模式进行长时间待机应用,每隔十分钟发送一次数据到服务器上,当不发送的时候就处于低功耗模式。在经过一段时间的测试以后发现板子过三四天左右就没有数据上传服务器了,…...

数据迁移工具,用这8种!
前言 最近有些小伙伴问我,ETL数据迁移工具该用哪些。 ETL(是Extract-Transform-Load的缩写,即数据抽取、转换、装载的过程),对于企业应用来说,我们经常会遇到各种数据的处理、转换、迁移的场景。 今天特地给大家汇总了一些目前…...

Sapro编程软件
Sapro软件是由西门子建筑科技公司开发的一款编程软件,主要用于Climatix控制器的编程、调试及相关功能实现.以下是其具体介绍: • 功能强大:可进行HVAC控制编程,实现设备控制、HMI用户访问和设备集成等功能,满足复杂的…...

Python图注意力神经网络GAT与蛋白质相互作用数据模型构建、可视化及熵直方图分析...
全文链接:https://tecdat.cn/?p38617 本文聚焦于图注意力网络GAT在蛋白质 - 蛋白质相互作用数据集中的应用。首先介绍了研究背景与目的,阐述了相关概念如归纳设置与转导设置的差异。接着详细描述了数据加载与可视化的过程,包括代码实现与分析…...

2024年图像处理、多媒体技术与机器学习
重要信息 官网:www.ipmml.org 时间:2024年12月27-29日 地点:中国-大理 简介 2024年图像处理、多媒体技术与机器学习(CIPMT 2024)将于2024年12月27-29日于中国大理召开。将围绕图像处理与多媒体技术、机器学习等在…...

java 1.8+springboot文件上传+vue3+ts+antdv
1.参考 使用SpringBoot优雅的实现文件上传_51CTO博客_springboot 上传文件 2.postman测试 报错 :postman调用时body参数中没有file单词 Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part file is…...
【机器人】机械臂轨迹和转矩控制对比
动力学控制和轨迹跟踪控制是机器人控制中的两个概念,它们在目标、方法和应用上有所不同,但也有一定关联。以下是它们的区别和联系: 1. 动力学控制 动力学控制是基于机器人动力学模型的控制方法,目标是控制机器人关节力矩或力&…...

如何利用矩阵化简平面上的二次型曲线
二次型曲线的定义 在二维欧式平面上,一个二次型曲线都可以写成一个关于 x , y x,y x,y的二元二次多项式: F ( x , y ) a 11 x 2 2 a 12 x y a 22 y 2 2 a 1 x 2 a 2 y a 0 0 \begin{equation} F(x,y)a_{11}x^22a_{12}xya_{22}y^22a_1x2a_2ya_00…...

【系统移植】制作SD卡启动——将uboot烧写到SD卡
在开发板上启动Linux内核,一般有两种方法,一种是从EMMC启动,还有一种就是从SD卡启动,不断哪种启动方法,当开发板上电之后,首先运行的是uboot。 制作SD卡启动,首先要将uboot烧写到SD卡ÿ…...

sql server 数据库还原,和数据检查
右键数据库选择还原, 还原的备份文件必须选择在本地的文件(远程文件没有试过)还原数据库名字可以修改,然后file选择中有个2个目录data file 的目录 ,和log data 的目录都可以重新选择还原到的新的目录,不要…...

工业大数据分析算法实战-day12
文章目录 day12时序分解STL(季节性趋势分解法)奇异谱分析(SSA)经验模态分解(EMD) 时序分割ChangpointTreeSplitAutoplait有价值的辅助 时序再表征 day12 今天是第12天,昨天主要是针对信号处理算…...

Hive其一,简介、体系结构和内嵌模式、本地模式的安装
目录 一、Hive简介 二、体系结构 三、安装 1、内嵌模式 2、测试内嵌模式 3、本地模式--最常使用的模式 一、Hive简介 Hive 是一个框架,可以通过编写sql的方式,自动的编译为MR任务的一个工具。 在这个世界上,会写SQL的人远远大于会写ja…...