TT Lab
开始
学习 学习路径 课程

存储实务 — RAID、快照、iSCSI、fio

挂上 iSCSI LUN 并用 fio 测量

在 TT Lab 中继续学习

目标

在同一台 VM 内搭建 LIO 目标端来提供 LUN,用发起端配置发现、登录、以 _netdev 挂载和自动登录,然后在该磁盘上用 fio 测量不同队列深度下的 IOPS 和延迟,并从 JSON 中取出数字进行上报。

为什么重要

把 SAN 的 LUN 挂到服务器上是基础设施工程师的日常工作,但如果不了解它与本地磁盘不同的三件事(要等网络的挂载、按名称做的访问控制、多条路径),重启一次服务器就会卡住。而且要回应“磁盘很慢”的报告,需要固定条件的测量。亲眼看到只改一个队列深度,IOPS 和延迟就会一起变化,就能解释规格书上的数字与应用实际遇到的数字为什么不同。

本实验在 Ubuntu 24.04 VM 中以 root 身份运行。目标端和发起端在同一台 VM 中通过 127.0.0.1:3260 相遇,所以完全按网络存储的流程操作,但测量数字并不是真正 SAN 的数字——fileio 后端存储会经过目标端一侧的页缓存,所以即使队列深度为 1 也能跑出几万 IOPS(实测)。目的不是看绝对值,而是看改变一个条件时数字如何变化。会话从 60 分钟开始,最多可延长到 180 分钟,会话结束后 VM 会消失。

步骤

  1. 把 /var/lib/sto/lun0.img(512MiB)创建为 fileio 后端存储 lun0,作为 LUN 挂到目标端 iqn.2026-09.io.labhub:sto 的 tpg1 下,把这台 VM 的发起端名称加入 ACL,再用 targetcli saveconfig 保存。
  2. 发现(sendtargets) 127.0.0.1 门户,并把输出保存到 /root/sto/iscsi/discovery.txt。
  3. 登录目标端,使新磁盘在 TRAN 中显示为 iscsi,并把 lsblk -o NAME,SIZE,TRAN,VENDOR,MODEL 的输出保存到 /root/sto/iscsi/lsblk.txt。
  4. 把 iSCSI 磁盘格式化为 ext4,在 /etc/fstab 中写入包含 UUID= 和 _netdev 的一行,使其挂载到 /mnt/iscsi,并现在就挂载好。
  5. 把节点记录中的 node.startup 改为 automatic。
  6. 在 /mnt/iscsi/fio.dat(128MiB)上测量 4KiB randread、libaio、direct=1、iodepth=1、10 秒,把 JSON 保存到 /root/sto/fio/qd1.json。
  7. 在相同条件下只改为 iodepth=32 再测一次,把 JSON 保存到 /root/sto/fio/qd32.json。
  8. 在 /root/sto/fio/report.txt 中写入 qd1_iops=、qd1_p99_us=、qd32_iops=、qd32_p99_us=、qd32_little= 五行,数值从 JSON 中计算得出。

参考

用 LIO 目标端提供 LUN

把 /var/lib/sto/lun0.img(512MiB)创建为 fileio 后端存储 lun0,并作为 LUN 挂到目标端 iqn.2026-09.io.labhub:sto 的 tpg1 下。把这台 VM 的发起端名称(/etc/iscsi/initiatorname.iscsi 中 InitiatorName= 的值)加入 ACL,并用 targetcli saveconfig 保存配置。

targetcli 会填充一棵形如路径的树——/backstores/fileio create、/iscsi create、/iscsi//tpg1/luns create、/iscsi//tpg1/acls create。门户(0.0.0.0:3260)在创建目标端时默认就会生成。

发现目标端

用发起端发现(sendtargets) 127.0.0.1 门户,并把输出保存到 /root/sto/iscsi/discovery.txt。

iscsiadm -m discovery -t sendtargets -p <门户>。发现不会建立会话,只会创建节点记录。

登录并确认新磁盘

登录目标端 iqn.2026-09.io.labhub:sto。新出现的磁盘在 lsblk 的 TRAN 列中必须显示为 iscsi。把 lsblk -o NAME,SIZE,TRAN,VENDOR,MODEL 的输出保存到 /root/sto/iscsi/lsblk.txt。

iscsiadm -m node -T -p <门户> --login。已登录的会话用 iscsiadm -m session 查看。

用 _netdev 登记到 fstab

把 iSCSI 磁盘格式化为 ext4,并在 /etc/fstab 中写入一行:以 UUID= 开头,选项中包含 _netdev,挂载点是 /mnt/iscsi。现在必须已经像 mount /mnt/iscsi 这样通过 fstab 行挂载好。

这块磁盘也可以用 /dev/disk/by-path/ip-127.0.0.1:3260-iscsi-iqn.2026-09.io.labhub:sto-lun-0 来指代。/dev/sdX 这样的名称可能随每次启动变化,所以 fstab 中要写 UUID。没有 _netdev,启动时会在网络之前就尝试挂载。

开启自动登录

在目标端 iqn.2026-09.io.labhub:sto(门户 127.0.0.1)的节点记录中,把 node.startup 改为 automatic。

iscsiadm -m node -T -p <门户> --op update -n node.startup -v automatic。当前值可以在 iscsiadm -m node -T -p <门户> 的输出中找到。

以队列深度 1 测量

用 fio 在 /mnt/iscsi/fio.dat(大小 128MiB)上以 ioengine=libaio、direct=1、iodepth=1 测量 4KiB 随机读,持续 10 秒(runtime=10、time_based),并把 JSON 结果保存到 /root/sto/fio/qd1.json。

形如 fio --name=<名称> --filename=<文件> --size=128M --rw=randread --bs=4k --ioengine=libaio --direct=1 --iodepth=1 --runtime=10 --time_based --output-format=json --output=<文件>。去掉 direct=1,测的就是页缓存。

以队列深度 32 测量

在与第 6 步相同的文件、相同的条件下,只改为 iodepth=32 再测一次,并把 JSON 结果保存到 /root/sto/fio/qd32.json。

只改一个条件才能比较。只让名称、输出文件和 iodepth 不同。

从 JSON 中取数字与利特尔法则

从两个 JSON 中取出数字,在 /root/sto/fio/report.txt 中写五行:qd1_iops=、qd1_p99_us=、qd32_iops=、qd32_p99_us=(IOPS 为四舍五入的整数,p99 是把 clat_ns.percentile 的 99.000000 换算成微秒后四舍五入的整数),以及 qd32_little=(qd32 的 IOPS × 平均延迟 lat_ns.mean 换算成秒的值,保留到小数点后第一位)。

不要手工抄写数值,用 python3 读取 JSON 来计算。jobs[0]['read'] 下面有 iops、lat_ns、clat_ns。纳秒除以 1,000 是微秒,除以 10 亿是秒。如果 qd32_little 接近队列深度,就说明利特尔法则成立。