Ceph,作为一个高度可扩展的分布式存储系统,已经成为云计算和大数据时代的关键基石。随着企业和组织对数据存储的需求日益增长,Ceph 通过其强大的特性,如可靠性、伸缩性和性能,满足了这些需求。然而,随着集群规模的扩大和工作负载的多样性,如何确保资源的有效分配和性能隔离成为了一个重要议题。在这个背景下,Ceph 的 Quality of Service (QoS) 功能显得尤为重要。
QoS 在 Ceph 中的实现,特别是在其 RADOS Block Device (RBD) 模块中,提供了一种机制来控制和限制存储资源的使用,如 IOPS(每秒输入输出操作次数)和带宽。这对于在多租户环境中维持服务质量,防止资源过度使用或“邻居噪音”问题至关重要。通过精确地配置 QoS 参数,管理员可以为不同的虚拟机、容器或应用分配适当的存储资源,确保系统的整体性能和响应性。
在本文中,我们将深入探讨 Ceph RBD 的 QoS 特性,重点关注如何验证和量化 RBD QoS 设置的效果。通过一系列的测试和分析,我们将展示 QoS 参数如何影响 RBD 性能,以及如何根据特定的工作负载和性能要求调整这些参数。无论是对于 Ceph 新手还是资深用户,了解和应用 RBD 的 QoS 功能都是提高存储系统效率和可靠性的关键步骤。
测试环境
- 操作系统:ubuntu 20.04
- 内核:5.4.0-163-generic
- CPU / 内存:32C / 128G
- 硬盘:10T
- ceph:17.2.5 quincy (stable)
测试流程
- 拉起一个使用ceph rbd存储的虚拟机
- 使用fio测试无限速情况下iops和bps
- 开启 image qos iops限速 测试rbd的iops
- 开启 image qos bps限速 测试rbd的bps
- 开启 pool qos iops限速 测试rbd的iops
- 开启 pool qos bps限速 测试rbd的bps
- 测试qemu对块设备进行bps限速
- 测试qemu对块设备进行iops限速
- 删除qos再次进行测试,验证已经恢复
测试步骤
在ceph 14版本开始支持rbd的qos 详细配置参数可以参考https://docs.ceph.com/en/latest/rbd/rbd-config-ref/
ceph rbd的qos是在librbd上进行限制的。
查看当前镜像的qos配置
代码语言:javascript复制rbd -p libvirt-pool config image ls scan.img|grep qos
查看存储池的qos配置,存储池的qos限制的是所有镜像总的qos不超过设置的值
代码语言:javascript复制rbd config pool ls libvirt-pool|grep qos
可以看到默认不设置的时候bps和iops都为0,表示默认不限速。rbd_qos_schedule_tick_min=50表示qos的最小调度间隔是50毫秒,每隔50毫秒检查一次当前的io操作是否符合qos配置。这里解释下rbd_qos_write_iops_burst_seconds=1表示在达到写入 IOPS 限制(由 rbd_qos_write_iops_limit 参数设置)之后,RBD 图像可以以突发模式继续写入操作的时间长度。这个突发模式允许 IOPS 短时间内超过设定的限制值,为的是处理短暂的高负载情况,而不是持续的高速写入。这个参数的值设定为 1 秒,意味着在触发 IOPS 限制后,写入操作可以在接下来的 1 秒内保持较高的 IOPS,之后将被限制回设定的 rbd_qos_write_iops_limit 值,同样对bps的burst_seconds的意义也是一样。
解释下相关参数:
- IOPS:每秒 I/O 数(任何类型的 I/O)
- read IOPS:每秒读取 I/O 数
- write IOPS:每秒写入 I/O 数
- bps:每秒字节数(任何类型的 I/O)
- read bps:每秒读取的字节数
- write bps:每秒写入的字节数
使用fio进行读取写入测试
fio 是一个灵活的 I/O 性能测试工具,广泛用于评估磁盘和文件系统的性能。以下是一个基本的示例,展示如何使用 fio 进行随机读写测试:
代码语言:javascript复制fio --name=randrw_test --ioengine=libaio --iodepth=1 --rw=randrw --rwmixread=50 --bs=4k --direct=1 --size=1G --numjobs=4 --runtime=60 --group_reporting
参数解释
- --name=randrw_test: 测试的名称。
- --ioengine=libaio: 使用 Linux AIO(异步 I/O)作为 I/O 引擎。
- --iodepth=1: I/O 深度,这里设置为 1,意味着每个 job 在任何时刻只有一个 I/O 操作在等待。
- --rw=randrw: 测试类型为随机读写。
- --rwmixread=50: 读写混合比例,这里设置为 50%,意味着读操作和写操作各占 50%。
- --bs=4k: 块大小设置为 4KB。
- --direct=1: 使用直接 I/O,绕过缓存。
- --size=1G: 每个 job 测试文件的大小。
- --numjobs=4: 同时运行的 job 数量。
- --runtime=60: 测试运行时间,这里设置为 60 秒。
- --group_reporting: 作为一个组来报告所有 job 的结果。
在不进行qos限速的情况下,我使用fio在rbd镜像存储的虚拟机里进行随机读写测试
代码语言:javascript复制rbd perf image iostat --pool libvirt-pool
image.png
开启 image qos iops限制此镜像的iops为100 测试scan.img的iops
代码语言:javascript复制rbd -p libvirt-pool config image set scan.img rbd_qos_iops_limit 100
再次在scan.img所在的虚拟机上进行随机读写测试
代码语言:javascript复制fio --name=randrw_test --ioengine=libaio --iodepth=1 --rw=randrw --rwmixread=50 --bs=4k --direct=1 --size=1G --numjobs=4 --runtime=60 --group_reporting
查看iops限速后的结果
代码语言:javascript复制rbd perf image iostat --pool libvirt-pool
可以看到效果很明显,iops读写不超过100
开启 image qos bps限制此镜像的bps为100KiB/s 测试scan.img的bps
代码语言:javascript复制rbd -p libvirt-pool config image set scan.img rbd_qos_iops_limit 0
rbd -p libvirt-pool config image set scan.img rbd_qos_bps_limit 100000
再次在scan.img所在的虚拟机上进行随机写测试
代码语言:javascript复制fio --name=randrw_test --ioengine=libaio --iodepth=1 --rw=randwrite --rwmixread=50 --bs=4k --direct=1 --size=1G --numjobs=4 --runtime=60 --group_reporting
查看bps限速后的结果
代码语言:javascript复制rbd perf image iostat --pool libvirt-pool
可以看到效果很明显,写吞吐不超过100KiB/s
后面单独对读写的iops和bps各进行了测试,发现符合预期。
开启 pool qos iops限速 测试存储池所有镜像的iops
代码语言:javascript复制rbd -p libvirt-pool config image set scan.img rbd_qos_bps_limit 0
rbd config pool set libvirt-pool rbd_qos_iops_limit 200
再次在scan.img所在的虚拟机上进行随机读写测试
代码语言:javascript复制fio --name=randrw_test --ioengine=libaio --iodepth=1 --rw=randrw --rwmixread=50 --bs=4k --direct=1 --size=1G --numjobs=4 --runtime=60 --group_reporting
这里发现对于pool层面的iops限速没什么效果
开启 pool qos bps限速 测试存储池所有镜像的bps
代码语言:javascript复制rbd config pool set libvirt-pool rbd_qos_iops_limit 0
rbd config pool set libvirt-pool rbd_qos_bps_limit 1000000
再次在scan.img所在的虚拟机上进行随机写测试
代码语言:javascript复制fio --name=randrw_test --ioengine=libaio --iodepth=1 --rw=randwrite --rwmixread=50 --bs=4k --direct=1 --size=1G --numjobs=4 --runtime=60 --group_reporting
这里发现对于pool层面的bps限速也没什么效果
后面单独对pool层面分别进行读、写的iops和bps,发现限速也没什么效果
测试qemu对块设备进行bps限速
可以通过下面命令查看当前虚拟机的qos,这里查看scan虚拟机vdb磁盘的qos,也就是我们刚才测试rbd qos的那个磁盘,0表示不限速
代码语言:javascript复制virsh blkdeviotune scan vdb
对scan虚拟机的vdb进行bps限制为5MiB/s
代码语言:javascript复制virsh blkdeviotune scan vdb --total-bytes-sec 5000000 --live
查看bps限速后的结果,iops实际不超过5MiB/s
测试qemu对块设备进行iops限速
对scan虚拟机的vdb进行iops限制
代码语言:javascript复制virsh blkdeviotune scan vdb --total-bytes-sec 0 --live
virsh blkdeviotune scan vdb --total-iops-sec 1000 --live
在scan虚拟机里对其进行随机读写测试
代码语言:javascript复制fio --name=Test --ioengine=libaio --iodepth=64 --rw=randrw --bs=4k --direct=1 --size=1G --numjobs=4 --runtime=60 --group_reporting
查看iops限速后的结果,iops实际不超过1000
删除qos再次进行测试
再次在scan.img所在的虚拟机上进行随机读写测试
代码语言:javascript复制fio --name=Test --ioengine=libaio --iodepth=64 --rw=randrw --bs=4k --direct=1 --size=1G --numjobs=4 --runtime=60 --group_reporting
image.png
测试结论
对于ceph rbd qos的使用,还是建议在image层面进行bps和iops的限速,pool层面的限速效果不明显。当然也可以使用qemu在块设备上做虚拟机磁盘的io限制,使用qemu做qos的优点是本地硬盘也可以进行限速,而ceph rbd的qos对象只是ceph集群中的rbd镜像。