新钛云服已累计为您分享698篇技术干货


最近,很多人都会问:如何设置 QEMU/KVM 以获取最高的性能?
虽然,过去很多人都在测试或者使用 Ceph 过程中进行调优设置以获取最佳性能,但到目前而言,还没有一个最优的最新数据。通常,我们在使用 Ceph 的时候,有经验的工程师往往会通过消除系统高级别的性能瓶颈来优化。
这可能意味着可能会通过 librbd 与同步 IO 隔离测试单个OSD的延迟,或者使用大量有高 IO 深度的客户端在裸机上的 OSD 集群上产生大量IO。在这种情况下,请求是用大量并发 IO 驱动由 librbd 支持的单个 QEMU/KVM,并查看其速度。
下文,我们将了解 QEMU/KVM 在使用 Ceph 的 librbd 驱动程序时的执行速度。
集群设置

所有节点都位于同一个 Juniper QFX5200 交换机上,并通过单个 100GbE QSFP28 链路连接。虽然集群有 10 个节点,但在决定最终设置之前我们也评估了各种配置。最终使用 5 个节点作为 OSD 主机,总共有 30 个 NVMe 支持的 OSD。
此设置的预期总体性能约为 1M 随机读取 IOPS 和至少 250K 随机写入 IOPS(在 3 副本的场景下),这足以测试单个 VM 的 QEMU/KVM 性能。集群中剩余的一个节点用作 VM 客户端主机。不过,在配置 VM 之前,使用 CBT (https://github.com/ceph/cbt/) 构建了几个测试集群,并使用 fio 的 librbd 引擎运行测试工作负载以获得基线结果。
基线测试
CBT 的配置为匹配 Ceph 环境修改了一些,而不是使用默认的配置。首先,禁用了 rbd 缓存 (1),每个 OSD 被分配了一个 8GB 的 OSD 内存 traget,并且在初始测试中禁用了 cephx ,并且使用 msgr V1(但在以后的测试中使用安全模式下的 msgr V2 启用了 cephx)。创建集群后,CBT 配置为使用带有 librbd 引擎的 fio 创建一个 6TB RBD 卷,然后通过 iodepth=128 的 fio 执行 16KB 随机读取 5 分钟。由于使用 CBT 重新创建集群和运行多个基线测试非常简单,因此,下面测试了几种不同的集群大小以获得 librbd 引擎和基于 kernel-rbd 的 libaio 引擎的基线结果。
在集群级别禁用 RBD 缓存将对使用 librbd 引擎的 fio 有效,但不会对 QEMU/KVM 的 librbd 驱动程序有效。相反,cache=none 必须通过 qemu-kvm 的驱动部分显式传递。
Kernel-RBD 在从单个 OSD 读取时表现非常出色,但 Librbd 在完整的 30 个 OSD Ceph 集群中以略高于 122K IOPS 的速度实现了最高性能。librbd 和 kernel-rbd 在 5 OSD Ceph 集群上的表现几乎一样。
尽管如此,在 5 个节点、30 个 OSD Ceph 集群上我们执行了进一步的测试。此场景更好地模仿了用户在小规模但更贴近真实环境并且配置 NVMe 的 Ceph 集群上可能看到的结果。
虚拟机部署
1. 下载镜像
wget https://cloud.centos.org/centos/8-stream/x86_64/images/CentOS-Stream-GenericCloud-8-20220913.0.x86_64.qcow2
virt-sysprep -a ~/CentOS-Stream-GenericCloud-8-20220913.0.x86_64.qcow2 --root-password password:123456 --ssh-inject root:file:/home/nhm/.ssh/id_rsa.pub
2. RBD 镜像池创建、初始化和设置 LibVirt 身份验证
sudo /usr/local/bin/ceph osd pool create libvirt-pool
sudo /usr/local/bin/rbd pool init libvirt-pool
sudo /usr/local/bin/ceph auth get-or-create client.libvirt mon 'profile rbd' osd 'profile rbd pool=libvirt-pool'
3. 将 qcow2 镜像转换为 Ceph RBD 镜像并调整大小
qemu-img convert -f qcow2 -O raw ./CentOS-Stream-GenericCloud-8-20220913.0.x86_64.qcow2 rbd:libvirt-pool/CentOS8
qemu-img resize rbd:libvirt-pool/CentOS8 6000G
4. 完成设置虚拟机并预填充基准数据
/usr/libexec/qemu-kvm -m 16384 -smp 16,sockets=1,cores=16,threads=1 -drive format=raw,file=rbd:libvirt-pool/CentOS8 -net nic -net user,hostfwd=tcp::2222-:22
ssh -p 2222 root@localhost
sudo yum install fio
cfdisk /dev/sda # Create a 2TB partition here (maximum size due to the partition type for image, oh well)
fio --ioengine=libaio --rw=write --numjobs=1 --bs=4M --iodepth=128 --size=20G --name=/dev/sda2
对 VM 进行基准测试
1. 默认情况
/usr/libexec/qemu-kvm -m 16384 -smp 16,sockets=1,cores=16,threads=1 -drive format=raw,file=rbd:libvirt-pool/CentOS8 -net nic -net user,hostfwd=tcp::2222-:22
fio --ioengine=libaio --direct=1 --bs=16384 --iodepth=128 --rw=randread --norandommap --size=20G --numjobs=1 --runtime=300 --time_based --name=/dev/sda2
read: IOPS=2484, BW=38.8MiB/s (40.7MB/s)(11.4GiB/300001msec)
2. 使用 virtio-blk-pci
/usr/libexec/qemu-kvm -m 16384 -smp 16,sockets=1,cores=16,threads=1 -drive format=raw,id=rbd0,if=none,file=rbd:libvirt-pool/CentOS8 -device virtio-blk-pci,drive=rbd0,id=virtioblk0 -net nic -net user,hostfwd=tcp::2222-:22
fio --ioengine=libaio --direct=1 --bs=16384 --iodepth=128 --rw=randread --norandommap --size=20G --numjobs=1 --runtime=300 --time_based --name=/dev/vda2
read: IOPS=24.9k, BW=390MiB/s (409MB/s)(114GiB/300005msec)
3. 添加单独的 IO 线程
/usr/libexec/qemu-kvm -m 16384 -smp 16,sockets=1,cores=16,threads=1 -drive format=raw,id=rbd0,if=none,file=rbd:libvirt-pool/CentOS8 -object iothread,id=iothread0 -device virtio-blk-pci,iothread=iothread0,drive=rbd0,id=virtioblk0 -net nic -net user,hostfwd=tcp::2222-:22
fio --ioengine=libaio --direct=1 --bs=16384 --iodepth=128 --rw=randread --norandommap --size=20G --numjobs=1 --runtime=300 --time_based --name=/dev/vda2
read: IOPS=26.0k, BW=407MiB/s (426MB/s)(119GiB/300005msec)
4. 禁用 LibRBD 驱动器缓存
/usr/libexec/qemu-kvm -m 16384 -smp 16,sockets=1,cores=16,threads=1 -drive format=raw,id=rbd0,if=none,cache=none,file=rbd:libvirt-pool/CentOS8 -object iothread,id=iothread0 -device virtio-blk-pci,iothread=iothread0,drive=rbd0,id=virtioblk0 -net nic -net user,hostfwd=tcp::2222-:22
fio --ioengine=libaio --direct=1 --bs=16384 --iodepth=128 --rw=randread --norandommap --size=20G --numjobs=1 --runtime=300 --time_based --name=/dev/vda2
read: IOPS=53.5k, BW=836MiB/s (876MB/s)(245GiB/300003msec)
5. 将内存分配器切换到 TCMalloc
LD_PRELOAD="/usr/lib64/libtcmalloc.so" /usr/libexec/qemu-kvm -m 16384 -smp 16,sockets=1,cores=16,threads=1 -drive format=raw,id=rbd0,if=none,cache=none,file=rbd:libvirt-pool/CentOS8 -device virtio-blk-pci,drive=rbd0,id=virtioblk0 -net nic -net user,hostfwd=tcp::2222-:22
fio --ioengine=libaio --direct=1 --bs=16384 --iodepth=128 --rw=randread --norandommap --size=20G --numjobs=1 --runtime=300 --time_based --name=/dev/vda2
read: IOPS=80.0k, BW=1250MiB/s (1311MB/s)(366GiB/300003msec)
6. 使用新版本的 LibRBD
LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64
LD_PRELOAD="/usr/lib64/libtcmalloc.so" /usr/libexec/qemu-kvm -m 16384 -smp 16,sockets=1,cores=16,threads=1 -drive format=raw,id=rbd0,if=none,cache=none,aio=native,file=rbd:libvirt-pool/CentOS8 -object iothread,id=iothread0 -device virtio-blk-pci,iothread=iothread0,drive=rbd0,id=virtioblk0 -net nic -net user,hostfwd=tcp::2222-:22
fio --ioengine=libaio --direct=1 --bs=16384 --iodepth=128 --rw=randread --norandommap --size=20G --numjobs=1 --runtime=300 --time_based --name=/dev/vda2
read: IOPS=126k, BW=1964MiB/s (2060MB/s)(575GiB/300002msec)
更大镜像的测试
mkfs.xfs /dev/vda2
mount /dev/vda2 /mnt
fio --ioengine=libaio --direct=1 --rw=write --numjobs=1 --bs=4M --iodepth=16 --size=2000G --name=/mnt/foo
write: IOPS=607, BW=2429MiB/s (2547MB/s)(2000GiB/843305msec); 0 zone resets
16K 随机读取
fio --ioengine=libaio --direct=1 --bs=16384 --iodepth=128 --rw=randread --norandommap --size=2000G --numjobs=1 --runtime=300 --time_based --name=/mnt/foo
read: IOPS=123k, BW=1916MiB/s (2009MB/s)(561GiB/300002msec)
16K 随机写入
fio --ioengine=libaio --direct=1 --bs=16384 --iodepth=128 --rw=randwrite --norandommap --size=2000G --numjobs=1 --runtime=300 --time_based --name=/mnt/foo
write: IOPS=64.1k, BW=1001MiB/s (1050MB/s)(293GiB/300003msec); 0 zone resets
进一步的 QEMU 优化?
较新的 --blockdev rbd,node-name=rbd0,cache.direct=on,pool=libvirt-pool,image=CentOS8
参数省略了 “raw'” 驱动程序以实现微小的加速...I O请求直接进行使用这种新参数从模拟的 virtio-blk 设备到 rbd 驱动程序。使用 -M q35 获得现代机器类型。
LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64
LD_PRELOAD="/usr/lib64/libtcmalloc.so" /usr/libexec/qemu-kvm -m 16384 -smp 16,sockets=1,cores=16,threads=1 --blockdev rbd,node-name=rbd0,cache.direct=on,pool=libvirt-pool,image=CentOS8 -M q35 -object iothread,id=iothread0 -device virtio-blk-pci,iothread=iothread0,drive=rbd0,id=virtioblk0 -net nic -net user,hostfwd=tcp::2222-:22

Msgr V2 和 AES 加密
ms_client_mode = secure
ms_cluster_mode = secure
ms_service_mode = secure
ms_mon_client_mode = secure
ms_mon_cluster_mode = secure
ms_mon_service_mode = secure

+ 14.00% _aesni_ctr32_ghash_6x
|+ 14.00% aesni_gcm_decrypt
| + 14.00% aes_gcm_cipher
| + 14.00% EVP_DecryptUpdate
| + 14.00% ceph::crypto::onwire::AES128GCM_OnWireRxHandler::authenticated_decrypt_update(ceph::buffer::v15_2_0::list&)
| + 14.00% ceph::msgr::v2::FrameAssembler::disasm_remaining_secure_rev1(ceph::buffer::v15_2_0::list*, ceph::buffer::v15_2_0::list&) const
Disassemble first segment
Disassemble remaining segments
For each Segment in Segments:
For each buffer in Segment:
convert buffer to c string
call EVP_DecryptUpdate on c string
openssl speed -evp aes-128-gcm -decrypt

结论
推荐阅读


推荐视频





