挂上 iSCSI LUN 并用 fio 测量
目标
在同一台 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 会消失。
步骤
- 把
/var/lib/sto/lun0.img(512MiB)创建为 fileio 后端存储lun0,作为 LUN 挂到目标端iqn.2026-09.io.labhub:sto的tpg1下,把这台 VM 的发起端名称加入 ACL,再用targetcli saveconfig保存。 - 发现(sendtargets)
127.0.0.1门户,并把输出保存到/root/sto/iscsi/discovery.txt。 - 登录目标端,使新磁盘在 TRAN 中显示为
iscsi,并把lsblk -o NAME,SIZE,TRAN,VENDOR,MODEL的输出保存到/root/sto/iscsi/lsblk.txt。 - 把 iSCSI 磁盘格式化为 ext4,在
/etc/fstab中写入包含 UUID= 和_netdev的一行,使其挂载到/mnt/iscsi,并现在就挂载好。 - 把节点记录中的
node.startup改为 automatic。 - 在
/mnt/iscsi/fio.dat(128MiB)上测量 4KiBrandread、libaio、direct=1、iodepth=1、10 秒,把 JSON 保存到/root/sto/fio/qd1.json。 - 在相同条件下只改为
iodepth=32再测一次,把 JSON 保存到/root/sto/fio/qd32.json。 - 在
/root/sto/fio/report.txt中写入qd1_iops=、qd1_p99_us=、qd32_iops=、qd32_p99_us=、qd32_little=五行,数值从 JSON 中计算得出。
参考
- 目标端:
targetcli ls、/backstores/fileio create、/iscsi create、…/tpg1/luns create、…/tpg1/acls create、saveconfig。 - 发起端:
iscsiadm -m discovery -t sendtargets -p 127.0.0.1、iscsiadm -m node -T <IQN> -p 127.0.0.1 --login、iscsiadm -m session。 - fio JSON:
jobs[0].read.iops、jobs[0].read.lat_ns.mean、jobs[0].read.clat_ns.percentile["99.000000"](纳秒)。 - 常见错误 1:在 fstab 中写
/dev/sdb,或漏掉_netdev。 - 常见错误 2:漏掉
direct=1,把页缓存速度当作磁盘速度上报。
用 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 接近队列深度,就说明利特尔法则成立。