作者简介
万群,Intel存储软件工程师 主要从事SPDK软件测试工作
目录
一. 系统配置(包括target端和host端)
二. NVME/TCP的ADQ特性在target端的配置实例
三. NVME/TCP的ADQ特性在host端的配置实例
四. 故障排除
五. 参考文献
提示
由于篇幅限制,这篇文章是CVL网卡的ADQ特性在SPDK的NVMF测试中的应用实例 - 上篇[1]的续篇,所有操作系统、内核以及相应工具包的安装都可以参照此篇文章的上篇CVL网卡的ADQ特性在SPDK的NVMF测试中的应用实例 - 上篇
一
系统配置(包括target端和host端)
提示:这里很多配置在系统重启之后需要重新配置,你可以参照你的操作系统进行持久配置或者启动之后运行脚本。
系统优化
注意:这里的系统优化也会依赖于硬件和软件环境和不同的负载。这里的优化在重载系统和快速IO系统中比较明显,但是也只是在有限的硬件和软件系统中测试过。在我们的环境(Fedora29)里的配置步骤如下:
1.禁用防火墙
#service firewalld stop; systemctl mask firewalld |
2.禁用SELinux
#vim /etc/selinux/config 修改SELINUX=enforcing为SELINUX=disabled |
3.启用latency-performance低延迟的性能模式
#yum install -y tuned #tuned-adm profile latency-performance |
使用以下命令查看配置的结果
#cat /etc/tuned/active_profile 结果为latency-performance #cat /etc/tuned/profile_mode 结果为manual |
4.设置CPU调整频率模式为performance
#cpupower frequency-set -g performance |
5.禁用irqbalance服务
#systemctl stop irqbalance |
6.配置操作系统参数来处理增加的数据包速率
a.增加socket侦听队列的连接请求的最大数目,该配置再重启后会失效,参数值重新恢复成默认的128
#sysctl -w net.core.somaxconn=4096 |
b.当特定接口接收数据包的速度快于内核处理数据包的速度时,增加允许排队的最大数据包数目
#sysctl -w net.core.netdev_max_backlog=8192 |
c.指定所能接受SYN同步包的最大客户端数量
#sysctl -w net.ipv4.tcp_max_syn_backlog=16384 |
d.增加发送和接受套接字缓冲区大小的最大值
#sysctl -w net.core.rmem_max=16777216 #sysctl -w net.core.wmem_max=16777216 |
e.确定TCP栈应该如何反映内存使用,每个值的单位都是内存页(通常是4KB)。第一个值是内存使用的下限;第二个值是内存压力模式开始对缓冲区使用应用压力的上限;第三个值是内存使用的上限。在这个层次上可以将报文丢弃,从而减少对内存的使用。示例中第一个值为786432*4/1024/1024=3G,第二个值为1019584*4/1024/1024=3.9G,第三个值为16777216*4/1024/1024=64G
#sysctl -w net.ipv4.tcp_mem=”764688 1019584 16777216” |
f.自动调优定义socket使用的内存,第一个值是为socket接收/发送缓冲区分配的最少字节数;第二个值是默认值(该值会被rmem_default/wmem_default覆盖),缓冲区在系统负载不重的情况下可以增长到这个值;第三个值是接收/发送缓冲区空间的最大字节数(该值会被rmem_max/wmem_max覆盖)
#sysctl -w net.ipv4.tcp_rmem=”8192 87380 16777216” #sysctl -w net.ipv4.tcp_wmem=”8192 65536 16777216” |
g.允许分配所有的物理内存
#sysctl -w vm.overcommit_memory=1 |
h.禁用透明大页
#echo never > /sys/kernel/mm/transparent_hugepage/enabled |
以上所有系统优化的步骤总结在以下脚本里(除了禁用SELinux的命令)
service firewalld stop systemctl mask firewalld tuned-adm profile latency-performance cat /etc/tuned/active_profile cat /etc/tuned/profile_mode cpupower frequency-set -g performance systemctl stop irqbalance sysctl -w net.core.somaxconn=4096 sysctl -w net.core.netdev_max_backlog=8192 sysctl -w net.ipv4.tcp_max_syn_backlog=16384 sysctl -w net.core.rmem_max=16777216 sysctl -w net.core.wmem_max=16777216 sysctl -w net.ipv4.tcp_mem="764688 1019584 16777216" sysctl -w net.ipv4.tcp_rmem="8192 87380 16777216" sysctl -w net.ipv4.tcp_wmem="8192 65536 16777216" sysctl -w vm.overcommit_memory=1 echo never > /sys/kernel/mm/transparent_hugepage/enabled |
网卡优化
1.卸载并重新加载ice驱动以清除之前所有TC配置
#modprobe -r ice #modprobe ice |
2.启用硬件TC卸载功能
#ethtool -K $iface hw-tc-offload on |
3.配置flower director,配置’channel inline’
#ethtool –set-priv-flags $iface channel-inline-flow-director on |
4.禁用LLDP
#ethtool –set-priv-flags $iface fw-lldp-agent off |
5.禁用channel packet inspection optimization
#ethtool –set-priv-flags $iface channel-pkt-inspect-optimize off |
6.启用繁忙的轮询专用标志(这里要求ice版本1.1.0以上)
#ethtool –set-priv-flags $iface channel-pkt-clean-bp-stop on #ethtool –set-priv-flags $iface channel-pkt-clean-bp-stop-cfg on |
7.验证配置
#ethtool -k $iface | grep “hw-tc” #ethtool –show-priv-flags $iface |
输出范例如下
link-down-on-close : off fw-lldp-agent : off channel-inline-flow-director : on channel-pkt-inspect-optimize : off channel-pkt-clean-bp-stop : on channel-pkt-clean-bp-stop-cfg: on vf-true-promisc-support : off mdd-auto-reset-vf : off legacy-rx : off |
以上所有网卡优化的步骤总结在以下脚本里:
iface=#ifacename modprobe -r ice modprobe ice ethtool -K $iface hw-tc-offload on ethtool --set-priv-flags $iface channel-inline-flow-director on ethtool --set-priv-flags $iface fw-lldp-agent off ethtool --set-priv-flags $iface channel-pkt-inspect-optimize off ethtool --set-priv-flags $iface channel-pkt-clean-bp-stop on ethtool --set-priv-flags $iface channel-pkt-clean-bp-stop-cfg on ethtool -k $iface | grep "hw-tc" ethtool --show-priv-flags $iface |
二
NVME/TCP的ADQ特性在target端的配置实例
在NVMe/TCP target端配置ADQ
本章节详细介绍如何配置NVME/TCP并使能ADQ特性。“[ADQ]”表示ADQ相关配置,当测试baseline的TCP性能时,不能够配置相应的命令。这里不要求ADQ既配置在target端也配置在host端。任何配置了ADQ的TCP端都可以和没有配置ADQ的TCP端通信。
1.[ADQ]创建TC
# tc qdisc add dev $iface root mqprio num_tc 2 map 0 1 queues $num_queues_tc0 $num_queues_tc1@$num_queues_tc0 hw 1 mode channel # tc qdisc add dev $iface ingress |
2.[ADQ]创建TC filter,这里NVMe/TCP target使用dst_port,NVMe/TCP host使用src_port。
# tc filter add dev $iface protocol ip ingress prio 1 flower dst_ip ${ipaddrserver}/32 ip_proto tcp dst_port $app_port skip_sw hw_tc 1 |
3.[ADQ]验证TC配置正确性
验证TC正确地创建了 # tc qdisc show dev $iface 验证TC filter # tc filter show dev $iface ingress |
4.将tx的终端审核率设置为静态值,并关闭rx的中断审核率
#ethtool --coalesce ${iface} adaptive-rx off rx-usecs 0 #ethtool --coalesce ${iface} adaptive-tx off tx-usecs 500 |
5.运行ice目录中的set_irq_affinity脚本
#${pathtoicepackage}/scripts/set_irq_affinity local $iface |
6.[ADQ]运行ice目录中的set_xps_rxqs脚本
#${pathtoicepackage}/scripts/set_xps_rxqs $iface |
7.设置busy_read值
# sysctl -w net.core.busy_read=1 |
以上所有nvmf target端ADQ配置可以总结为以下脚本:
iface=$ifacename pathtoicepackage=$patch_to_ice_driver num_queues_tc0=2 num_queues_tc1=8 cpumask="0x1F" ipaddrserver=$ipaddrserver app_port=4420 ifup $iface sleep 5 tc qdisc add dev $iface root mqprio num_tc 2 map 0 1 queues $num_queues_tc0 $num_queues_tc1@$num_queues_tc0 hw 1 mode channel tc qdisc add dev $iface ingress tc filter add dev $iface protocol ip ingress prio 1 flower dst_ip ${ipaddrserver}/32 ip_proto tcp dst_port $app_port skip_sw hw_tc 1 tc qdisc show dev $iface tc filter show dev $iface ingress ethtool --coalesce ${iface} adaptive-rx off rx-usecs 0 ethtool --coalesce ${iface} adaptive-tx off tx-usecs 500 ${pathtoicepackage}/scripts/set_irq_affinity local $iface ${pathtoicepackage}/scripts/set_xps_rxqs $iface sysctl -w net.core.busy_read=1 |
在NVMe/TCP target端配置SPDK
1.切换到spdk目录
#cd spdk |
2.为了获取更好的性能,建议将target使用的CPU限制为目标nvme设备的NUMA节点
#./scripts/setup.sh status 输出示例如图所示 BDF Vendor Device NUMA Driver Device name NVMe devices 0000:d9:00.0 8086 0a54 1 uio_pci_generic - 0000:d8:00.0 8086 0a54 1 uio_pci_generic - 0000:5e:00.0 8086 0a54 0 uio_pci_generic - 0000:5f:00.0 8086 0a54 0 uio_pci_generic - #lscpu 输出示例如图所示 NUMA node0 CPU(s): 0-27,56-83 NUMA node1 CPU(s): 28-55,84-111 |
3.启动nvmf_tgt应用
#./build/bin/nvmf_tgt -m 0xAAAA |
4.设置target端传入连接的轮询间隔
#./scripts/rpc.py nvmf_set_config -r 10000 |
5.是用rpc命令nvmf_create_transport来创建一个transport(包括TCP, RDMA, FC等,这里指定为TCP),-y 1选项只适用于使能ADQ的情况
#./scripts/rpc.py nvmf_create_transport -t tcp -q 128 -p 64 -c 4096 -I 131072 -u 131072 -a 128 -b 32 -n 4096 -y 1 这里每个参数的意义 -t tcp #transport是tcp -q 32 #最大qd -p 64 #每个session最大queue -c 4096 #胶囊(incapsule)数据大小为4096 -i 131072 #最大IO大小 -u 131072 #IO单位大小 -a 128 #最大AQ深度 -b 32 #缓冲大小 -n 4096 #transport可用的缓冲池数据 -y 1 #[ADQ]套接字优先级 |
6.配置NVMe bdev属性执行admin queue轮询异步事件的频率(-p选项),-n指定每次I/O尝试的次数,-a指定当超时(-t选项)采取的行动
#./scripts/rpc.py bdev_nvme_set_options -n 4 -t 0 -a none -p 10000 |
7.设置transport属性来使能posix的placement ID(SPDK20.10之后的版本)
#./scripts/rpc.py sock_impl_set_options –enable-placement_id -I posix |
8.初始化subsystem
#./scripts/rpc.py framework_start_init |
9.创建subsystem
#./scripts/rpc.py nvme_create_subsystem nqn.2019-o6.io.spdk:cnode1 |
10.允许任何host访问target端的subsystem
#./scripts/rpc.py nvmf_subsystem_allow_any_host -e nqn.2019-06.io.spdk:cnode1 |
11.为susbystem添加监听地址,端口号和transport
#./scripts/rpc.py nvmf_subsystem_add_listener -t tcp -a ${ipaddrserver} -s ${app_port} nqn.2019-06.io.spdk:cnode1 |
12.列出target端可用的NVMe设备
#./scripts/setup.sh status |
13.为每个NVMe设备创建bdev controller
#./scripts/rpc.py bdev_nvme_attach_controller -b nvme1 -t pcie -a 000:8a:00.0 |
14.为每个nvme bdev添加namespace
#./scripts/rpc.py nvmf_subsystem_add_ns nqn.2019-06.io.spdk:cnode1 nvme1n1 |
15.查看所有配置的subsystem和transport
#./scripts/rpc.py nvmf_get_subsystems #./scripts/rpc.py nvmf_get_transports |
以上所有target端的SPDK配置可以总结为以下脚本
ipaddrserver=$ipaddrserver app_port=$app_port cpumask="0x1F" pathtospdk=$path_to_spdk nvmepciaddr=$nvme_pci_addr nqnname=$nqn_name nvmename1=$nvme_name num_queues_tc1=8 cd $pathtospdk HUGEMEM=32768 ./scripts/setup.sh ./scripts/setup.sh status nohup ./build/bin/nvmf_tgt --wait-for-rpc -m $cpumask 2>&1 > nvmf_tgt.log & sleep 10 ./scripts/rpc.py nvmf_set_config -r 10000 ./scripts/rpc.py bdev_nvme_set_options -n 4 -t 0 -a none -p 100000 ./scripts/rpc.py sock_impl_set_options --enable-placement_id -i posix ./scripts/rpc.py framework_start_init ./scripts/rpc.py nvmf_create_transport -t tcp -q 128 -p 64 -c 4096 -i 131072 -u 131072 -a 128 -b 32 -n 4096 -y 1 ./scripts/rpc.py nvmf_create_subsystem ${nqnname} ./scripts/rpc.py nvmf_subsystem_allow_any_host -e ${nqnname} ./scripts/rpc.py nvmf_subsystem_add_listener -t tcp -a ${ipaddrserver} -s ${app_port} ${nqnname} ./scripts/rpc.py bdev_nvme_attach_controller -b ${nvmename1} -t pcie -a ${nvmepciaddr} ./scripts/rpc.py nvmf_subsystem_add_ns ${nqnname} "${nvmename1}n1" ./scripts/rpc.py nvmf_get_subsystems ./scripts/rpc.py nvmf_get_transports |
完成测试之后的步骤
1.从target的控制器移除所有bdev
#./scripts/rpc.py bdev_nvme_detach_controller ${bdev} |
2.停止nvmf_tgt
#ctrl+c |
3.切换回到kernel驱动
#./scripts/setup.sh reset |
三
NVME/TCP的ADQ特性在host端的配置实例
在NVMe/TCP host端配置ADQ
1.[ADQ]创建TC
# tc qdisc add dev $iface root mqprio num_tc 2 map 0 1 queues $num_queues_tc0 $num_queues_tc1@$num_queues_tc0 hw 1 mode channel #tc qdisc add dev $iface ingress |
2.[ADQ]创建TC filter
# tc filter add dev $iface protocol ip ingress prio 1 flower dst_ip ${ipaddrhost}/32 ip_proto tcp src_port $app_port skip_sw hw_tc 1 |
3.[ADQ]验证所创建的TC
# tc qdisc show dev $iface # tc filter show dev $iface ingress |
4.将tx的终端审核率设置为静态值,并关闭rx的中断审核率
# ethtool --coalesce ${iface} adaptive-rx off rx-usecs 0 #ethtool --coalesce ${iface} adaptive-tx off tx-usecs 500 |
5.运行ice目录中的set_irq_affinity脚本
# ${pathtoicepackage}/scripts/set_irq_affinity local $iface |
6.运行ice目录中的set_xps_rxqs脚本
# ${pathtoicepackage}/scripts/set_xps_rxqs $iface |
7.设置busy_read值
# sysctl -w net.core.busy_read=1 |
以上所有host端的ADQ配置可以总结为以下脚本
iface=$iface pathtoicepackage=$path_to_ice_package num_queues_tc0=2 num_queues_tc1=16 cpumask="0x1F" ipaddrserver=$ipaddr_server ipaddrhost=$ipaddr_host app_port=$app_port tc qdisc add dev $iface root mqprio num_tc 2 map 0 1 queues $num_queues_tc0@0 $num_queues_tc1@$num_queues_tc0 hw 1 mode channel tc qdisc add dev $iface ingress tc filter add dev $iface protocol ip ingress prio 1 flower dst_ip ${ipaddrhost}/32 ip_proto tcp src_port $app_port skip_sw hw_tc 1 tc qdisc show dev $iface tc filter show dev $iface ingress ethtool --coalesce ${iface} adaptive-rx off rx-usecs 0 ethtool --coalesce ${iface} adaptive-tx off tx-usecs 500 ${pathtoicepackage}/scripts/set_irq_affinity local $iface ${pathtoicepackage}/scripts/set_xps_rxqs $iface sysctl -w net.core.busy_read=1 |
在NVMe/TCP host端配置SPDK
1.通过tcp transport发现target端的NVMe设备
#modprobe nvme_tcp #nvme discover -t tcp -a $ipaddrserver -s $app_port 类似的运行结果如下 Discovery Log Number of Records 1, Generation counter 6 =====Discovery Log Entry 0====== trtype: unrecognized adrfam: ipv4 subtype: nvme subsystem treq: not required portid: 0 trsvcid: 4420 subnqn: nqn.2019-06.io.spdk:cnode1 traddr: 192.168.4.9 |
2.分配huge page并把NVMe设备从内核驱动绑定到用户态驱动
# HUGEMEM=32768 ./scripts/setup.sh |
3.运行fio命令
#fio fio.job fio.job文件示例如下所示 [global] ioengine=<path_to_spdk>/build/fio/spdk_bdev spdk_json_conf=<path_to_spdk_bdev.json> ramp_time=10 runtime=100 numjobs=1 iodepth=1 thread=1 group_reporting=1 direct=1 norandommap=1 time_based=1 percentile_list=99:99.9:99.99 iodepth_batch_complete_min=1 iodepth_batch=8 iodepth_batch_complete_max=32 cpus_allowed_policy=split cpus_allowed=0-27 filename=Nvme0n1 [4k_rd] bs=4k rw=randread spdk_bdev.json文件示例如下所示 {"subsystems": [ { "subsystem": "bdev", "config": [ { "params": { "name": "Nvme0", "trtype": "tcp", "traddr": "192.168.4.9", "adrfam": "ipv4", "trsvcid": "4420", "priority": "1", "subnqn": "nqn.2019-06.io.spdk:cnode1" }, "method": "bdev_nvme_attach_controller" } ] } ] } |
四
故障排除
网络问题
注意当你下载所需的软件或者kernel文件的时候遇到网络问题,可以尝试打开代理
五
参考文献
[1] CVL网卡的ADQ特性在SPDK的NVMF测试中的应用实例 - 上篇
转载须知
推荐阅读
CVL网卡的ADQ特性在SPDK的NVMF测试中的应用实例 - 上篇
你的一个“分享”
让我们之间的距离又近了一步
转载:https://blog.csdn.net/weixin_37097605/article/details/110508233