压缩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

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

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

相关文章

数据结构之栈,队列,树

目录 一.栈 1.栈的概念及结构 2.栈的实现 3.实现讲解 1.初始化栈 2.销毁栈 3.压栈 4.出栈 5.返回栈顶元素 6.返回栈内元素个数 7.判断栈内是否为空 二.队列 1.队列的概念及结构 2.队列的实现 3.实现讲解 1.初始化队列 2.销毁队列 3.单个成员入队列 4.单个成员…

2、C#基于.net framework的应用开发实战编程 - 设计(二、三) - 编程手把手系列文章...

二、设计&#xff1b; 二&#xff0e;三、构建数据库&#xff1b; 此例子使用的是SQLite数据库&#xff0c;所以数据库工具用的SQLiteStudio x64&#xff0c;这个是SQLite专用的数据库设计管理工具&#xff0c;其它的数据库管理工具比如DBeaver的使用请见实战工具系列文章。 1、…

“信任构建”:网上购物商城的用户评价与信誉系统

2 相关技术 2.1 SSM框架介绍 本课题程序开发使用到的框架技术&#xff0c;英文名称缩写是SSM&#xff0c;在JavaWeb开发中使用的流行框架有SSH、SSM、SpringMVC等&#xff0c;作为一个课题程序采用SSH框架也可以&#xff0c;SSM框架也可以&#xff0c;SpringMVC也可以。SSH框架…

单点Redis所面临的问题及解决方法

1.数据丢失问题 大家可以设想一下这个场景&#xff0c;假如我们现在只有一个Redis&#xff0c;即单点Redis&#xff0c;我们在往Redis中添加数据的时候突然宕机了&#xff0c;那数据怎么办&#xff0c;如果是一条还好&#xff0c;我在敲一遍就行&#xff0c;那我敲了一万行都没…

计算机组成原理的学习笔记(8)-- 指令系统·其一 指令的组成以及数据寻址方式

学习笔记 前言 ​ 本文主要是对于b站尚硅谷的计算机组成原理的学习笔记&#xff0c;仅用于学习交流。 1. 指令 1.1 组成 操作码&#xff08;Opcode&#xff09;&#xff1a;指指令中执行特定操作的部分。地址码&#xff1a;指令中用于指定操作数位置的部分。 1.2 扩展操作…

RAGFlow 基于深度文档理解构建的开源 RAG引擎 - 安装部署

RAGFlow 基于深度文档理解构建的开源 RAG引擎 - 安装部署 flyfish 1. 确保 vm.max_map_count ≥ 262144 这是指要调整Linux内核参数vm.max_map_count&#xff0c;以确保其值至少为262144。这个参数控制着进程可以映射的最大内存区域数量。对于某些应用程序&#xff08;如Ela…

2024.2 ACM Explainability for Large Language Models: A Survey

Explainability for Large Language Models: A Survey | ACM Transactions on Intelligent Systems and Technology 问题 可解释性问题&#xff1a;大语言模型&#xff08;LLMs&#xff09;内部机制不透明&#xff0c;难以理解其决策过程&#xff0c;如在自然语言处理任务中&…

docker与docker-compose版本对应

1、说明 docker 和 docker-compose 是两个独立但又紧密相关的工具&#xff0c;docker用于管理docker容器&#xff0c;docker-compose用于编排多docker容器应用。了解它们之间的版本对应关系有助于确保在使用 docker-compose 时不会遇到兼容性问题。 2、docker与docker-compos…

【动态规划篇】步步带你深入解答成功AC最优包含问题(通俗易懂版)

本篇小鸡汤&#xff1a;待到苦尽甘来时&#xff0c;我给你讲讲来时路。 欢迎拜访&#xff1a;羑悻的小杀马特.-CSDN博客 本篇主题&#xff1a;解答洛谷的最优包含问题 制作日期&#xff1a;2024.12.23 隶属专栏&#xff1a;C/C题海汇总 ​​ 目录 本篇简介&#xff1a; 一动态…

Intent--组件通信

组件通信1 获取子活动的返回值 创建Activity时实现自动注册&#xff01;【Activity必须要注册才能使用】 默认 LinearLayout 布局&#xff0c;注意 xml 中约束布局的使用&#xff1b; 若需要更改 线性布局 只需要将标签更改为 LinearLayout 即可&#xff0c;记得 设置线性布局…

table 表格转成 excell 导出

OK&#xff0c;功能非常简单&#xff0c;但是很实用啊&#xff01; 依赖安装 这里我们需要安装两个依赖&#xff1a; xlsx 和 file-saver&#xff0c;就可以帮助我们实现功能了&#xff01; npm i xlsx file-saver代码参考 导出方法 utils/index.js import * as XLSX from …

Vivado 编译(单核性能对比+高性能迷你主机+Ubuntu20.04/22.04安装与区别+20.04使用远程命令)

目录 1. 简介 2. 单核性能对比 2.1 PassMark 2.2 geekbench 2.3 CPU-7 2.4 选择 UM790 pro 3. Ubuntu 22.04 物理机 3.1 安装 Ubuntu 22.04 3.2 安装 Vitis 2022.1 3.3 缺点 4. Ubuntu 20.04 物理机 4.1 安装 Ubuntu 20.04 4.2 实用命令 4.2.1 SSH 保持活跃 4.2…

Java期末复习JDBC|网课笔记+校课总结

目录 1、概念 2、JDBC步骤 JDBC的基本步骤&#xff1a; 1、加载数据库驱动&#xff1a;通常使用Class类的forName()静态方法来加载驱动。 2、通过DriverManager获取数据库连接&#xff1a;需要传入3个参数&#xff1a;数据库URL、登陆数据库的用户名和密码。 3、通过Conn…

Require:离线部署 Sourcegraph

Sourcegraph 使读取、编写和修复代码变得容易——即使在庞大而复杂的代码库中。 代码搜索&#xff1a;搜索所有分支和所有代码主机的所有存储库。代码智能&#xff1a;导航代码、查找引用、查看代码所有者、跟踪历史记录等。修复和重构&#xff1a;一次对许多存储库进行大规模更…

element ui--下拉根据拼音首字母过滤

很多场景下我们的下拉不仅仅要根据选项中的字过滤&#xff0c;还要根据拼音首字母过滤&#xff0c;现在我们来实现下。 要获取汉字拼音&#xff0c;可以用pinyin-pro库来实现 1.导入拼音库 npm install pinyin-pro 下面的代码可以获取companyName的拼音&#xff0c;返回的是…

Vue3 中使用axios

1.安装axios、js-cookie、pinia axios命令行&#xff1a; npm install axios js-cookie命令行&#xff1a; npm install js-cookie store命令行&#xff1a; npm install pinia 2.配置文件 (1)缓存文件配置 src/plugins/auth.js const sessionCache {set (key, valu…

从AI换脸到篡改图像,合合信息如何提升视觉内容安全?

本文目录 引言一、AI“真假之战”下的发展现状与考验挑战1.1 视觉内容安全现状与技术分类1.2视觉内容安全企业1.3视觉内容安全领域挑战 二、开山之石&#xff1a;引领视觉内容安全的创新之路2.1合合内容安全系统2.2发起编制相关技术规范2.3参与篡改检测挑战赛 三、视觉内容安全…

解决Ubuntu下无法装载 Windows D盘的问题

电脑安装了 Windows 和 Ubuntu 24.04 后&#xff0c;在Ubuntu系统上装载 D盘&#xff0c;发现无法装载错误如下&#xff1a; Error mounting /dev/nvme0n1p4 at /media/jackeysong/Data: wrong fs type, bad option, bad superblock on /dev/nvme0n1p4, missing codepage or h…

STM32-笔记10-手写延时函数(SysTick)

1、什么是SysTick Systick&#xff0c;即滴答定时器&#xff0c;是内核中的一个特殊定时器&#xff0c;用于提供系统级的定时服务。该定时器是一个24位的倒计数定时器‌。它从设定的初值&#xff08;即重载值&#xff09;开始计数&#xff0c;每经过一个系统时钟周期&#xff0…

“AI+Security”系列第4期(一)之“洞” 见未来:AI 驱动的漏洞挖掘新范式

在数字化浪潮下&#xff0c;安全漏洞问题日益严峻&#xff0c;成为各行业发展的重大挑战。近日&#xff0c;“AISecurity” 系列第 4 期线下活动于北京成功举办&#xff0c;聚焦 “洞” 见未来&#xff1a;AI 驱动的漏洞挖掘新范式&#xff0c;汇聚了安全领域的众多专家。 本次…