在机器内部无法使用块设备,只能使用 iSCSI 协议获取块设备的数据。

介绍 iSCSI

因为本地盘无法满足需要的灵活性,通过网络将 SCSI 实现变成了 Internet SCSI (iSCSI) 。iSCSI 主要是通过 TCP/IP 的技术,将存储设备端通过 iSCSI target (iSCSI 标的) 功能,做成可以提供磁盘的服务器端,再通过 iSCSI initiator (iSCSI 初始化用戶) 功能,做成能够挂载使用 iSCSI target 的用户端,如此便能通过 iSCSI 协议来进行磁盘的使用。

iSCSI target:存储服务端,存放存盘或者 RAID 设备,为其他机器提供网络磁盘。

iSCSI initiator: 使用 target 的客户端,一般是服务器。需要安装一些软件,并且会连接到 iSCSI target的服务器。

iscsi 网络结构示意

iscsi 网络结构示意

安装与使用 iSCSI 客户端

安装

yum install -y iscsi-initiator-utils

发现服务器上都有哪些target

iscsiadm -m discovery -t st -p 192.168.68.2
192.168.68.2:3260,1 iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f
192.168.68.2:3260,1 iqn.2016.com.chenyudong.share.8888fb83-ab08-466b-89de-df1499b23a8e

iSCSI 有一套自己分享 target 名称定义,基本上,由 iSCSI 分享出來的 target 名称都是以 iqn 开头,意思是:『iSCSI Qualified Name (iSCSI 限定名称)』的意思。

iqn.yyyy-mm.<reversed domain name>:identifier
iqn.年年-月.域名的反写               :这个分享的target名称

挂载磁盘到本地

iscsiadm -m node -l -T iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f
Logging in to [iface: default, target: iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f, portal: 192.168.68.2,3260] (multiple)
Login to [iface: default, target: iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f, portal: 192.168.68.2,3260] successful.

查看磁盘

lsblk -o name,size,type,serial
NAME          SIZE TYPE SERIAL
sda         446.1G disk 6c0149825c2175f623f974a909bf7888
└─sda1         50G part
sdb           3.5T disk 6c0149825c2175f623f974a909c63f88
sdc            50G disk ISCSI_bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f

这样就可以像本地盘硬盘一样使用了。

卸载所有的 iSCSI 磁盘,删除 iSCSI 磁盘数据

当磁盘不再使用时,可以清除所有的磁盘。并且删除 iSCSI 的磁盘数据。

iscsiadm -m node --logout   # login 逆操作
iscsiadm -m node -o delete  # discovery 的逆操作

性能调优

本来打算通过上面的操作开心的使用了,结果发现磁盘的dd操作非常慢,才1MB/s的速度,距离以前的使用经验 70MB/s 有一段的差距。于是开启了参数调优的路程。

dd读取速度慢

一开始dd读取速度非常慢,fio 测试使用aio方法,速度符合预期。

因为dd是单线程读取,他们建议通过并行分段dd,通过 aio 的方法可以加大,感觉难度比较大。

read_ahead_kb

默认 /sys/block/sdx/queue/read_ahead_kb 观察到预读大小为128KB。当需要对大量的大文件进行读取时,可以通过适当调大此参数提升性能。

操作系统可探测到程序何时从文件或者磁盘中连续读取数据。在这种情况下,它可执行智能预读算法,因此用户可能会要求从磁盘中读取更多数据。因此当用户下一步尝试读取数据块时,它已经在操作系统的页缓存中了。可能的缺点是操作系统可能从磁盘中读取过多数据,这样就会占用页缓存直到高内存压力将其清除。如果有多个进程执行错误预读就会增加这种情况下的内存压力。

[root@minios_10_3_0_5 ~]# echo 128 > /sys/block/sdc/queue/read_ahead_kb
[root@minios_10_3_0_5 ~]# dd if=/dev/sdc of=./xxx bs=2M count=2000
2000+0 records in
2000+0 records out
4194304000 bytes (4.2 GB) copied, 154.452 s, 27.2 MB/s

[root@minios_10_3_0_5 ~]# echo 512 > /sys/block/sdc/queue/read_ahead_kb
[root@minios_10_3_0_5 ~]# dd if=/dev/sdc of=./xxx bs=2M count=2000
2000+0 records in
2000+0 records out
4194304000 bytes (4.2 GB) copied, 105.913 s, 39.6 MB/s

[root@minios_10_3_0_5 ~]# echo 4096 > /sys/block/sdc/queue/read_ahead_kb
[root@minios_10_3_0_5 ~]# dd if=/dev/sdc of=./xxx bs=2M count=2000
2000+0 records in
2000+0 records out
4194304000 bytes (4.2 GB) copied, 28.1032 s, 149 MB/s

[root@minios_10_3_0_5 ~]# echo 8192 > /sys/block/sdc/queue/read_ahead_kb
[root@minios_10_3_0_5 ~]# dd if=/dev/sdc of=./xxx bs=2M count=2000
2000+0 records in
2000+0 records out
4194304000 bytes (4.2 GB) copied, 21.9228 s, 191 MB/s

max_sectors_kb

默认将发送到磁盘的最大请求设定为 512 KB。这个可调参数可用来增大或者减小该值。最小值为逻辑块大小;最大值由 max_hw_sectors_kb 设定。有些 SSD 会在 I/O 大小超过内部删除块大小时性能下降。在此类情况下建议将 max_hw_sectors_kb 降低到删除块大小。您可以使用类似 iozone 或者 aio-stress 的 I/O 生成程序对此进行测试,记录大小可从 512 字节到 1 MB 不等。

一开始测试,后端的target server老是挂,经过定位,说是协商 iSCSI 挂载参数的时候数据传输值是 256K,现在这个磁盘的读操作是 512K,导致后端异常。建议修改为 256K 。

echo 256 > /sys/block/sdc/queue/max_sectors_kb

没想到,经过了一个qemu-img操作后,/sys/block/sdc/queue/max_sectors_kb变成了 512。导致读取了一点又把后端给搞异常了。

在网上查询 https://forum.proxmox.com/threads/troubles-iscsi-and-max_sectors_kb.25750/ 发现也有一个类似的案例,数值被udev给重置了。而我这也会被重置会默认值,因此修改这个值不太靠谱

修改配置文件 /etc/iscsi/iscsid.conf

# To specify the maximum number of data bytes the initiator can receive
# in an iSCSI PDU from a target, edit the following line.
#
# The value is the number of bytes in the range of 512 to (2^24-1) and
# the default is 262144
node.conn[0].iscsi.MaxRecvDataSegmentLength = 262144

MaxRecvDataSegmentLength 修改为 524288 (512 * 1204, 单位bit),可以解决问题,这样和 /sys/block/sdx/queue/max_sectors_kb 刚好配合在一起使用。后端没问题。但是通过修改系统默认值不太友好,只要修改单盘的配置就可以满足预期了。

对单盘调整 MaxRecvDataSegmentLength 值

如何只对单个盘生效呢? 尝试了好几次命令,没有成功,偶然在阅读 https://blog.csdn.net/msdnchina/article/details/72860154 这边中,发现了在挂载 iSCSI 磁盘的时候可以看到 debug 的login记录日志。 发现

iscsiadm -m discovery -t st -d8 -p 192.168.68.2
iscsiadm: ip 192.168.68.2, port -1, tgpt -1
iscsiadm: Max file limits 1024 4096
iscsiadm: updating defaults from '/etc/iscsi/iscsid.conf'
iscsiadm: updated 'discovery.sendtargets.iscsi.MaxRecvDataSegmentLength', '32768' => '32768'
iscsiadm: updated 'node.startup', 'manual' => 'automatic'
iscsiadm: updated 'node.leading_login', 'No' => 'No'
iscsiadm: updated 'node.session.timeo.replacement_timeout', '120' => '120'
iscsiadm: updated 'node.conn[0].timeo.login_timeout', '30' => '15'
iscsiadm: updated 'node.conn[0].timeo.logout_timeout', '15' => '15'
iscsiadm: updated 'node.conn[0].timeo.noop_out_interval', '5' => '5'
iscsiadm: updated 'node.conn[0].timeo.noop_out_timeout', '5' => '5'
iscsiadm: updated 'node.session.err_timeo.abort_timeout', '15' => '15'
iscsiadm: updated 'node.session.err_timeo.lu_reset_timeout', '30' => '30'
iscsiadm: updated 'node.session.err_timeo.tgt_reset_timeout', '30' => '30'
iscsiadm: updated 'node.session.initial_login_retry_max', '4' => '8'
iscsiadm: updated 'node.session.cmds_max', '128' => '128'
iscsiadm: updated 'node.session.queue_depth', '32' => '32'
iscsiadm: updated 'node.session.xmit_thread_priority', '-20' => '-20'
iscsiadm: updated 'node.session.iscsi.InitialR2T', 'No' => 'No'
iscsiadm: updated 'node.session.iscsi.ImmediateData', 'Yes' => 'Yes'
iscsiadm: updated 'node.session.iscsi.FirstBurstLength', '262144' => '262144'
iscsiadm: updated 'node.session.iscsi.MaxBurstLength', '16776192' => '16776192'
iscsiadm: updated 'node.conn[0].iscsi.MaxRecvDataSegmentLength', '262144' => '262144'
iscsiadm: updated 'node.conn[0].iscsi.MaxXmitDataSegmentLength', '0' => '0'
iscsiadm: updated 'node.conn[0].iscsi.HeaderDigest', 'None' => 'None'
iscsiadm: updated 'node.session.nr_sessions', '1' => '1'
iscsiadm: updated 'node.session.iscsi.FastAbort', 'Yes' => 'Yes'
iscsiadm: updated 'node.session.scan', 'auto' => 'auto'
iscsiadm: Looking for config file /var/lib/iscsi/send_targets/192.168.68.2,3260
iscsiadm: Lookiscsiadm: updated 'node.session.iscsi.FastAbort', 'Yes' => 'Yes'
iscsiadm: updated 'node.session.iscsi.InitialR2T', 'No' => 'No'
iscsiadm: updated 'node.session.iscsi.ImmediateData', 'Yes' => 'Yes'
iscsiadm: updated 'node.session.iscsi.FirstBurstLength', '262144' => '262144'
iscsiadm: updated 'node.session.iscsi.MaxBurstLength', '16776192' => '16776192'
iscsiadm: updated 'node.session.iscsi.DefaultTime2Retain', '0' => '0'
iscsiadm: updated 'node.session.iscsi.DefaultTime2Wait', '2' => '2'
iscsiadm: updated 'node.session.iscsi.MaxConnections', '1' => '1'
iscsiadm: updated 'node.session.iscsi.MaxOutstandingR2T', '1' => '1'
iscsiadm: updated 'node.session.iscsi.ERL', '0' => '0'
iscsiadm: updated 'node.session.scan', 'auto' => 'auto'
iscsiadm: updated 'node.conn[0].address', '' => '192.168.68.2'
iscsiadm: updated 'node.conn[0].port', '3260' => '3260'
iscsiadm: updated 'node.conn[0].startup', 'manual' => 'manual'
iscsiadm: updated 'node.conn[0].tcp.window_size', '524288' => '524288'
iscsiadm: updated 'node.conn[0].tcp.type_of_service', '0' => '0'
iscsiadm: updated 'node.conn[0].timeo.logout_timeout', '15' => '15'
iscsiadm: updated 'node.conn[0].timeo.login_timeout', '30' => '15'
iscsiadm: updated 'node.conn[0].timeo.auth_timeout', '45' => '45'
iscsiadm: updated 'node.conn[0].timeo.noop_out_interval', '5' => '5'
iscsiadm: updated 'node.conn[0].timeo.noop_out_timeout', '5' => '5'
iscsiadm: updated 'node.conn[0].iscsi.MaxXmitDataSegmentLength', '0' => '0'
iscsiadm: updated 'node.conn[0].iscsi.MaxRecvDataSegmentLength', '262144' => '262144'
iscsiadm: updated 'node.conn[0].iscsi.HeaderDigest', 'None' => 'None'
iscsiadm: updated 'node.conn[0].iscsi.IFMarker', 'No' => 'No'
iscsiadm: updated 'node.conn[0].iscsi.OFMarker', 'No' => 'No'
iscsiadm: found drec 192.168.68.2 3260
iscsiadm: rmd /var/lib/iscsi/send_targets/192.168.68.2,3260/iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f,192.168.68.2,3260,1,
default
iscsiadm: Removing config file /var/lib/iscsi/nodes/iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f/192.168.68.2,3260 iface id d
efault
iscsiadm: Removing config file /var/lib/iscsi/nodes/iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f/192.168.68.2,3260,1/default
iscsiadm: overwriting existing record
iscsiadm: node addition making link from /var/lib/iscsi/nodes/iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f/192.168.68.2,3260,
1 to /var/lib/iscsi/send_targets/192.168.68.2,3260/iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f,192.168.68.2,3260,1,defaulting for config file /var/lib/iscsi/send_targets/192.168.68.2,3260 config st_config.

....

iscsiadm: rec read looking for config file /var/lib/iscsi/nodes/iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f/192.168.68.2,326
0.
iscsiadm: rec read looking for config file /var/lib/iscsi/nodes/iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f/192.168.68.2,326
0,1/default.
iscsiadm: updated 'node.name', '' => 'iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f'
iscsiadm: updated 'node.tpgt', '-1' => '1'
iscsiadm: updated 'node.startup', 'manual' => 'automatic'
iscsiadm: updated 'node.leading_login', 'No' => 'No'
iscsiadm: updated 'iface.iscsi_ifacename', 'default' => 'default'
iscsiadm: updated 'iface.transport_name', 'tcp' => 'tcp'
iscsiadm: updated 'iface.vlan_id', '0' => '0'
iscsiadm: updated 'iface.vlan_priority', '0' => '0'
iscsiadm: updated 'iface.iface_num', '0' => '0'
iscsiadm: updated 'iface.mtu', '0' => '0'
iscsiadm: updated 'iface.port', '0' => '0'
iscsiadm: updated 'iface.tos', '0' => '0'
iscsiadm: updated 'iface.ttl', '0' => '0'
iscsiadm: updated 'iface.tcp_wsf', '0' => '0'
iscsiadm: updated 'iface.tcp_timer_scale', '0' => '0'
iscsiadm: updated 'iface.def_task_mgmt_timeout', '0' => '0'
iscsiadm: updated 'iface.erl', '0' => '0'
iscsiadm: updated 'iface.max_receive_data_len', '0' => '0'
iscsiadm: updated 'iface.first_burst_len', '0' => '0'
iscsiadm: updated 'iface.max_outstanding_r2t', '0' => '0'
iscsiadm: updated 'iface.max_burst_len', '0' => '0'
iscsiadm: updated 'node.discovery_address', '' => '192.168.68.2'
iscsiadm: updated 'node.session.iscsi.InitialR2T', 'No' => 'No'
iscsiadm: updated 'node.session.iscsi.ImmediateData', 'Yes' => 'Yes'
iscsiadm: updated 'node.session.iscsi.FirstBurstLength', '262144' => '262144'
iscsiadm: updated 'node.session.iscsi.MaxBurstLength', '16776192' => '16776192'
iscsiadm: updated 'node.session.iscsi.DefaultTime2Retain', '0' => '0'
iscsiadm: updated 'node.session.iscsi.DefaultTime2Wait', '2' => '2'
iscsiadm: updated 'node.session.iscsi.MaxConnections', '1' => '1'
iscsiadm: updated 'node.session.iscsi.MaxOutstandingR2T', '1' => '1'
iscsiadm: updated 'node.session.iscsi.ERL', '0' => '0'
iscsiadm: updated 'node.session.scan', 'auto' => 'auto'
iscsiadm: updated 'node.conn[0].address', '' => '192.168.68.2'
iscsiadm: updated 'node.conn[0].port', '3260' => '3260'
iscsiadm: updated 'node.conn[0].startup', 'manual' => 'manual'
iscsiadm: updated 'node.conn[0].tcp.window_size', '524288' => '524288'
iscsiadm: updated 'node.conn[0].tcp.type_of_service', '0' => '0'
iscsiadm: updated 'node.conn[0].timeo.logout_timeout', '15' => '15'
iscsiadm: updated 'node.conn[0].timeo.login_timeout', '30' => '15'
iscsiadm: updated 'node.conn[0].timeo.auth_timeout', '45' => '45'
iscsiadm: updated 'node.conn[0].timeo.noop_out_interval', '5' => '5'
iscsiadm: updated 'node.conn[0].timeo.noop_out_timeout', '5' => '5'
iscsiadm: updated 'node.conn[0].iscsi.MaxXmitDataSegmentLength', '0' => '0'
iscsiadm: updated 'node.conn[0].iscsi.MaxRecvDataSegmentLength', '262144' => '262144'
iscsiadm: updated 'node.conn[0].iscsi.HeaderDigest', 'None' => 'None'
iscsiadm: updated 'node.conn[0].iscsi.IFMarker', 'No' => 'No'
iscsiadm: updated 'node.conn[0].iscsi.OFMarker', 'No' => 'No'
iscsiadm: found drec 192.168.68.2 3260
iscsiadm: rmd /var/lib/iscsi/send_targets/192.168.68.2,3260/iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f,192.168.68.2,3260,1,
default
iscsiadm: Removing config file /var/lib/iscsi/nodes/iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f/192.168.68.2,3260 iface id d
efault
iscsiadm: Removing config file /var/lib/iscsi/nodes/iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f/192.168.68.2,3260,1/default
iscsiadm: overwriting existing record
iscsiadm: node addition making link from /var/lib/iscsi/nodes/iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f/192.168.68.2,3260,
1 to /var/lib/iscsi/send_targets/192.168.68.2,3260/iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f,192.168.68.2,3260,1,default

这里发现了,在 discovery 的时候,会生成配置文件。 因此修改挂载参数的时候应该在login之前,而不能在login之后修改。

通过

# 提前先发现 iSCSI 磁盘
# iscsiadm -m discovery -t st -p 192.168.68.2

# 修改 MaxRecvDataSegmentLength 参数
iscsiadm -m node -o update -T iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f -n node.conn[0].iscsi.MaxRecvDataSegmentLength -v 524288


# 然后挂载磁盘
iscsiadm -m node -l -T iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f


# 查看配置生效
vim /var/lib/iscsi/nodes/iqn.2016.com.chenyudong.share.bb7d09bc-c8d0-43b9-925a-3b2d2bd4349f/192.168.68.2,3260,1/default

node.conn[0].iscsi.MaxRecvDataSegmentLength = 524288

看到这个就生效了。 最后可以愉快的读取磁盘数据了。

参考

声明:未经允许禁止转载 东东东 陈煜东的博客 文章,谢谢。如经授权,转载请注明: 转载自东东东 陈煜东的博客

本文链接地址: Linux iSCSI 使用与一些性能优化 – https://www.chenyudong.com/archives/iscsi-use-and-performance-optimization.html