首页
学习
活动
专区
工具
TVP
发布

超算系统需要躲开的NFS大坑

花掉大笔经费建设的超算机群为什么存储性能这么差?怎么向领导交待?

存储产品那么多,听起来都很好,但谁都不说里面都什么坑,真是难选。

我只想安静地写程序做科研,却被存储设备折磨得头疼,浪费时间,怎么避开那些大坑呢?

在NFS环境上测试MPI程序,并行读写同一个文件怎么结果不对?

编程语言、操作命令很容易学会,但背后的原理不清楚。简单明了的参考资料好难找,一上来就用一堆代码讲解,看起来费时费力。

这篇文章试图解决这几个问题。着急的读者可以只看结论,然后转发了事:-)

超算应用的并行读写模式与常用存储测试用例差别很大,从而导致存储设备的演示测试性能高,而实际应用性能差。

MPI-IO的开发单位说了,决不推荐NFS存储,性能差。NFS协议为串行读写设计,多个客户端之间相互不协调,导致负载不均、延时增大、元数据开销增多等后果(能比正常带宽低80%)。从原理上看,非对称架构的存储产品更适合超算软件的MPI并行IO。

在NFS上并行读写同一个文件时,一定要用NFS v3版本的客户端,并在挂载的时候加上noac选项,否则文件数据可能不正确。

如果串行读写文件,可用NFS存储;如果并行读写文件,用NFS存储要能忍受它的低性能。Lustre等非对称文件系统并行读写性能较高。

本文力求浅显易懂,说清NFS存储并行读写性能差的背后原因。

存储的功能、性能指标很多,超级计算机看重哪些指标呢?

存储的可靠性永远第一位,不能丢数据、不能频繁故障。第二位的就是读写性能,带宽越高越好。克隆、备份、远程复制等功能只是锦上添花,不太重要。

流行的存储产品就可以认为足够稳定,读写性能则强烈地依赖于存储的接口协议。

市面上的文件系统很多,但存储接口协议不多:标准的NFS协议和私有协议。NFS协议应用广泛,计算节点上安装的NFS客户端也由专业机构开发,与操作系统的兼容性好。为了得到更好的性能,Lustre这样的文件系统选择自行设计私有协议,自行开发私有客户端;私有客户可能对操作系统的版本有一定要求,更新速度也慢,兼容性较差。

标准的并不总是好的,对超算机群来说,NFS文件系统就是噩梦,具体表现如下:

负载不均

小型NFS文件系统只有1个或2个存储服务器(或称为存储机头),不在本文讨论范围内。

超算机群的数据量很大,需要使用分布式文件系统(3个及以上存储服务器)。

NFS协议要求每台计算服务器都在挂载一个NFS服务器,见图1,一旦挂载成功,就不再改挂其它NFS服务器;通常在计算服务器开机的时候执行挂载动作,关机的时候再断开连接。

超算机群的计算服务器的数量通常远远多于NFS服务器的数量,例如5:1或10:1甚至更高,因此多台计算服务器会挂载同一台NFS服务器。为获得最好性能,计算服务器与NFS服务器之间的对应关系要保持均衡,见图1,计算服务器C和C3都挂载NFS服务器S,C1和C4都挂载S1。

图 1

假设一个超算机群有100台计算服务器,3台NFS服务器。存储产品的域名挂载功能通常能使每台NFS服务器被33或34台计算服务器挂载,负载相当均衡。

机群上运行的计算任务,绝大部分不会占用超过一半的计算服务器(否则这个机群就该扩容了)。假设一个计算任务占用8台计算服务器,这8台计算服务器是由作业调度软件分配的,有一定的随机性。最坏的情况下,这8台计算服务器挂载的都是同一台NFS服务器。那么8台计算服务器上的MPI集合IO操作都会压到1台NFS服务器上,而另外2台NFS服务器空闲,浪费了2/3的IO潜力。

这样的极端不均衡情形出现的几率也许不太大,但中等不均衡状况出现的几率相当大,例如4/2/2台计算服务器分别挂载NFS服务器C/ C1/ C2。MPI-IO中的集合IO结束时会有一个进程间同步,因此,聚合IO操作的速度取决于最慢进程的速度,进而取决于负载最重的NFS服务器C的速度。

NFS的挂载机制决定了负责不均不可避免:一旦挂载成功,客户端中途不会自动改变所挂载的NFS服务器。想中途更改的话,要么管理员手动改变NFS客户端与NFS服务器之间的挂载关系,要么编写脚本根据作业情况自动挂载。中途更改会带来3个严重问题:

1. 同一台计算服务器上可能运行着两个或两个以上的作业,为了一个作业而更改挂载关系,会使其它作业中断;

2. 每个NFS客户端更改挂载关系不是瞬间完成的,通常会花费几秒钟甚至1分钟,频繁更改会给存储设备带来压力;

3. 超算机群上通常同时运行着很多个作业,找出一个对所有作业都均衡的挂载方案也是不一件容易的事情。

而Lustre等非对称文件系统只挂载元数据服务器,不挂载IO服务器,Lustre客户端可以直接访问任意的IO服务器,因此不存类似的负载不均问题。

数据中转耗时多

NFS客户端读写一个文件的时候只能向已挂载的NFS服务器发起请求,因为文件数据被打散分布在多个NFS服务器上,所以NFS服务器上会有一个中转操作,见图2。

图 2

图2中,计算服务器C需要向NFS服务器S写入3个连续数据块D~D2,而数据块D~D2应该分别放置在NFS服务器S~S2上。因此,S需要在缓冲区暂存数据D~D2,将D写入自己的本地硬盘,通过网络将D1和D2分别发送给NFS服务器S1和S2。等D~D2都正确地写入硬盘,S才会向C返回写成功的信号。

不妨将计算服务器与NFS服务器之间的数据流量称为外部流量,将NFS服务器之间的数据流量称为内部流量。显然图2中的外部流量为9(9个数据块),内部流量为6。容易推算,NFS服务器的数量为M的时候,外部流量与内部流量的比例是M:M-1。在M较大的时候,例如10,有效流量(外部流量)的比例稍稍超过50%,等价于将网络带宽上限降低于一半,严重影响文件系统性能。一个解决办法是增加一套网络交换机、每台NFS服务器增加一个网口,专走内部流量,当然这样会增加成本。

即使配备内部网络,仍然无法解决IO路径长的问题:文件数据从NFS客户端走到NFS服务器上的硬盘上,几乎都要走一个中转过程(比例(M-1)/M),必然导致延时变长。作为对比,看看Lustre的IO路径,见图3,数据块的最终目的地是哪个IO服务器,计算服务器上的Lustre客户端就将数据块发送到哪个IO服务器,不但节省了内部流量(从而省了交换机和网卡)而且减小了延时。

图3

也许有人会想,能不能将图2中内部流量在NFS服务器的内存中暂存一下啊,数据一旦写入内存就告诉NFS客户写成功了。这个思路正确,但需要将内部流量暂存在保电的内存中(例如NVDIMM或NVRAM,就是内存条上配备电容或电池),防止服务器突然掉电而丢失暂存的数据。保电内存会增加成本,价格比普通内存条贵不少。

保电内存仍然不能消除操作的数据中转延时,见图4。仍然拿Lustre文件系统来对比,见图5,安装在计算服务器上的Lustre客户端先从元数据服务器(MDS)获得文件分布图(layout),然后就知道了每一个数据块都存放在哪个IO服务器的哪个位置, Lustre客户端直接从相应的IO服务器上读取数据块,没有中转,节省内部流量而且消除了中转延时。

图 4

图 5

最严重的问题还是一致性和文件锁

ROMIO官方文档[1]说,决不鼓励在NFS存储上运行MPI-IO程序,原文件如下:

It is worth first mentioning that in no way do we encourage the use of ROMIO on NFS volumes. NFS is not a high-performance protocol, nor are NFS servers typically very good at handling the types of concurrent access seen from MPI-IO applications.

必须首先强调,我们决不鼓励在NFS卷上使用ROMIO。NFS不是一个高性能的协议,NFS服务器通常也不擅长处理MPI-IO应用里的并发访问。

由于NFS协议非常流行,ROMIO必须硬着头皮支持NFS存储。但有下面3个前提要求[1]:

NFS v3客户端

在挂载的NFS目录上,文件锁函数 fcntl必须能够正常工作

计算服务器挂载NFS存储的时候必须使用选项noac

其实不强制要求v3版本的NFS客户端,只要文件锁函数fcntl正常工作就行,但用NFS v3能够保证fcntl正常工作,省去了验证的麻烦。

为什么要求文件锁函数fcntl和选项noac呢?ROMIO官网并没有解释,而论文[2]说出了其中原理。

文件锁保证并发访问的正确性

NFS协议是为串行访问设计的,即每个客户端访问不同的文件,不支持多个客户端同时访问同一个文件。具体表现为,文件描述符(对应open函数返回的文件句柄)不能共享:如果N个客户端想同时读写同一个文件,那么N个客户端都必须调用一次open函数以便得到文件描述符。这个N客户端虽然打开同一个文件,但客户端之间并不相互协调,相互不知道对方的动作,可能导致写冲突。

假设客户端C1和C2同时写文件f1.txt,C1写的范围是[0-1023]字节,而C2写的范围是[512-1515]字节。按照NFS协议,C1和C2之间不相互协调,那么就可能导致C1和C2同时写文件区间[512-1023],文件中最终数据不可预知。

为了避免数据冲突,ROMIO使用文件锁函数fcntl。在C1准备写文件的[0-1023]字节时,先调用函数fcntl锁住这个文件区间,以便客户端C1独占操作。客户端C2写文件区间[512-1023]写数据时,文件系统发现区间[512-1023]被客户端C1锁住了,于是让客户端C2等待。客户端C1写操作完成之后C2才能开始写。

fcntl保证并行IO操作的正确性,代价是降低了性能。按照MPI-IO分析文章中的经验推断,集合IO涉及的MPI进程越多,锁竞争越激烈,性能下降越严重。

noac选项关掉缓存

因为NFS设计时就没有考虑多个进程同时读写同一个文件的情况,所以NFS客户端就可以采用激进的缓存机制:不但缓存文件数据还缓存文件属性信息。文件属性包含读、写、执行权限、atime(access time, 最后1次访问时间 )/mtime(modification time,最后修改时间)/ctime(change time,元数据的最后改变时间)等。

这样以来,多个MPI进程聚合IO时就有文件同步的问题:如果开启了数据缓存机制,进程A通过NFS客户端CA写入文件区间[0-511],操作返回时,文件数据可能真的已经写到NFS服务器的硬盘上,也可能还停留在CA的缓存里。假设紧接着的MPI聚合IO操作要求进程B通过NFS客户端CB读取文件区间[0-511],这时就会出现3种情形:

NFS客户端CA已经将文件区间[0-511]写入NFS服务器,而NFS客户端CB也没有缓存区间[0-511]的数据(压根没缓存或者旧缓存过期了)。此时进程B通过CB读文件区间[0-511]的请求使得CB向NFS服务器请求文件数据,从而进程B能得到正确数据。

NFS客户端CA还没有将文件区间[0-511]写入NFS服务器,仍然保存在CA的缓存中。此时NFS客户端CB无论如何也读不到最新的数据,从而进程B能得到错误的旧数据。

NFS客户端CA已经将文件区间[0-511]写入NFS服务器,而NFS客户端CB本地缓存了文件属性和文件区间[0-511]的数据。进程B向CB请求读文件区间[0-511]时,CB就会对比文件数据缓存的更新时间和文件属性缓存中记录的文件最后修改时间(mtime等)。因为客户端CA不能主动向客户端CB推送文件已经更新消息,而客户端CB缓存的刷新又有一定的时间间隔,所以客户端CB就可能得出错误的结论:缓存中的文件数据就是最新的,不用从NFS服务器重新读取。最终导致进程B读到错误的旧数据。

进程A和进程B先后写同一个文件区间的场景,NFS缓存也有可能导致数据错误,过程类似,请读者自行分析,不赘述。

保证MPI 集合IO结果正确的必要条件是:一个进程的操作结果能被其它进程立即看到。读者可以拿上面进程A和进程B先写后读同一个文件区间的场景来验证,将写操作涉及的文件数据立即刷入NFS服务器+文件属性信息在进程间保持同步就能避免那些错误的发生。

文件属性同步很简单,用noac选项关掉文件属性缓存即可。这样以后,NFS客户端每次查看文件属性的时候都要向NFS服务器抓取。仍然拿进程A和进程B先写后读的场景来说:客户端CA将文件区间[0-511]立即写入NFS服务器,NFS服务器上文件属性也随之更新;客户端CB读取文件区间[0-511]时,先从NFS服务器获取最新的文件属性,与本地缓存的文件数据的更新对比后发现NFS服务器上的数据是最新的,于是弃用本地缓存的数据,转而从NFS服务器读取最新的文件数据。进程B读到正确数据。

关掉缓存,向NFS服务器写入、请求文件属性的次数就会大增,会降低存储系统的性能。

不知道锁边界

ROMIO对集合IO的优化关键是巧妙利用文件系统的锁粒度。使用“锁界对齐”、“静态循环”、“分组循环”几个大招的前提是知道文件的锁边界在哪里。Lustre、GPFS等并行文件系统接口丰富,可以方便地获取锁边界。而NFS协议没有这样的接口命令,ROMIO不知道NFS存储设备上的锁粒度,很可能使用默认的“均匀剖分”策略,显然不能达到最好性能。

NFS存储实测性能

前面都是从原理上定性分析MPI集合IO在NFS存储上性能差,有没有定量分析呢?到底差到什么程度呢?是降低10%还是降低90%呢?

回答是:没有在严肃的学术论文中看到NFS的并行IO性能数据。推测原因可能有这些:

技术实力雄厚的超算中心早就知道NFS存储不适合,没有采购,也就没有实测数据。

业界已知的结论,定量对比也算不上亮眼的成果,就不浪费时间写这方面的论文了。

即使大中型超算采购了NFS存储,发布性能差的数据是自己打脸,没几个人会干。

尽管如此,性能下降幅度还是可以估算的。网络上有人声称[3] noac选项会降低至20%的写带宽,可信度请自行分辨。

参照Lustre,如果ROMIO对NFS存储采用“均匀剖分”策略,那么它的性能最差情况下只有“分组循环”的4%(500/13000),见图6。

图 6

负载不均、数据中转对性能的影响没看到数据。但noac选项和文件锁fcntl这两项就可能使性能下降至0.8%(20%*4%)。如果您知道更多更准确的数据,烦请告知。

参考文献

[1]ftp://ftp.mcs.anl.gov/pub/romio/users-guide/node12.html

[2] Latham R., Ross R., Thakur R. (2004) The Impact of File Systems on MPI-IO Scalability. In: Kranzlmüller D., Kacsuk P., Dongarra J. (eds) Recent Advances in Parallel Virtual Machine and Message Passing Interface. EuroPVM/MPI 2004. Lecture Notes in Computer Science, vol 3241. Springer, Berlin, Heidelberg

[3] http://beowulf.beowulf.narkive.com/9ZbvJ8JH/mpi-io-nfs-alternatives

来源:HPC世界

温馨提示:

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190220A0LHSM00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券