FEATURED · 精选文章

QEMU/KVM磁盘在线备份

发布时间 / 2026/8/12 20:01:37
来源 / 创域科博编辑部
栏目 / 资讯中心
QEMU/KVM磁盘在线备份 QEMU/KVM磁盘的在线完整及增量备份是“打包”方案的一种具体实现可实现基于时间点的备份同时支持本地与远程2种备份方式并可指定备份文件进行恢复。tag: qemu, kvm, disk, live, backup, incremental, bitmap小慢哥的原创文章欢迎转载目录▪ 1. 本文缘由▪ 2. 最终能实现什么▪ 3. 环境说明▪ 4. 常用命令一览▪ 5. 磁盘在线备份的4种方式▪ 6. 查询磁盘对应的设备名▪ 7. 什么是bitmap▪ 8. 创建与查询bitmap▪ 9. 基于bitmap做增量备份▪ 10. 删除bitmap▪ 11. 重置bitmap▪ 12. 备份逻辑▪ 13. 远程备份▪ 14. 备份任务管理▪ 15. 事件查看▪ 16. 备份链、数据恢复、合并▪ 17. 参考文档1. 本文缘由在虚拟化底层技术中存储是重中之重没有人愿意丢数据。因此备份就显得尤为重要根据备份的实现方案可分为2类▷副本可以单纯从后端存储上直接实现而无需计算层面的帮助比如Ceph可以做多副本本地盘文件形式可以通过DRBD技术做实时同步。副本方案提高了存储的整体可靠性▷打包表示对磁盘数据进行定期打包导出当需要恢复的时候可以指定备份文件来恢复副本与打包是互补的副本无法根据时间点来做备份恢复而打包也没有宕机前一刻的数据。本文阐述的所有内容均是“打包”2. 最终能实现什么经过调研和测试最终本文的内容可以实现如下几大功能▷ 在线完整备份、在线增量备份▷ 事件查看▷ 任务管理▷ 不限存储形式可以是本地盘qcow2、raw也可以是ceph rbd等各种形式▷ 远程备份3. 环境说明本文所有内容除特殊说明均是基于以下环境▷ 操作系统CentOS 7.5 x86_64▷ qemu基于ovirt-4.3 yum源的qemu-2.12.0▷ libvirt基于centos-update yum源的libvirt-4.5.04. 常用命令一览获取磁盘设备名# 通过qmp查看 virsh qemu-monitor-command DOMAIN --pretty { execute: query-block } # 通过hmp查看 virsh qemu-monitor-command DOMAIN --hmp info block--pretty表示将输出的json进行换行格式化展示否则只有一行该参数和--hmp互斥备份命令# 完整备份包含backing file“full” virsh qemu-monitor-command DOMAIN { execute : drive-backup , arguments : { device : drive-virtio-disk0 , sync : full , target : /opt/backup/full.img } } # 完整备份不包含backing file仅备份当前文件“top” virsh qemu-monitor-command DOMAIN { execute : drive-backup , arguments : { device : drive-virtio-disk0 , sync : top , target : /opt/backup/top.img } } # 实时导出新IO“none” virsh qemu-monitor-command DOMAIN { execute : drive-backup , arguments : { device : drive-virtio-disk0 , sync : none , target : /opt/backup/none.img } } # 增量备份“bitmap” virsh qemu-monitor-command DOMAIN { execute : drive-backup , arguments : { device : drive-virtio-disk0 , sync : incremental , bitmap : bitmap0 , target : /opt/backup/inc.0.qcow2 } } # 增量备份“bitmap”通过iscsi远程导出 virsh qemu-monitor-command DOMAIN { execute : drive-backup , arguments : { device : drive-virtio-disk0 , sync : incremental , bitmap : bitmap0 , target : iscsi://192.168.1.100:3260/iqn.2019-01.com.iaas/0 } }bitmap操作# 创建非持久bitmapqemu 2.4 virsh qemu-monitor-command DOMAIN { execute: block-dirty-bitmap-add, arguments: {node: drive-virtio-disk0,name: bitmap0}} # 创建持久bitmapqemu 2.10 virsh qemu-monitor-command DOMAIN { execute: block-dirty-bitmap-add, arguments: {node: drive-virtio-disk0,name: bitmapY, persistent: true}} # 删除bitmap virsh qemu-monitor-command DOMAIN { execute : block-dirty-bitmap-remove, arguments : { node : drive-virtio-disk0, name : bitmap0 } } # 重置bitmap virsh qemu-monitor-command DOMAIN { execute: block-dirty-bitmap-clear, arguments: {node: drive-virtio-disk0,name: bitmap0}} # 查询虚拟机所有磁盘的块信息含bitmap virsh qemu-monitor-command DOMAIN --pretty { execute: query-block } # 查询虚拟机指定磁盘的bitmap查询第一块磁盘使用[0]第二块用[1]以此类推 virsh qemu-monitor-command DOMAIN --pretty { execute: query-block } | jq .return[0] | sed -n /dirty\-bitmaps/,/]/p事件监听# 始终监听事件 virsh qemu-monitor-event DOMAIN --timestamp --loop # 当收到特定事件后停止监听 virsh qemu-monitor-event DOMAIN --event BLOCK_JOB_COMPLETED备份任务管理# 通过qmp查看运行中的任务 virsh qemu-monitor-command DOMAIN --pretty { execute: query-block-jobs } # 通过hmp查看运行中的任务 virsh qemu-monitor-command DOMAIN --hmp info block-jobs # 停止备份任务 virsh qemu-monitor-command DOMAIN { execute: block-job-cancel, arguments: { device: drive-virtio-disk0, force: true } } # 暂停备份任务 virsh qemu-monitor-command DOMAIN { execute : block-job-pause, arguments : { device : drive-virtio-disk0 } } # 恢复已暂停的备份任务 virsh qemu-monitor-command DOMAIN { execute : block-job-resume, arguments : { device : drive-virtio-disk0 } }5. 磁盘在线备份的4种方式▷full完整备份会将指定磁盘及其链上的所有母盘backing file合并输出到本地▷top仅备份当前磁盘而不包含backing file。此项仅对本地盘有效对于ceph rbdtop和full的效果一样都是完整备份▷nonenew I/O即从执行备份命令起一旦有IO变化就会实时导出有变化的数据直到虚拟机关机或者手工停止job才会停止。仅支持qcow2格式的块设备不支持raw格式注意这里指的是qcow2格式而并非要求qcow2本地盘▷incremental指定dirty bitmap进行备份目前qemu的增量备份就是指基于dirty bitmap的备份上述4种备份是互斥的任意一种备份job运行中都无法执行其他类型的备份也无法再开启同种备份的新jobfull、top、none这三种备份的操作方法非常简单在前面“常用命令一览”中已经提到不再赘述而增量备份会稍微复杂点本文的重点将放在增量备份上6. 查询磁盘对应的设备名由于qemu不支持一键备份所有磁盘因此无论有几块盘必须先找到要备份的磁盘设备名可通过qmp或者hmp查找设备名qmp是qemu原生方法hmp是为了简化qmp的使用而增加的一层翻译器其中的h就是human表示友好可读hmp虽然好用但不确定其能否支持所有qmp功能因此这里只是简单演示下hmp的使用之后主要还是通过qmp进行操作# 通过qmp查看 virsh qemu-monitor-command DOMAIN --pretty { execute: query-block } # 通过hmp查看 virsh qemu-monitor-command DOMAIN --hmp info block输出中的drive-virtio-disk0、drive-virtio-disk1就是设备名关于qmp和hmp的详细使用详见笔者的另一篇文章《基于QMP实现对qemu虚拟机进行交互》https://mp.weixin.qq.com/s/HUo0HO6Sl9xn5-FWiexXoA7. 什么是bitmap本文将重点讲解bitmap备份在qemu里“增量备份”指的就是基于dirty bitmap的incremental备份方式。请注意这里提到了2个词dirty bitmap和incremental接下来要详细讲解什么是bitmap、bitmap怎么用、有哪些特性与注意事项只有了解清楚bitmap才能做好增量备份什么是bitmap通过dirty bitmap可以实现qemu磁盘的在线增量备份而无需创建一长串的快照qemu的增量备份通常来说就是指通过dirty bitmap实现的备份dirty bitmap是qemu实现的跟踪需要在下次进行增量备份的数据▷ v2.4开始支持dirty bitmap但这时的bitmap只是记录在qemu的仿真器内存中并没有记录在底层块设备中底层块设备指ceph rbd、本地盘qcow2等这种bitmap称为in-memory bitmap笔者习惯叫做非持久bitmap▷ v2.10开始qemu开始支持persistent dirty bitmap笔者习惯叫做持久bitmapbitmap、dirty bitmap、persistent dirty bitmap区别▷bitmap是qemu支持的一个高级功能直到本文编写完成时v3.1.0bitmap只有一种类型就是dirty bitmap▷dirty bitmap是bitmap的一种类型也是唯一的类型因此dirty bitmap和bitmap是一回事。由于dirty bitmap是记录在内存中而非磁盘上因此可以支持任意类型的底层磁盘比如本地盘、ceph rbd也支持任意格式的磁盘格式比如qcow2、raw等等。▷persistent dirty bitmap是dirty bitmap的改进版因为dirty bitmap是记录在内存中的当qemu虚拟机关机后dirty bitmap就消失了就会导致需要重新做一次完整备份。persistent dirty bitmap是v2.10开始才支持持久bitmap仅支持qcow2不支持raw格式例如本地盘raw文件或者ceph-rbdbitmap的名称▷ 对于节点是唯一的但附加到不同节点的bitmap可以共享相同的名称。对于同一节点持久bitmap和非持久bitmap的名称也不能冲突▷ 为qemu内部使用而创建的bitmap可能是匿名的没有名称。但用户创建的bitmap肯定不是匿名的。每个节点可以有任意数量的bitmap▷ 用户创建的bitmap名称不能是空即基于bitmap做增量备份的工作原理▷ 首先在虚拟机启动状态下针对虚拟机某个磁盘称为node打上bitmap此时bitmap存在qemu内存中并且bitmap的count属性为0▷ 其次当磁盘数据有变化的时候bitmap会将变化记录下来可以看到count不断递增不会超过磁盘virtual size▷ 最后指定bitmap做备份时候qemu会根据bitmap记录导出对应的增量数据到本地或远程8. 创建与查询bitmap# 创建非持久bitmapqemu 2.4 virsh qemu-monitor-command DOMAIN --pretty { execute: block-dirty-bitmap-add, arguments: {node: drive-virtio-disk0,name: bitmap0}} # 创建持久bitmapqemu 2.10 virsh qemu-monitor-command DOMAIN --pretty { execute: block-dirty-bitmap-add, arguments: {node: drive-virtio-disk0,name: bitmap1, persistent: true}} # 查询虚拟机的所有磁盘的bitmap virsh qemu-monitor-command DOMAIN --pretty { execute: query-block } # 查询虚拟机第一块磁盘的bitmap virsh qemu-monitor-command DOMAIN--pretty { execute: query-block } | jq .return[0] | sed -n /dirty\-bitmaps/,/]/p # 查询虚拟机第二块磁盘的bitmap virsh qemu-monitor-command DOMAIN--pretty { execute: query-block } | jq .return[1] | sed -n /dirty\-bitmaps/,/]/p9. 基于bitmap做增量备份# 备份 virsh qemu-monitor-command DOMAIN --pretty { execute : drive-backup , arguments : { device : drive-virtio-disk0 , sync : incremental , bitmap : bitmap0 , target : /opt/backup/inc.0.qcow2 } } # 在备份过程中可以查看任务 virsh qemu-monitor-command DOMAIN --pretty { execute: query-block-jobs }10. 删除bitmapvirsh qemu-monitor-command DOMAIN --pretty { execute : block-dirty-bitmap-remove, arguments : { node : drive-virtio-disk0, name : bitmap0 } }11. 重置bitmap重置bitmap就是将bitmap的count值置为0重新跟踪磁盘变化virsh qemu-monitor-command DOMAIN --pretty { execute: block-dirty-bitmap-clear, arguments: {node: drive-virtio-disk0,name: bitmap0}}12. 备份逻辑到这里已经知道如何做完整备份和增量备份了但如何把二者结合起来呢“等下结合什么先做完整备份然后创建bitmap过段时间后做增量备份不行吗”“真要这么简单就好了但你漏了一个关键点在开机状态下磁盘的数据可能实时变化当你还在做完整备份的过程中磁盘数据可能已经变化了然后你再创建bitmap已经太迟了”“那我就先创建bitmap然后再做完整备份这样就不会缺少数据了吧”“看起来可以但从理论上来说也是不行的你看分别执行2条QMP命令先执行bitmap的创建再执行完整备份虽然创建bitmap是毫秒级完成的但若磁盘IO变化很快毫厘之间也有可能产生数据的变化”“那怎么办”“接着往下看就知道了”虚拟机启动前就确定要备份若虚拟机第一次启动之前就确定要备份磁盘那么可以paused状态启动虚拟机这样可以保证磁盘IO不会变化就没有上面的那么多担心了具体操作如下1️⃣ 以paused状态启动虚拟机virsh start DOMAIN --paused2️⃣ 对磁盘进行完整备份sync:top3️⃣ 对磁盘创建bitmapblock-dirty-bitmap-add4️⃣ 恢复虚拟机状态virsh resume DOMAIN5️⃣ 接下来可以做incremental备份sync:incremental范例如下virsh start DOMAIN --paused virsh qemu-monitor-command DOMAIN { execute : drive-backup , arguments : { device : drive-virtio-disk0 , sync : top , target : /opt/backup/top.img } } virsh qemu-monitor-command DOMAIN --pretty { execute: block-dirty-bitmap-add, arguments: {node: drive-virtio-disk0,name: bitmap0}} virsh resume DOMAIN # ...运行一段时间... virsh qemu-monitor-command DOMAIN --pretty { execute : drive-backup , arguments : { device : drive-virtio-disk0 , sync : incremental , bitmap : bitmap0 , target : /opt/backup/inc.0.qcow2 } } # ...又运行一段时间... virsh qemu-monitor-command DOMAIN --pretty { execute : drive-backup , arguments : { device : drive-virtio-disk0 , sync : incremental , bitmap : bitmap0 , target : /opt/backup/inc.1.qcow2 } }虚拟机运行过程中确定要备份如果是虚拟机已经运行一段时间了才决定做备份就需要用到QMP的“事务”1️⃣ 以事务方式对磁盘创建bitmapblock-dirty-bitmap-add及对磁盘做完整备份sync:top2️⃣ 接下来可以做incremental备份sync:incrementalQMP部分功能支持事务性事务的目的是当其中一件事失败后会自动回滚保证数据一致性但这里也可用于保证创建bitmap和开始备份之间没有缺少数据因此上述1️⃣通过事务操作{ execute: transaction, arguments: { actions: [ {type: block-dirty-bitmap-add, data: {node: drive-virtio-disk0, name: bitmap0} }, {type: drive-backup, data: {device: drive-virtio-disk0, target: /path/to/full_backup.img, sync: top} } ] } }范例如下virsh qemu-monitor-command DOMAIN --pretty { execute: transaction, arguments: { actions: [ { type: block-dirty-bitmap-add, data: {node:drive-virtio-disk0, name:bitmap0}}, { type: drive-backup, data: {device: drive-virtio-disk0, target: /opt/backup/top.img,sync:top }} ]} } # ...运行一段时间... virsh qemu-monitor-command DOMAIN --pretty { execute : drive-backup , arguments : { device : drive-virtio-disk0 , sync : incremental , bitmap : bitmap0 , target : /opt/backup/inc.0.qcow2 } } # ...又运行一段时间... virsh qemu-monitor-command DOMAIN --pretty { execute : drive-backup , arguments : { device : drive-virtio-disk0 , sync : incremental , bitmap : bitmap0 , target : /opt/backup/inc.1.qcow2 } }如果之前已经创建过bitmap此刻想忽略bitmap重新做一次完整备份并重置bitmap用于接下来的增量备份则可以{ execute: transaction, arguments: { actions: [ {type: block-dirty-bitmap-clear, data: {node: drive-virtio-disk0, name: bitmap0} }, {type: drive-backup, data: {device: drive-virtio-disk0, target: /path/to/new_full_backup.img, sync: top} } ] } }13. 远程备份经测试qemu仅支持一种远程备份方法iscsi方法就是在drive-backup的target里使用iscsi的格式即可# target内容 格式 iscsi://[username[%password]]host[:port]/target-iqn-name/lun 例子 iscsi://192.168.1.100:3260/iqn.2019-01.com.iaas/0 virsh qemu-monitor-command DOMAIN { execute : drive-backup , arguments : { device : drive-virtio-disk0 , sync : incremental , bitmap : bitmap0 , target : iscsi://192.168.1.100:3260/iqn.2019-01.com.iaas/0 } }14. 备份任务管理如果迟迟没有收到事件要如何查看备份任务是否还在进行中呢或者想中断备份又如何操作呢查看备份任务# 通过qmp查看 virsh qemu-monitor-command DOMAIN --pretty { execute: query-block-jobs } # 通过hmp查看 virsh qemu-monitor-command DOMAIN --hmp info block-jobs输出# 通过qmp查看有任务时候的输出 { return: [ { auto-finalize: true, io-status: ok, device: drive-virtio-disk1, auto-dismiss: true, busy: true, len: 1073741824, offset: 2424832, status: running, paused: false, speed: 0, ready: false, type: backup }, { auto-finalize: true, io-status: ok, device: drive-virtio-disk0, auto-dismiss: true, busy: true, len: 21474836480, offset: 163840000, status: running, paused: false, speed: 0, ready: false, type: backup } ], id: libvirt-45 } # 通过qmp查看无任务时候的输出 { return: [ ], id: libvirt-360 } # 通过hmp查看有任务时候的输出 Type backup, device drive-virtio-disk1: Completed 20185088 of 1073741824 bytes, speed limit 0 bytes/s Type backup, device drive-virtio-disk0: Completed 181403648 of 21474836480 bytes, speed limit 0 bytes/s # 通过hmp查看无任务时候的输出 No active jobs停止备份任务virsh qemu-monitor-command DOMAIN --pretty { execute: block-job-cancel, arguments: { device: drive-virtio-disk1, force: true } }如果不带force参数则默认为false在false情况下当任务处于暂停状态时无法停止输出{return:{},id:libvirt-5880}同时收到事件2019-02-03 13:02:58.5350000: event JOB_STATUS_CHANGE for domain DOMAIN: {status:aborting,id:drive-virtio-disk1} 2019-02-03 13:02:58.5410000: event BLOCK_JOB_CANCELLED for domain DOMAIN: {device:drive-virtio-disk1,len:2147483648,offset:29687808,speed:0,type:backup} 2019-02-03 13:02:58.5410000: event JOB_STATUS_CHANGE for domain DOMAIN: {status:concluded,id:drive-virtio-disk1} 2019-02-03 13:02:58.5410000: event JOB_STATUS_CHANGE for domain DOMAIN: {status:null,id:drive-virtio-disk1}▷ 根据官方文档JOB_STATUS_CHANGE事件是从qemu-3.0才出现的但在qemu-2.12时就能看到了2.9看不到尚未深究▷ 因此若qemu是2.12当收到JOB_STATUS_CHANGE事件应当不予理会后面不再赘述暂停备份任务virsh qemu-monitor-command DOMAIN { execute : block-job-pause, arguments : { device : drive-virtio-disk0 } }输出{return:{},id:libvirt-5882}同时收到事件假设之前任务处于running状态2019-01-22 02:42:55.5030000: event JOB_STATUS_CHANGE for domain DOMAIN: {status:paused,id:drive-virtio-disk0}恢复已暂停的备份任务virsh qemu-monitor-command DOMAIN { execute : block-job-resume, arguments : { device : drive-virtio-disk0 } }输出{return:{},id:libvirt-5999}同时收到事件2019-01-22 02:46:04.9280000: event JOB_STATUS_CHANGE for domain DOMAIN: {status:running,id:drive-virtio-disk0}15. 事件查看监听事件在备份操作前可以另外再开一个shell窗口实时监听qmp的事件# 始终监听事件 virsh qemu-monitor-event DOMAIN --timestamp --loop # 当收到特定事件后停止监听 virsh qemu-monitor-event DOMAIN --event BLOCK_JOB_COMPLETED开始备份时会收到的事件2019-01-29 03:14:54.5160000: event JOB_STATUS_CHANGE for domain DOMAIN: {status:created,id:drive-virtio-disk0} 2019-01-29 03:14:54.5160000: event JOB_STATUS_CHANGE for domain DOMAIN: {status:running,id:drive-virtio-disk0}备份完成时收到的事件2019-01-24 06:25:21.6290000: event JOB_STATUS_CHANGE for domain DOMAIN: {status:created,id:drive-virtio-disk0} 2019-01-24 06:25:21.6290000: event JOB_STATUS_CHANGE for domain DOMAIN: {status:running,id:drive-virtio-disk0} 2019-01-24 06:26:34.9350000: event JOB_STATUS_CHANGE for domain DOMAIN: {status:waiting,id:drive-virtio-disk0} 2019-01-24 06:26:34.9350000: event JOB_STATUS_CHANGE for domain DOMAIN: {status:pending,id:drive-virtio-disk0} 2019-01-24 06:26:34.9350000: event BLOCK_JOB_COMPLETED for domain DOMAIN: {device:drive-virtio-disk0,len:21474836480,offset:21474836480,speed:0,type:backup} 2019-01-24 06:26:34.9350000: event JOB_STATUS_CHANGE for domain DOMAIN: {status:concluded,id:drive-virtio-disk0} 2019-01-24 06:26:34.9350000: event JOB_STATUS_CHANGE for domain DOMAIN: {status:null,id:drive-virtio-disk0}▷ 重点看上面的BLOCK_JOB_COMPLETED事件该事件从qemu-1.1就已经出现的▷ 遗憾的是事件内容并不详细无法识别出是full、top、none还是bitmap也看不到备份产生的文件路径16. 备份链、数据恢复、合并其实本章节应该放到本文最后面但本文篇幅较多放后面担心容易被遗漏备份链经过增量备份后会形成一条备份链full.qcow2 - inc.0.qcow2 - inc.1.qcow2 - inc.2.qcow2数据恢复当需要使用备份进行数据恢复时候就可以使用该链上的文件进行恢复比如要恢复到inc.1.qcow2的末尾那么有2种方案保持链、合并▷保持链1️⃣ 将full.qcow2、inc.0.qcow2、inc.1.qcow2拷贝到目标宿主机上2️⃣ 通过qemu-img rebase -u来确保链的顺序3️⃣ 虚拟机xml里指定inc.1.qcow2▷合并1️⃣ 将full.qcow2、inc.0.qcow2、inc.1.qcow2合并成为一个qcow2# 将inc.1.qcow2合并到inc.0.qcow2 qemu-img commit inc.1.qcow2 # 将inc.0.qcow2合并到full.qcow2 qemu-img commit inc.0.qcow22️⃣ 然后xml里指定这个合并好的qcow2即full.qcow2就行17. 参考文档# 作者最初的想法 http://lists.gnu.org/archive/html/qemu-devel/2013-11/msg03035.html # 官方文章 qcow2介绍https://chromium.googlesource.com/external/qemu//v2.12.0/docs/interop/qcow2.txt bitmap介绍https://chromium.googlesource.com/external/qemu//v2.12.0/docs/interop/bitmaps.rst qmp使用https://qemu.weilnetz.de/doc/qemu-qmp-ref.html qemu使用https://qemu.weilnetz.de/doc/qemu-doc.html # 关于qemu磁盘备份的文章 2011年https://www.linux-kvm.org/images/b/b6/2011-forum-LiveBackup.pdf 2015年http://events17.linuxfoundation.org/sites/events/files/slides/kvm2015_rh_light_44_vfinal.pdf 2016年https://www.linux-kvm.org/images/6/65/02x08B-Max_Reitz-Backups_with_QEMU.pdf 2017年https://www.linux-kvm.org/images/e/e6/Kvm-forum2017_backup.pdf 2018年https://events.linuxfoundation.org/wp-content/uploads/2017/12/2018-libvirt-incremental-backup-expanded._Eric-Blake.pdf 2018年https://archive.fosdem.org/2018/schedule/event/vai_qemu_live_dev_operations/attachments/slides/2391/export/events/attachments/vai_qemu_live_dev_operations/slides/2391/Live_Block_Device_Operations_in_QEMU_FOSDEM2018.pdf # iscsi http://atodorov.org/blog/2015/04/07/how-to-configure-iscsi-target-on-red-hat-enterprise-linux-7/ http://linux-iscsi.org/wiki/TargetcliQEMU磁盘的在线备份是“打包”方案的一种具体实现可实现基于时间点的备份同时支持本地与远程2种备份方式并可指定备份文件进行恢复
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻