背景
阿里云云存储网关支持以传统文件访问协议(NFS/SMB)来访问阿里云对象存储服务,网关通过暴露一个文件共享来和后端的OSS Bucket映射。用户操作对应的文件共享也就相当于在相应的OSS Bucket上进行操作,大大的便利了习惯于传统文件协议的用户。
NFS网络文件系统是在Linux机器上通用的一种文件系统,允许用户能够以本地文件系统类似的方式通过网络来访问远端服务器上的文件。NFS自推出以来,历经了NFSv2、NFSv3、NFSv4几个版本,现在的Linux机器上基本都已经用的NFSv4的版本,NFSv3在一些稍微老些版本的机器上还有使用,NFSv2已经几乎没有人使用了。
云存储网关是支持以NFSv3和NFSv4两个版本的协议来进行访问的,为了使这两个版本都能支持(主要是为了兼顾NFSv3的支持),在实现方面实际上有些权衡,导致默认情况下数据上传到OSS Bucket的效率对NFSv4协议来说其实不是最优的。这也就是为什么引入“NFS V4优化“这个选项的原因。
原理解析
使用过云存储网关的用户应该都知道,在用户写入一个文件到云存储网关的NFS共享里面之后,云存储网关会在后台将这个文件上传到该共享所对应的OSS Bucket里面。但是网关在什么时候开始文件的上传呢?是这个文件完全写入完成才开始上传呢?还是说文件没有完全写完的时候就开始上传了,边写边传呢?
OSS更新某个文件或者说是对象的时候,是原子性的,要么通过一次PutObject来完成,要么通过调用Multipart Upload相关的API接口来完成,即使只修改文件的很少一部分,也是如此。所以对一个文件如果写入了10次,实际上最后调用一次API就好了。这样比较理想的做法是在文件做了关闭动作表明当次修改完成之后,再根据用户是否对文件做了修改来决定是不是需要上传。听起来很完美,对不对?对NFSv4协议来说,这确实是比较完美的。但是考虑到NFSv3协议的话,事情就有了一点点变化,因为NFSv3协议原生并没有Close语义!!!用户在客户端关闭了某个文件之后,从服务器的角度来说,并不知道用户关闭了文件这件事情,所以对NFSv3而言我们并没有办法采用这边提到的完美的上传解决方案。
所以为了对NFSv3和NFSv4能够提供一种通用的解决方案,之前文件网关提供了“同步延迟”这个选项来控制文件上传的真正时机。这个选项的效果基本可以做到在绝大多数情况下,只在文件关闭的时候将这个文件上传到OSS Bucket。但是实际上它是通过检测在一定时间段内是否有写入来侦测是否需要上传的,假设同步延迟的值是10秒,也就是说对某个文件如果10秒内没有新的写入,就会尝试将该文件上传,否则就会延迟上传的时间。考虑到绝大数情况下用户基本都是打开文件然后持续的写入最后关闭文件,所以对这些情况基本是能够做到在文件关闭的时候才上传这种效果的。
但是如果用户打开文件之后,并不是持续的写入,而是间隔的写入,并且写入的间隔大于“同步延迟”的话(或者用户想尽早看到文件出现在OSS Bucket里面而干脆将同步延迟设置成了零)就可能会造成一些中间没有意义的上传。如何优化这种情况呢?
介绍到在这,相信您已经明白了新的“NFS V4优化“选项该出场了。考虑到现在绝大多数的Linux机器基本都已经支持NFSv4版本了,而且对绝大多数用户来说并没有强烈的需求需要指定使用NFSv3版本。所以“NFS V4优化”选项实现了前文提到的那种完美的方案,只有在用户在客户端关闭了文件的时候,才尝试上传文件到OSS Bucket。在这个选项打开时,尝试用NFSv3协议挂载共享就会失败。
配置
在升级到最新版本的云存储网关之后就可以体验“NFS V4优化”选项了,可以新建NFS共享的时候勾上这个选项,也可以对一个已有的共享打开或者关闭这个选项。如果您本地已经挂载了NFS共享,您可以使用mount命令看到当前挂载的NFS的版本。在笔者的CentOS 7.6上,当前挂载的NFS版本是4.1。
[root@iZbp116y3gfxxlyq58wu9iZ ~]# mount
...
172.16.159.155:/nfsv4optimize on /mnt/v4optimize type nfs4 (rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=172.16.159.131,local_lock=none,addr=172.16.159.155)
这就说明你的机器默认已经支持了NFSv4,如果所有的客户端上的输出都具有“vers=4.x”这种输出,那就可以很安全的打开“NFS V4优化”选项了。
打开该选项之后,尝试用NFSv3的方式挂载的话会出错。
[root@iZbp116y3gfxxlyq58wu9iZ ~]# mount 172.16.159.155:/nfsv4optimize /mnt/v4optimize/ -overs=3
mount.nfs: access denied by server while mounting 172.16.159.155:/nfsv4optimize
如果因为某些无法避免的原因必须要使用NFSv3的方法的挂载的话,可以动态关闭这个选项之后再尝试挂载。
[root@iZbp116y3gfxxlyq58wu9iZ ~]# mount 172.16.159.155:/nfsv4optimize /mnt/v4optimize/ -overs=3
[root@iZbp116y3gfxxlyq58wu9iZ ~]# mount
...
172.16.159.155:/nfsv4optimize on /mnt/v4optimize type nfs (rw,relatime,vers=3,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=172.16.159.155,mountvers=3,mountport=32888,mountproto=udp,local_lock=none,addr=172.16.159.155)
验证
接下来我们通过一个简单的例子来看这个选项的效果。我们在客户端写了一个简单的程序,它打开一个共享里面的文件,每一分钟写入一些内容,我们可以通过观察OSS Bucket对应的这个文件的修复时间来判断到底上传了几次。
import time
with open("/mnt/v4optimize/v3test/test_file", "w") as f:
for i in range(1,5):
f.write("hello world!")
f.flush()
time.sleep(60)
为了性能默认的NFS挂载参数一般是以async的模式来挂载共享的,也就是说客户端操作系统会缓存一部分数据,然后再一起写到NFS共享里面。为了消除这一部分的影响让测试结果更精确,我们需要以sync的方式挂载该NFS共享来测试。
[root@iZbp116y3gfxxlyq58wu9iZ /]# mount 172.16.159.155:/nfsv4optimize /mnt/v4optimize/ -osync
[root@iZbp116y3gfxxlyq58wu9iZ /]# mount
...
172.16.159.155:/nfsv4optimize on /mnt/v4optimize type nfs4 (rw,relatime,sync,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=172.16.159.131,local_lock=none,addr=172.16.159.155)
之后我们可以通过OSS控制台观察这个文件的修改时间来判断到底发生了几次上传。
当前共享的同步延迟选项设置的是0秒。根据前面的判断,不打开“NFS V4优化”选项,我们应该看到多次上传。通过观察会发现OSS Bucket里面的文件修改时间确实每一分钟会修改一次,符合我们的预期。如果打开该优化选项,只会看到文件的修改时间变了一次。感兴趣的用户也可以自己做一下这个测试。
总结
本文主要介绍了云存储网关的“NFS V4优化”选项的工作原理,如果您并没有需求必须使用NFSv3的方式挂载网关的NFS共享,建议您都以NFSv4的方式挂载并打开这个选项,从而获得更理想的文件上传效率。