1970~1989年,针对远程文件访问,有大量的实验性系统。这些系统有的称为文件服务器(file server),例如,Woodstock File Server 、Cambridge File Server。有的称为网络文件系统,例如,Sun 公司的Sun Network File System 和加利福尼亚大学伯克利分校开发的Sprite Network File System 。有的称为分布式文件系统,例如XDFS和AFS。当时网络文件系统与分布式文件系统这两个词并没有本质区别,都是指通过网络并使用文件系统接口来访问远程的文件。
1985年Sun公司发布了NFS协议作为对远程文件系统进行透明访问的一种解决方案,同时,Sun还发布了一个NFS的参考实现。NFS在工业界和学术界都得到广泛的使用。很多计算机厂商在他们的操作系统中都实现了NFS,使得它成为事实上的工业标准。
1989年,NFS协议被标准化机构IETF接受,并发布了RFC 1094 (被称为NFS v2,Sun公司最初发布的NFS协议被认为是v1)。此后,“网络文件系统(NFS)”一词一般是指根据IETF的NFS协议实现的文件系统。
1995年,IETF发布了NFS v3(RFC 1813)。直到目前,大部分存储产品仍然使用这个版本的NFS。NFS v3在v2的基础上增加了4个操作,即COMMIT、READDIRPLUS、FSINFO和FSSTAT。COMMIT用于改进v2的写性能,READDIRPLUS用于改进ls-l的性能,FSSTAT用于支持 df命令。
2000年,IETF发布了NFS v4(RFC 3010),这个版本与之前的版本一个最大的不同在于v4是有状态的,这也使得NFS v4变得非常复杂。后来,RFC 3530(2003)和RFC 7530(2015)分别对NFS v4做了两次修订。
NFS的设计目标包括:
①可移植性。即NFS不局限于UNIX系统,任何操作系统都能够实现NFS的服务器和客户端。
②异构性。即NFS不依赖任何硬件,服务器和客户端可以是不同的机器。
③宕机恢复容易。即无论服务器还是客户端宕机,恢复机制应尽可能简单。
④透明性。即应用程序能够透明地访问远程文件,它们不感知文件或目录是在本地磁盘上还是在远程服务器上,已有的应用程序无需重新编译链接就能访问NFS中的文件。
⑤访问性。NFS的文件访问性能要与本地文件的访问性能接近。
网络文件系统NFS基于客户端-服务器模型。服务器输出一个或多个本地文件系统的目录子树,对于每一个输出的目录子树,服务器可以指定哪些客户端可以挂载它,及其访问权限(只读或者可读可写)。客户端计算机可以像挂载本地文件系统一样,将这个目录子树挂载到自己的本地目录树上,在UNIX操作系统中使用mount(挂载)命令来挂载NFS。
客户端计算机将服务器输出的一个目录子树挂载到本地目录树上之后,客户端的用户和应用程序可以用访问本地文件系统一样的接口f访问这个目录子树中的文件和目录。
通常,NFS的实现包括以下几个组成部分:
①NFS协议。定义了一组客户端能够向服务器发送的请求及参数,服务器的处理及返回的应答。
②RPC协议。定义客户端与服务器之间所有的交互的格式,每个NFS请求及应答都用RPC包的形式发送。
③XDR。对于通过网络传输的数据,定义了一种与机器无关的数据表示方法,所有的RPC请求都采用外部数据表示法(XDR)表示。
④NFS服务器。负责处理所有的客户端请求,提供对输出的目录子树的访问。一般是实现一个守护进程nfsd来接收和处理客户端的NFS请求。
⑤NFS客户端。提供与访问本地文件系统一样的用户接口,把用户对NFS的访问转化为一个或多个RPC请求,发给NFS服务器,从而实现应用程序对远程文件的透明访问。
⑥挂载协议。定义了挂载和卸载NFS文件系统的语义,一般是实现一个守护进程mountd来接收和处理NFC挂载相关的请求。
⑦NLM和NSM协议。NLM是网络锁管理协议,NSM是网络状态监控协议。它们一起实现NFS的文件锁功能。
Sun公司在实现NFS的客户端时,发明了VFS(虚拟文件系统)。通过VFS把文件系统的用户接口与物理实现分离,使得在一个操作系统上,可以同时挂载多个不同类型的物理文件系统。比如,本地的UNIX文件系统和NFS客户端。通过VFS,能够实现远程文件的透明访问,即应用程序不感知文件的位置(本地还是远程),应用程序无需编译链接就可以访问NFS。
NFS协议的最主要的特点是服务器是无状态的,即服务器不维护客户端的上下文信息。因此,客户端发给服务器的每个RPC请求都包含了服务器处理该请求的所有信息。例如,NFS协议没有打开和关闭文件的请求,READ和WRITE请求将文件偏移作为参数传给服务器。服务器不维护打开文件结构,也不维护打开文件的当前位置指针,这些信息由客户端维护。
无状态使得NFS不能提供与本地UNIX文件系统完全一样的功能。比如,NFS协议自身不支持文件锁功能。所以,在NFS协议之外,由另外的两个协议(NLM和NSM)来实现文件锁功能。
为了使得NFS的访问性能接近本地文件的访问性能,大部分NFS客户端都实现了缓存,即在客户端本地缓存NFS正在访问的一些文件和目录,包括它们的元数据。
客户端缓存的引入会带来一致性问题:一方面,客户端缓存的内容与服务器的内容可能不一致;另一方面,多个客户端挂载了同一服务器输出的同一目录子树,如果它们同时对同一文件或目录进行修改,也可能出现各个客户端上文件的内容不一致。
为了减少不一致的出现,客户端缓存里的数据块只在一段时间内有效,通常设置为文件块3秒钟内有效,目录块30秒钟内有效。超过这个时间,客户端就必须丢弃其缓存的数据块。如果客户端打开一个缓存的文件时,会给服务器发请求以检查文件是否有改变。对于脏数据块,每过30秒钟必须写回服务器。因此,NFS的文件共享是一种基于时间的语义,而不是UNIX的文件共享语义。
最初,NFS使用UNIX的保护机制,对于文件所有者、同组用户和其他用户分别设置读、写和执行权限。每个NFS请求都包含客户端应用程序的用户信息(UID和GID),服务器用它们来验证访问合法性。后来,NFS也支持客户端与服务器之间的每个请求都使用基于公钥加密的密钥来验证访问合法性。
NFS被所有的计算机主流厂商实现在他们的操作系统上,不仅包括UNIX类型的操作,还包括非UNIX的操作系统,例如PC-DOS和Windows。因此,早在1990年代,NFS就已经成为事实上的工业标准。
后来,面向企业数据中心都使用NFS作为其文件服务。在NFS的基础上,发展出了SAN存储产品和NAS存储产品等。直到现在,几乎所有存储厂商生成的存储产品都支持NFS协议。