速读原著-TCP/IP(NFS实例)

2020-03-18 11:12:12 浏览数 (2)

第29章 网络文件系统

29.6 NFS实例

我们使用t c p d u m p来看一下在典型的文件操作中,客户调用了哪些 N F S过程。当t c p d u m p检测到一个包含 R P C调用(在图 2 9 - 1中调用字段等于 0)、目的端口是 2 0 4 9的U D P数据报时,它把数据报按照一个 N F S请求进行解码。类似地,如果一个 U D P数据报是一个 R P C应答(在图2 9 - 2中应答字段为1),源端口是2 0 4 9,t c p d u m p就把此数据报作为一个N F S应答来解码。

29.6.1 简单的例子:读一个文件

第一个例子是使用c a t ( 1 )命令将位于一个N F S服务器上的一个文件复制到终端上:

如同图2 9 - 6所示,主机s u n(N F S客户机)上的文件系统 /nfs/bsdi/usr 实际上是主机b s d i(N F S服务器)上的 /usr 文件系统。当c a t打开这个文件时, s u n上的内核检测到这一点,然后使用N F S去访问文件。图2 9 - 7显示了t c p d u m p的输出。

当t c p d u m p解析一个N F S请求或应答报文时,它打印客户的 X I D字段,而不是端口号。第1行和第2行中的X I D字段值是0 x 7 a a 6。

客户内核中的打开函数一次处理文件名 /nfs/bsdi/usr/rstevens/hello.c 中的一个成员。当处理到/ n f s / b s d i / u s r时,它发现这是指向一个已安装的 N F S文件系统的一个安装点。

在第1行中,客户调用 G E TAT T R过程取得客户已经安装的服务器目录的属性( / u s r)。这个R P C请求,除I P首部和U D P首部之外,包含 1 0 4个字节的数据。第 2行中的应答返回了一个O K值,除了I P首部和U D P首部之外,包含了 9 6个字节的数据。在这个图中,我们可以看出最小的N F S报文包含大约1 0 0个字节的数据。

在第3行中,客户调用 L O O K U P过程来查看 r s t e v e n s文件。在第 4行中收到一个 O K应答。L O O K U P过程说明了文件名r s t e v e n s和远程文件系统被安装时由内核保存的文件句柄。应答中包含了下一步要使用的一个新的文件句柄。

在第5行中,客户使用第4行中返回的文件句柄对h e l l o . c调用L O O K U P过程。在第6行返回了另一个文件句柄。新的文件句柄就是客户在第7行和第9行中引用文件/ n f s / b s d i / u s r / r s t e v e n s / h e l l o . c所使用的文件句柄。我们看到客户对于正在打开的路径名的每个成员都调用了一次 L O O K U P过程。

在第7行中,客户又调用了一次 G E TAT T R过程,接着在第 9行中调用了R E A D过程。客户请求从偏移0开始的1 0 2 4个字节,但是接收到的没有这么多(减去 R P C字段和其他由R E A D过程返回的值的大小,在第1 0行中返回了3 8个字节的数据。这是文件h e l l o . c的实际大小)。

在这个例子中,应用进程对于内核所做的这些 R P C请求和应答一点儿也不知道。应用进程只是调用了内核的 o p e n函数,后者引起了 3个R P C请求和3个应答(1 ~ 6行),然后应用进程又调用了内核的 r e a d函数,它引起了两个请求和两个应答( 7 ~ 1 0行)。该文件位于一个 N F S文件服务器,这一点对客户应用进程来说是透明的。

29.6.2 简单的例子:创建一个目录

作为另一个简单的例子,我们将当前工作目录改变为一个 N F S服务器上的一个目录,然后创建一个新的目录:

代码语言:javascript复制
sun % cd /nfs/bsdi/usr/rstevens 改变当前工作目录
sun % mkdir Mail 并且创建一个目录

图2 9 - 8显示了t c p d u m p的输出。

改变目录引起客户调用了两次 G E TAT T R过程(1 ~ 4行)。当我们创建新的目录时,客户调用了G E TAT T R过程(5 ~ 6行),接着调用L O O K U P过程(7 ~ 8行,用来验证将创建的目录不存在),跟着调用了M K D I R过程来创建目录(9 - 1 0行)。在第8行中,应答O K并不表示目录存在。

它只是表示过程返回了。 t c p d u m p并不理解N F S过程的返回值。它一般打印 O K和应答报文中数据的字节数。

29.6.3 无状态

N F S的一个特征(N F S的批评者称之为N F S的一个瑕疵,而不是一个特征)是 N F S服务器是无状态的( s t a t e l e s s )。服务器并不记录哪个客户正在访问哪个文件。请注意一下在前面给出的N F S过程中,没有一个 o p e n操作和一个c l o s e操作。L O O K U P过程的功能与o p e n操作有些类似,但是服务器永远也不会知道客户对一个文件调用了 L O O K U P过程之后是否会引用该文件。无状态设计的理由是为了在服务器崩溃并且重启动时,简化服务器的崩溃恢复操作。

29.6.4 例子:服务器崩溃

在下面的例子中我们从一个崩溃然后重启动的 N F S服务器上读一个文件。这个例子演示了无状态的服务器是如何使得客户不知道服务器的崩溃。除了在服务器崩溃然后重启动时一个时间上的暂停外,客户并不知道发生的问题,客户应用进程没有受到影响。

在客户机s u n上,我们对一个长文件( N F S服务器主机s v r 4上的文件/ u s r / s h a r e / l i b / t e r m c a p)执行c a t命令。在传送过程中把以太网的网线拔掉,关闭然后重启动服务器主机,再重新将网线连上。客户被配置成每个 NFS read过程读1 0 2 4个字节。图2 9 - 9显示了t c p d u m p的输出。1 ~ 1 0行对应于客户打开文件,操作类似于图 2 9 - 7所示。在第11行我们看到对文件的第一个R E A D操作,在1 2行返回了1 0 2 4个字节的数据。这个操作一直继续到 1 2 9行(读1 0 2 4个字节的数据,跟着一个O K应答)。

在第1 3 0行和第1 3 1行我们看到两个请求超时,并且分别在 1 3 2行和1 3 3行重传。第一个问题是这里为什么会有两个读请求,一个从偏移 6 5 5 3 6开始读,另一个从偏移 7 3 7 2 8开始读?答案是客户内核检测到客户应用进程正在进行顺序地读操作,所以试图预先取得数据块(大多数的U n i x内核都采用了这种预读技术)。客户内核也正在运行多个 N F S块I / O守护程序,后者试图代表客户产生多个 R P C请求。一个守护程序正在从偏移 6 5 5 3 6处读8 1 9 2个字节(以1 0 2 4字节为一组数据块),而另一个正在从7 3 7 2 8处预读8 1 9 2个字节。

客户重传发生在1 3 0 ~ 1 6 8行。在第1 6 9行我们看到服务器已经重启动,在它对第 1 6 8行的客户N F S请求做出应答之前,它发送了一个 A R P请求。对1 6 8行的响应被发送在 1 7 1行。客户的R E A D操作继续进行下去。

除了从1 2 9行到1 7 1行5分钟的暂停,客户应用进程并不知道服务器崩溃然后又重启动了。这个服务器的崩溃对于客户是透明的。

为了研究这个例子中的超时和重传时间间隔,首先要意识到这儿有两个客户守护程序,分别有它们各自的超时。第 1个守护程序(在偏移 6 5 5 3 6处开始读)的间隔,四舍五入到两个十进制小数点,为0.68, 0.87, 1.74, 3.48, 6.96, 13.92, 20.0, 20.0, 20.0等等。第2个守护程序(在偏移7 3 7 2 8处开始读)的间隔也是一样的(精确到两个小数点)。可以看出这些 N F S客户使用了一个这样的超时定时器:间隔为 0 . 8 7 5秒的倍数,上限为2 0秒。每次超时后,重传间隔翻倍:0.875, 1.75, 3.5, 7.0和1 4 . 0。

客户要重传多久呢?客户有两个与此有关的选项。首先,如果服务器文件系统是“硬”安装的,客户就会永远重传下去。但是如果服务器文件系统是“软”安装的,客户重传了固定数目的次数之后就会放弃。在“硬”安装的情况下,客户还有一个选项决定是否允许用户中断无限制的重传。如果客户主机安装服务器文件系统时说明了中断能力,并且如果我们不想在服务器崩溃之后等 5分钟,等着服务器重启动,就可以键入一个中断键以终止客户应用程序。

29.6.5 等幂过程

如果一个 R P C过程被服务器执行多次仍然返回同样的结果,那么就把它叫作等幂过程(Idempotent Procedure)。例如,N F S的读过程是等幂的。正像我们在图 2 9 - 9中看到的,客户只是重发一个特定的R E A D调用直到它得到一个响应。在我们的例子中,重传的原因是服务器崩溃了。如果服务器没有崩溃,而是 R P C应答报文丢失了(既然 U D P是不可靠的),客户只是重传请求,服务器再一次执行同样的 R E A D过程。同一个文件的同一部分被重读一次,发送给客户。

这种方法行得通的原因在于每个 R E A D请求指出了读操作开始的偏移位置。如果有一个N F S过程要求服务器读一个文件的下 N个字节,这种方法就不行了。除非服务器被做成是有状态的(与无状态相反),如果一个应答丢失了,客户重发读下 N个字节的R E A D请求,结果将是不一样的。这就是为什么 N F S的R E A D和W R I T E过程要求客户说明开始的偏移位置的原因。

客户维护着状态(每个文件当前的偏移位置),而不是服务器。不幸的是并不是所有的文件系统操作都是等幂的。例如,考虑下面的动作:客户 N F S发 出R E M O V E请求来删除一个文件;服务器 N F S删除了文件,并回答 O K;服务器的回答丢失了;客户N F S超时,然后重传请求;服务器 N F S找不到指定的文件,回答指出一个错误;客户应用程序接收到一个错误表示文件不存在。这个返回给客户应用程序的错误是不对的—该文件的确存在并且被删除了。

等幂的N F S过程是:G E TAT T R、S TAT E S、L O O K U P、R E A D、W R I T E、R E A D L I N K和R E A D D I R。不是等幂的过程是: C R E AT E、R E M O V E、R E N A M E、L I N K、S Y M L I N K、M K D I R和R M D I R。S E TAT T R过程如果不用来截断文件,一般是等幂的。

既然使用U D P总会发生响应报文丢失的现象, N F S服务器需要一种方法来处理非等幂的操作。大多数的服务器实现了一个最近应答的高速缓存,用于存放非等幂操作最近的应答。

每当服务器收到一个请求,它首先检查这个高速缓存,如果找到了一个匹配,就返回以前的应答而不再调用相应的N F S过程。[Juszczak 1989]提供了这种高速缓存的实现细节。等幂服务器过程的概念可以应用于任何基于 U D P的应用程序,而不仅仅是 N F S。例如,D N S也提供了一个等幂服务。一个 D N S的服务器可以任意多次地执行一个解析者的请求而没有任何不良的后果(如果不考虑网络资源浪费的话)。

0 人点赞