根笔者最近在SPDK优化上的工作,下面总结了一些可以提升性能的优化点。

永远保持高队列深度

对于NVME SSD和RDMA这种基于completion queue/submittion queue 硬件机制的设备,就应该根据硬件队列执行的特性,始终保持队列中有物理队列深度这么多的请求在跑,这样才可能榨干硬件性能。

数据结构

在IO路径上如果你需要缓存一段请求,并且只只需要操作它的头和尾。如果是基于C++ 模板,切记:不要使用双向链表,而应该用queue。

内存拷贝

大厂的很多基础库中,期望的浅复制,在有些情况下可能包括拷贝操作,针对这个需要仔细筛查。特别是在IO路径上不同的函数参数传递
的过程中,尽量用指针传递。

内存分配

IO路径上频繁的内存分配会影响性能,特别是对 spdk 提供的内存分配函数。一种思路是预估请求的多少,预先分配好。

占时高的函数

读写程序跑起来的时候,可以用perf 跟踪并记录到热点函数,然后分析
是否符合预期,对于不符合预期的想办法把它的时间占比降下来。笔者通过perf 发现,对一个std::map结构进行判空比较占据了超过5%的比例,后来通过把这个判断放到其他条件之后,性能得到一定改善。

IO路径上尽量避免锁,因为:
对于自旋锁:它很耗CPU;对于互斥锁:它又很可能导致频繁的上下文切换。进而整体上影响性能。

去掉不必要的打印、睡眠、乘法、除法

把IO路径上乘、除、模等需要比较多CPU周期的操作,改造成位的操作;把冗余的日志和睡眠减少乃至都去掉,也会对性能有提升。

内连函数、编译选项 -O 优化、热点函数汇编、使用高级指令

这个是常见的公共的优化方法,常见于计算密集型的应用。

通过综合上面的措施,笔者把4K粒度的读写从2~3万IOS优化到45万左右IOPS。当然在多个线程并发、队列深度不同的情况下,是否还能保持如此高的性能还有待验证。