查看原文
其他

为什么都说NFS读写性能差,如何进行优化?

SunnyZhang 数据存储张 2024-05-06

这里插播一个广告,本人的一本旧书《文件系统技术内幕》比较系统的介绍了文件系统的相关内容。目前还在热卖中,需要的同学可以择机购买,你懂的。

使用基于NFS协议存储系统的同学经常遇到的问题是在小文件比较多的情况下性能会比较差。小文件访问性能差本身是可以理解的,但是NFS确实是太差了。不知大家是否深层次分析过,为什么NFS访问小文件性能会这么差?

NFS文件系统与本地文件系统的差异在于多了一个网络传输的过程。因此,我们从网络传输方面下手,看看能不能获取一些线索。为了能够捕获协议的数据,我们向共享目录写入一个文件(本例为tgt.c,可以根据情况改变文件名称),具体命令如下所示。

         

dd if=tgt.c of=/mnt/test/sub1/sub2/sub3/sub4/sub5/test bs=1024 count=2

         

如下图是通过Wireshark抓取的网络通信的数据包,可以看出,NFS在访问文件的时候客户端与服务端有的交互除了WRITE之外,还有很多其它的交互,包括ACCESSLOOKUPSETATTR等。并且可以看出,这些请求的数量跟目录的深度是有关系,每一级目录都会进行LOOKUP和ACCESS操作,这就是NFS在访问小文件的时候性能差的一个主要原因。

         

我们具体分析一下这个过程,稍微简化一下,如图所示。可以看出,对于每一级组件(component),客户端都会发送一个LOOKUP指令和一个ACCESS指令。这两个指令是干什么的呢?

 

我们可以看一下协议文档,以NFSv3为例,其文档为RFC1813。如下图是LOOPUP例程的功能描述,通过该描述可以看出LOOKUP的功能是按照名称搜索目录中的项目,成功的情况下返回一个句柄。从功能描述来看,这个指令也是很必要的,我们在访问一个文件的时候,显然必须要确保路径是真是存在的。所以,客户端要针对每一个组件发送一条LOOKUP指令来确保整条路径的存在性。

另外一个指令是ACCESS,该指令的描述如下图所示,其主要作用时确认访问的权限。也就是当我们访问文件的时候,客户端需要向服务端逐组件的确认该用户是否有权限访问当前目录。如果没有相应的权限,当然不允许访问了。

具体的权限很多,如协议中的定义,包括读、查询、修改、扩展、删除和执行等操作。服务端会进行权限的确认操作,如果确认失败则客户端会禁止应用的访问请求。所以,对于一个长路径进行逐级的确认也是必须的。

由上述分析可以看出,对于一次写操作,客户端文件系统需要经过与服务端10多次的通信交互,访问性能自然会差很多。基于上述分析,如果向提升性能,显然应该减少客户端与服务端交互的次数。如果能够绝对信任服务端的文件路径,一个最直接的方法是修改客户端的逻辑,避免多级查询。但是这种方法门槛有点高,而且有一点的隐患。在不修改代码的情况下,我们可以遵循如下原则来一定程度上提升性能。

核心原则是减少客户端与服务端的交互次数,因此我们在访问文件的时候应该尽量保持文件的打开状态,避免重复打开关闭文件,这样NFS全路径的逐级检查。这种方法对NFSv4以后的版本适用,但对于NFSv3及以前的版本并不适用,因为他们是无状态的。即使你在客户端不关闭文件,在服务端访问完数据后也是关闭的。

减少目录层级,前面描述已经很清楚了。NFS会检查每一级目录,而且每一级目录的检查需要客户端与服务端交互至少2次。如果我们尽量减少目录层级,那么可以最大化的降低客户端与服务端交互的次数。

避免超大目录,也就是一个目录中文件的数量不要太多。服务端的有些文件系统变量目录像的效率并不高,当目录项太多时,查找将非常耗时。

尽量使用大文件,而非小文件。似乎这个并不好实现,因为文件的大小是业务决定的,我们似乎很难控制文件的大小。但是,如果是自己开发的应用程序, 在保存数据的时候尽量以大文件的形式,而非小文件的形式,这对性能是有益的。

回头想一下,NFS的性能问题很早就暴露了,难道NFSv4、NFSv4.1和NFSv4.2发展这么多年就没有解决吗?我们后续会分析更新版本NFS协议,看看他们在性能方面做了哪些优化。

         

继续滑动看下一个
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存