您好!欢迎来到爱源码

爱源码

热门搜索: 抖音快手短视频下载   

避坑指南:SPDK问题的分析过程 [企业网站源码]

  • 时间:2022-09-08 01:24 编辑: 来源: 阅读:308
  • 扫一扫,手机访问
摘要:避坑指南:SPDK问题的分析过程 [企业网站源码]
【前言】这是一个充满波折的问题分析。资料少,代码多,经验少,概念多。当内核态、客户端态、DIF、LBA、大页面内存、SGL、RDMA、NVME、SSD一起面对面的时候,问题是单点事故还是群体的无奈?为了加深记忆,也为了参考给人启示,特把这个问题分析过程记录下来。 【现象】同事L在项目中需要使用NVMF写盘,发现写盘失败,疯狂打印错误代码:虽然图中截取很少,但实际上一直在疯狂打印。 故障现象简单描述为:通过NVMF写盘失败,疯狂打印错误代码15;作为对比,写本地一切正常。 注意:这里的磁盘是指SSD磁盘。 目前实验室使用的型号是公司的V3版(HWE3xxx) 【解析】这里记录几个涉及到的基本缩写:习惯了缩写作为名词后,总是容易忽略后面更多的意思。分析问题需要对这些有更深的理解。刚开始我们对这些认识不深,数据求解流程不清晰,很难下手。 分析步骤(1)I/O发出时,通过改变I/O的大小和队列深度,发现在数据量较小时几乎没有问题,直接发出1M大小的I/O时必然出现。 因此可以推断,IO的大小与问题的发生密切相关。 直接跑业务核实问题太繁琐,很麻烦。把问题直接简化到一个服务器和一个请求者,发现结果就可以稳定重现。它们是:1。运行SPDK自带的app,nvmf_tgt程序,这就是nvmf的服务器;进入spdk目录后,配置2M页面;配置nvmf.conf配置文件,假设文件放在/opt/yy目录下;配置文件请参考附录;快跑。/app/nvmf _ TGT/nvmf _ TGT-c/opt/YY/nvmf . conf;2.您可以在两种模式下使用客户端。一个是SPDK附带的perf程序。路径是。/examples/nvme/perf/perf,将配置必要的参数;注意:系统还附带一个perf,不是系统自带的那个;Perf是测试工具,会随机产生大量的数据写入,可以验证问题的可修复性,但不利于问题的初步分析;一个是修改nvme目录下的helloworld程序(最初的版本,同事C提供的,几经改进,后来叫DEMO程序);代码见附录;因为都是在客户端状态下运行,所以开始调试非常方便。 同时两端启动调试模式,进行单步跟踪。发现错误代码是在异步模式下获取的,如图,函数名已经告知,这是解决问题的结果。调用来自这里,第383行:断点在第303行。根据堆栈信息(无有效信息,省略),错误代码可能来自SPDK的异步调用,也可能来自设施。翻看SPDK代码,发现根本没有15误码的设置,基本推断是SSD返回的。 根据初始信息,IO数据的大小会影响问题,IO数据小时不会出现。那么分界点在哪里呢?使用二分法在演示程序上进行尝试,发现当LBA的数目为15时,就是分界点。 那么,怎么用呢?单步跟踪,一个参数映入眼帘,命名空间的sectors_per_max_io的参数(NVME协议规范,一个SSD下有一个控件,有好几个命名空间) 通过修改此参数,您可以控制最后写入的光盘的大小。在演示程序上做实验,问题就消失了。 但是当IO大小和深度较大时,要么是内存错误代码不足,要么是错误仍然出现,在多盘场景下非常容易重现。 条件解给出如下:(1)修改上述位置;(2)发布服务时,要求限制IO的大小和发布磁盘的数量;在实际操作中,很难将其转化为单个磁盘,因为需要多个磁盘,这不是一个理想的处理方案。 另外发现不同版本磁盘的最小适应值是不一样的,最安全的值是7,但是接下来主要选取一个以15为安全线的磁盘来分析问题。 分析步骤(2)为了快速处理问题,尽量广泛求助。还有人遇到过这么明显的问题吗?上了hi3ms搜了谷歌,咨询了相关同事,哎,真的没有第二例了!更奇怪的是,在Intel的基线报告中,有大量IO数据NVMF测试,有正常结果。 为什么这里会有问题?区别:英特尔必须用英特尔的磁盘;这里是公司板块;是因为这个吗?硬件方面,理论上没有那么大的区别吧? 经过一番查询,发现硬盘无DIF格式化时NVMF是正常的。如果是DIF格式,即512+8格式,就会出现问题。那么,为什么英特尔没有问题呢?基本上,已经确定他们使用没有DIF的格式。同时发现,如果没有DIF,延迟会快一点,这很容易理解。 有疑问,但还是没有答案。为什么本地写不出现,而NVMF写出现?这是需要回答的最重要的问题。 作为基础,你需要简单了解一下NVME的写盘。 这个过程是异步的;写之前程序按照队列准备好数据(比如SGL),然后通知SSD,程序结束;然后SSD会把数据从机器里拿出来,写入磁盘。求解完成后,它会通知程序,程序会检查结果队列。 可以看出,现在的写盘主要是指数据按队列准备,后面部分由SSD设施解决。 有了这个基础,你就可以快速了解本地磁盘写了。在调用SPDK API之后,SPDK准备好队列,然后提交它。真正保存数据的是SSD里的控制器。 但是NVMF写作呢?毕竟中间有网络。是如何解决的? 为了方便分析,我们选择了变换DEMO,主要是因为perf比较复杂,随机LBA和数据量大对分析干扰很大。 演示程序中规定在LBA 0号提交数据,每次提交17条数据(总长度17*520=8840)。 那你为什么给数据块指定17?由于15及以下不会出问题,根据前面的分析,这个SSD的正常分割线是15,而16是2的4次方,2的n次方在一台电脑中太特殊了,所以选择了普通的17。 其次,保证其他地方一模一样。只是在初始化的时候,形成了两种模式,一种是本地写,一种是NVMF写。如图,直接手动更改红框中的参数。tr_rdma和tr_pcie可以在两种模式之间切换;这样做的目的是为了形成一个完整的对比,把所有能对齐的条件对齐,分析NVMF的哪一部分有问题。 初步一步追溯调用过程后,可以梳理出本地写和NVMF写的基本解决流程:本地写:在请求端,我们申请了1M大小的连续内存,块大小与4K大小对齐;通过调用SPDK的API将17个块(也就是1M大小只有17*520字节)写入磁盘;SPDK的API会调用PCIE模式接口(系统初始化时注册的回调函数,上图红框的参数决定了在门户初始化时会去PCIE对应的接口);准备数据队列,提交SSD写盘请求,返回;按照轮解完成的界面获取写盘成功通知;NVMF写:在请求端:(1)在请求端,申请1M大小的连续内存,块大小与4K大小对齐;(2)通过调用SPDK的API向磁盘写入17个块(也就是1M大小只有17*520字节);(3)SPDK的API会调用RDMA模式的接口(同上,初始化时注册了RDMA的回调函数,上图红框的参数决定了这里的调用会去RDMA对应的接口);(4)准备一个数据队列,通过RDMA网络传输到服务器,并返回;服务器端:(5)服务器的RDMA在轮询中收到数据到达的通知;(6)组装数据结构以方便内部API调用;(7)一路调用bdev、spdk、nvme的api到数据,地址转换成物理地址。最后,调用pcie的数据接口提交;(8)然后按规范提交门铃并返回;两边异步打印结果(提交请求后,只能等待异步打印结果):(9)请求方轮流求解已完成的接口,如果出现错误解,则打印;通过调试,我们可以看到错误码是15(10)服务器端轮循方案的接口。如果有错误,会有打印:反复向local和NVMF发送数据(以上0从17条数据开始),一对一的过程与参数对比(双屏提供更大的便利)。确实发现了很多相同点和不同点:(1)本地写的过程和NVMF写的请求端几乎一样,只是本地写的数据是提交的。(2) NVMF服务器有很长的调用栈(30层深),但是本地写进程根本不存在;(3)经过一系列调用,3)NVMF服务器最后来到像本地写盘,NVME _ Transport _ q pair _ Submit _ Request这样的函数调用;一个似乎很明显的结论是,RDMA上空的NVME实际上是,数据经过RDMA传输后,仍然是PCIE上空的NVME;;(4)本地写作时,只有一个SGL,这个SGL也只有一个SGE。在调用RDMA之前,NVMF的请求者也只有一个SGL,这个SGL也只有一个SGE。(NVMF服务器写盘之前,只有一个SGL,但是有两个SGE;在这个SGL;整个过程可以描述如下:如图:这是一个重要的发现,基本可以解释为什么处理方法1在某些场合是有效的(15的安全线内数据量小于8k,只保证一个SGL中有一个SGE),但不能解释少数场合的失败。 查了一下就清楚多了:RDMA在NVMF的请求端得到的数据是一个SGL包含一个SGE,RDMA之后,从NVMF的服务器端得到的数据是一个SGL包含两个sge。 至此,似乎肇事者基本上被“锁定”了,也就是RDMA!但是看了RDMA的数据和SSD的数据,发现一个SGL,一个SGE,两个sge根本是免费的。 虽然RDMA在收到数据后将一个SGE分成两个sge,有引发问题的嫌疑,但从数据的细节来看,似乎并不能直接引发问题。 为了验证在一个SGL中有多个sge是否是一个问题,演示再次进行了改革。在构造写数据之前,将数据分成多个sge,如图:首先我们尝试了NVMF,发现可以重现,和之前的NVMF没什么区别。接下来我们试了一下本地的,发现没有问题,就是疑点没有消除。 分析步骤(3)没有办法回到怀疑,只好拆了从头分析。在一次偶然的NVMF分发中,发现第二个SGE的地址在前面,第一个SGE的地址在后面,然后我们就密切关注了。即使在演示程序中,这个地址的顺序也绝对是随机的,大多数时候是顺序的,也有几次是颠倒的,但无论如何,一个 马上构造同样的形式,本地写,发现重新出现!这是一个“重要的发现”!也可以本地转载!几乎可以很顺利的推断出,NVMF是不是关键!那么RDMA的嫌疑就排除了!写的时候,如果多个sge的数据区完全连续,没有问题;如果多个sge的数据区不连续,就会出现问题。 那么,就很容易推导出问题了。目前的SSD不支持不连续SGE!是SSD吗?!然后 (此处省略一段。 ) 可以,SSD没有问题。问题是8192的长度。正确的应该是8320!820和8192是什么?892是512 * 16;820是520 * 16;你看,我之前都没有意识到刷屏的错误提醒。什么是“数据SGL长度无效”?这种模糊的提醒有很多种可能。可能是SGL的SGE个数不对,SGE的长度不对,SGL的length字段读写不对,寄存器不对,内存被践踏。 然而,事实是SGE的数据长度与块520的基本大小不一致!现在用的格式是DIF地区,512+8=520!那个提醒是告诉你数据块没有对齐,SGE的长度是无效的!当这个基本参数在各个点发生变化时,本地DEMO正常,DEMO的NVMF也正常。看来真相大白了。 然而,没过几分钟我就开心了。使用perf发出1M IO时,问题再次出现!分析步骤(4)仔细跟踪后发现,虽然问题重复出现,但屏幕没有以前多了。而且,通过一步发现,只要SGE数据的地址以FF000结尾,就会出现问题。 回头看这个地址,可以看到接收到数据后来自RDMA,偶尔会出现FF000的结尾,可以说明错误画面没有那么密集。 看来RDMA还是有问题~进一步分析可以发现,这些地址其实并不是RDMA临时分配的,而是从缓冲队列中获取的。 基本上可以说缓冲队列有很多选择,偶尔FF000末尾的那个会用来缓冲,只有这个地址会出问题。 那么,为什么这个地址有问题呢?还记得上一步吗?设置2M大页内存,SPDK基于DPDK,DPDK内存队列需要2M大页内存,最常用的是2m大页。 这些缓冲区是从DPDK的那些大页面中获取的,FF000接近2M边界,一般缓冲区使用没有问题。但是,SSD不接受跨大页面的空间。所以在准备提交队列的时候,如果有一个需要跨大页,就把这个SGE一分为二,以FF000结尾的地址只能存放4096个字节,所以一个SGE可以存放4096个字节,剩下的可以放在下一个SGE。 有针对性的做法是在获取地址之前加一个判断,如果是这样的地址就跳过。 修改!验证!屏气 但是,再一次出乎意料的,在大IO下用perf测试还是有问题!不要气馁,再战!打开日志(因为是异步的,测试了大量的数据,所以我们要在关键的地方添加日志,记录这些地址分配的细节。主要的地方是:提交请求的时候,看到上面的文件和代码行,就不贴代码了,一个是RDMA一开始接收数据的地方,一个是完成后的结果),继续分析。 你马上可以看到,还有一种地址分配异常,在SGE也会形成长度问题,如图:再次修改并屏蔽获取地址的位置,直接将两种类型合并跳过。 如图(471~475,另外需要配置nvmf_request_get_buffers函数跳过求解):修改!验证!所有用例都通过了测试!问题消失!提供第二种解决方案,按照上面的代码,就可以彻底处理问题了。 虽然问题解决了,跳过了一小部分特殊地址,有些浪费了,但总觉得这次改革太土了!可以消除问题,但是我感觉不舒服!有没有其他方法分析第(5)步?继续挖掘问题。 由于RDMA只使用缓冲队列,所以有一个地方分配了这个缓冲队列,但是分配的时候没有使用,显然有点浪费。那至少可以做到,所以这个数据分配的时候不要分配。 一路回来,终于找到申请的地方,但是很复杂。我们慢慢消化吧。 发现有一段描述很长,和地址分配很有关系。有了这些信息,再一步一步看分配缓冲区过程,大致猜测一下修改过程中的一个参数,即能影响到后面的求解过程。 红框1是代码的默认参数,改为红框2。红框2中的两个参数的含义是单个生产者和单个消费者,这与演示程序中的模式完全匹配。 修改!验证!当RDMA获得SGE地址时,它单向增长。 问题消失!一个参数就消除了问题,相比之下舒服多了!【概要】(1)问题的最终解决方案是:IOUnitSize的大小要在NVMF的配置文件中明确设置,与使用的块大小对齐整数倍。目前使用520块,建议设置为8320;创建内存池参数;上图中的一个参数就可以了。 (2)过程很曲折,但就是不放弃,跟着代码走,翻遍数据,大胆假设,仔细验证迭代,最终找到问题所在;如果你熟悉相关的概念和解决方案,你会节省很多时间。(3)最后,安利VSC,加上Remote–SSH,可以直接在Linux机器上呈现代码,进行可视化调试,随意穿梭代码,对这个分析有很大的帮助。附录:Nvmf的配置文件如下[global][Nvmf][transport]type RDMA in capsule datasize 16384 iou nitsize 8192[NVME]TransportID " tr type:PCIe traddr:0000:04:00.0 " NVME 0 TransportID " tr type:PCIe traddr:0000:05:00.0 " NVME 1 TransportID " tr type:PCIe traddr:0000:82:00。0 " nvme 2[子系统1]NQN nqn . 2020-05 . io . spdk:cnode 1听RDMA 192.168.80.4:5678 SN SPDK 001 MN SPDK _ Controller 1 allowanhost是命名空间nvme 0 n1 1[子系统2]NQN nqn . 2020-05 . io . spdk:cnode 2听RDMA 192 . 168 . 80 . 4:5678 SN spdk


  • 全部评论(0)
资讯详情页最新发布上方横幅
最新发布的资讯信息
【技术支持|常见问题】1556原创ng8文章搜索页面不齐(2024-05-01 14:43)
【技术支持|常见问题】1502企业站群-多域名跳转-多模板切换(2024-04-09 12:19)
【技术支持|常见问题】1126完美滑屏版视频只能显示10个(2024-03-29 13:37)
【技术支持|常见问题】响应式自适应代码(2024-03-24 14:23)
【技术支持|常见问题】1126完美滑屏版百度未授权使用地图api怎么办(2024-03-15 07:21)
【技术支持|常见问题】如何集成阿里通信短信接口(2024-02-19 21:48)
【技术支持|常见问题】算命网微信支付宝产品名称年份在哪修改?风水姻缘合婚配对_公司起名占卜八字算命算财运查吉凶源码(2024-01-07 12:27)
【域名/主机/服务器|】帝国CMS安装(2023-08-20 11:31)
【技术支持|常见问题】通过HTTPs测试Mozilla DNS {免费源码}(2022-11-04 10:37)
【技术支持|常见问题】别告诉我你没看过邰方这两则有思想的创意广告! (2022-11-04 10:37)

联系我们
Q Q:375457086
Q Q:526665408
电话:0755-84666665
微信:15999668636
联系客服
企业客服1 企业客服2 联系客服
86-755-84666665
手机版
手机版
扫一扫进手机版
返回顶部