第3章 NFS基本应用

Posted 骏马金龙

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第3章 NFS基本应用相关的知识,希望对你有一定的参考价值。

1.1 概述

类似ext家族、xfs格式的本地文件系统,它们都是通过单个文件名称空间(name space)来包含很多文件,并提供基本的文件管理和空间分配功能。而文件是存放在文件系统中(上述名称空间内)的单个命名对象,每个文件都包含了文件实际数据和属性数据。但是,这些类型的文件系统和其内文件都是存放在本地主机上的。

实际上,还有网络文件系统。顾名思义,就是跨网络的文件系统,将远程主机上的文件系统(或目录)存放在本地主机上,就像它本身就是本地文件系统一样。在Windows环境下有cifs协议实现的网络文件系统,在Unix环境下,最出名是由NFS协议实现的NFS文件系统。

NFS即network file system的缩写,nfs是属于用起来非常简单,研究起来非常难的东西。相信,使用过它或学过它的人都不会认为它的使用有任何难点,只需将远程主机上要共享给客户端的目录导出(export),然后在客户端上挂载即可像本地文件系统一样。到目前为止,nfs已经有5个版本,NFSv1是未公布出来的版本,v2和v3版本目前来说基本已经淘汰,v4版本是目前使用最多的版本,nfsv4.1是目前最新的版本。

1.2 RPC不可不知的原理

要介绍NFS,必然要先介绍RPC。RPC是remote procedure call的简写,人们都将其译为"远程过程调用",它是一种框架,这种框架在大型公司应用非常多。而NFS正是其中一种,此外NIS、hadoop也是使用rpc框架实现的。

1.2.1 RPC原理

所谓的remote procedure call,就是在本地调用远程主机上的procedure。以本地执行"cat -n ~/abc.txt"命令为例,在本地执行cat命令时,会发起某些系统调用(如open()、read()、close()等),并将cat的选项和参数传递给这些函数,于是最终实现了文件的查看功能。在RPC层面上理解,上面发起的系统调用就是procedure,每个procedure对应一个或多个功能。而rpc的全名remote procedure call所表示的就是实现远程procedure调用,让远程主机去调用对应的procedure。

上面的cat命令只是本地执行的命令,如何实现远程cat,甚至其他远程命令?通常有两种可能实现的方式:

(1).使用ssh类的工具,将要执行的命令传递到远程主机上并执行。但ssh无法直接调用远程主机上cat所发起的那些系统调用(如open()、read()、close()等)。

(2).使用网络socket的方式,告诉远程服务进程要调用的函数。但这样的主机间进程通信方式一般都是daemon类服务,daemon类的客户端(即服务的消费方)每调用一个服务的功能,都需要编写一堆实现网络通信相关的代码。不仅容易出错,还比较复杂。

而rpc是最好的解决方式。rpc是一种框架,在此框架中已经集成了网络通信代码和封包、解包方式(编码、解码)。以下是rpc整个过程,以cat NFS文件系统中的a.sh文件为例。

    

nfs客户端执行cat a.sh,由于a.sh是NFS文件系统内的文件,所以cat会发起一些procedure调用(如open/read/close),这些procedure对应的ID号码和对应的参数会发送给rpc client(可能是单个procedure ID,也可能是多个procedure组合在一起一次性发送给rpc client,在NFSv4上是后者),rpc client会将这些数据进行编码封装(封装和解封装功能由stub代码实现),封装后的消息称为"call message",然后将call message通过网络发送给rpc server,rpc server会对封装的数据进行解封提取,于是就得到了要调用的procedures ID和对应的参数,然后将它们交给NFS服务进程,最终调用procedure ID对应的procedure来执行,并返回结果。NFS服务发起procedure调用后,会得到数据(可能是数据本身,可能是状态消息等),于是将返回结果交给rpc server,rpc server会将这些数据封装,这部分数据称为"reply message",然后将reply message通过网络发送给rpc client,rpc client解封提取,于是得到最终的返回结果。

从上面的过程可以知道,rpc的作用是数据封装,rpc client封装待调用的procedure ID及其参数(其实还有一个program ID,关于program,见下文),rpc server封装返回的数据。

举个更简单的例子,使用google搜索时,实现搜索功能的program ID以及涉及到的procedure ID和要搜索的内容就是rpc client封装的对象,也是rpc server要解封的对象,搜索的结果则是rpc server封装的对象,也是rpc client要解封的对象。解封后的最终结果即为google搜索的结果。

1.2.2 RPC工具介绍

在CentOS 6/7上,rpc server由rpcbind程序实现,该程序由rpcbind包提供。

[root@xuexi ~]# yum -y install rpcbind

[root@xuexi ~]# rpm -ql rpcbind | grep bin/
/usr/sbin/rpcbind
/usr/sbin/rpcinfo

其中rpcbind是rpc主程序,在rpc服务端该程序必须处于已运行状态,其默认监听在111端口。rpcinfo是rpc相关信息查询工具。

对于rpc而言,其所直接管理的是programs,programs由一个或多个procedure组成。这些program称为RPC program或RPC service。

如下图,其中NFS、NIS、hadoop等称为网络服务,它们由多个进程或程序(program)组成。例如NFS包括rpc.nfsd、rpc.mountd、rpc.statd和rpc.idmapd等programs,其中每个program都包含了一个或多个procedure,例如rpc.nfsd这个程序包含了如OPEN、CLOSE、READ、COMPOUND、GETATTR等procedure,rpc.mountd也主要有MNT和UMNT两个procedure。

对于RPC而言,它是不知道NFS/NIS/hadoop这一层的,它直接管理programs。每个program启动时都需要找111端口的rpc服务登记注册,然后RPC服务会为该program映射一个program number以及分配一个端口号。其中每个program都有一个唯一与之对应的program number,它们的映射关系定义在/etc/rpc文件中。以后rpc server将使用program number来判断要调用的是哪个program中的哪个procedure(因为这些都是rpc client封装在"call message"中的),并将解包后的数据传递给该program和procedure。

例如只启动rpcbind时。

[root@xuexi ~]# systemctl start rpcbind.service

[root@xuexi ~]# rpcinfo -p localhost
   program vers proto   port  service
    100000    4   tcp    111  portmapper
    100000    3   tcp    111  portmapper
    100000    2   tcp    111  portmapper
    100000    4   udp    111  portmapper
    100000    3   udp    111  portmapper
    100000    2   udp    111  portmapper

其中第一列就是program number,第二列vers表示对应program的版本号,最后一列为RPC管理的RPC service名,其实就是各program对应的称呼。

当客户端获取到rpc所管理的service的端口后,就可以与该端口进行通信了。但注意,即使客户端已经获取了端口号,客户端仍会借助rpc做为中间人进行通信。也就是说,无论何时,客户端和rpc所管理的服务的通信都必须通过rpc来完成。之所以如此,是因为只有rpc才能封装和解封装数据。

既然客户端不能直接拿着端口号和rpc service通信,那还提供端口号干嘛?这个端口号是为rpc server提供的,rpc server解包数据后,会将数据通过此端口交给对应的rpc service。

1.3 启动NFS

NFS本身是很复杂的,它由很多进程组成。这些进程的启动程序由nfs-utils包提供。由于nfs是使用RPC框架实现的,所以需要先安装好rpcbind。不过安装nfs-utils时会自动安装rpcbind。

[root@xuexi ~]# yum -y install nfs-utils

[root@xuexi ~]# rpm -ql nfs-utils | grep /usr/sbin
/usr/sbin/blkmapd
/usr/sbin/exportfs
/usr/sbin/mountstats
/usr/sbin/nfsdcltrack
/usr/sbin/nfsidmap
/usr/sbin/nfsiostat
/usr/sbin/nfsstat
/usr/sbin/rpc.gssd
/usr/sbin/rpc.idmapd
/usr/sbin/rpc.mountd
/usr/sbin/rpc.nfsd
/usr/sbin/rpc.svcgssd
/usr/sbin/rpcdebug
/usr/sbin/showmount
/usr/sbin/sm-notify
/usr/sbin/start-statd

其中以"rpc."开头的程序都是rpc service,分别实现不同的功能,启动它们时每个都需要向rpcbind进行登记注册。

[root@xuexi ~]# systemctl start nfs.service

[root@xuexi ~]# rpcinfo -p localhost
   program vers proto   port  service
    100000    4   tcp    111  portmapper
    100000    3   tcp    111  portmapper
    100000    2   tcp    111  portmapper
    100000    4   udp    111  portmapper
    100000    3   udp    111  portmapper
    100000    2   udp    111  portmapper
    100024    1   udp  56229  status
    100024    1   tcp  57226  status
    100005    1   udp  20048  mountd
    100005    1   tcp  20048  mountd
    100005    2   udp  20048  mountd
    100005    2   tcp  20048  mountd
    100005    3   udp  20048  mountd
    100005    3   tcp  20048  mountd
    100003    3   tcp   2049  nfs
    100003    4   tcp   2049  nfs
    100227    3   tcp   2049  nfs_acl
    100003    3   udp   2049  nfs
    100003    4   udp   2049  nfs
    100227    3   udp   2049  nfs_acl
    100021    1   udp  48609  nlockmgr
    100021    3   udp  48609  nlockmgr
    100021    4   udp  48609  nlockmgr
    100021    1   tcp  50915  nlockmgr
    100021    3   tcp  50915  nlockmgr
    100021    4   tcp  50915  nlockmgr

可以看到,每个program都启动了不同版本的功能。其中nfs program为rpc.nfsd对应的program,为nfs服务的主进程,端口号为2049。mountd对应的program为rpc.mountd,它为客户端的mount和umount命令提供服务,即挂载和卸载NFS文件系统时会联系mountd服务,由mountd维护相关挂载信息。nlockmgr对应的program为rpc.statd,用于维护文件锁和文件委托相关功能,在NFSv4以前,称之为NSM(network status manager)。nfs_acl和status,很显然,它们是访问控制列表和状态信息维护的program。

再看看启动的相关进程信息。

[root@xuexi ~]# ps aux | grep -E "[n]fs|[r]pc"
root        748  0.0  0.0      0     0 ?        S<   Jul26   0:00 [rpciod]
rpc        6127  0.0  0.0  64908  1448 ?        Ss   Jul26   0:00 /sbin/rpcbind -w
rpcuser    6128  0.0  0.0  46608  1836 ?        Ss   Jul26   0:00 /usr/sbin/rpc.statd --no-notify
root       6242  0.0  0.0      0     0 ?        S<   Jul26   0:00 [nfsiod]
root       6248  0.0  0.0      0     0 ?        S    Jul26   0:00 [nfsv4.0-svc]
root      17128  0.0  0.0  44860   976 ?        Ss   02:49   0:00 /usr/sbin/rpc.mountd
root      17129  0.0  0.0  21372   420 ?        Ss   02:49   0:00 /usr/sbin/rpc.idmapd
root      17134  0.0  0.0      0     0 ?        S<   02:49   0:00 [nfsd4]
root      17135  0.0  0.0      0     0 ?        S<   02:49   0:00 [nfsd4_callbacks]
root      17141  0.0  0.0      0     0 ?        S    02:49   0:00 [nfsd]
root      17142  0.0  0.0      0     0 ?        S    02:49   0:00 [nfsd]
root      17143  0.0  0.0      0     0 ?        S    02:49   0:00 [nfsd]
root      17144  0.0  0.0      0     0 ?        S    02:49   0:00 [nfsd]
root      17145  0.0  0.0      0     0 ?        S    02:49   0:00 [nfsd]
root      17146  0.0  0.0      0     0 ?        S    02:49   0:00 [nfsd]
root      17147  0.0  0.0      0     0 ?        S    02:49   0:00 [nfsd]
root      17148  0.0  0.0      0     0 ?        S    02:49   0:00 [nfsd]

其中有一项/usr/sbin/rpc.idmapd进程,该进程是提供服务端的uid/gid <==> username/groupname的映射翻译服务。客户端的uid/gid <==> username/groupname的映射翻译服务则由"nfsidmap"工具实现,详细说明见下文。

1.4 配置导出目录和挂载使用

1.4.1 配置nfs导出目录

在将服务端的目录共享(share)或者说导出(export)给客户端之前,需要先配置好要导出的目录。比如何人可访问该目录,该目录是否可写,以何人身份访问导出目录等。

配置导出目录的配置文件为/etc/exports或/etc/exports.d/*.exports文件,在nfs服务启动时,会自动加载这些配置文件中的所有导出项。以下是导出示例:

/www    172.16.0.0/16(rw,async,no_root_squash)

其中/www是导出目录,即共享给客户端的目录;172.16.0.0/16是访问控制列表ACL,只有该网段的客户端主机才能访问该导出目录,即挂载该导出目录;紧跟在主机列表后的括号及括号中的内容定义的是该导出目录对该主机的导出选项,例如(rw,async,no_root_squash)表示客户端挂载/www后,该目录可读写、异步、可保留root用户的权限,具体的导出选项稍后列出。

以下是可接收的几种导出方式:

/www1    (rw,async,no_root_squash)  # 导出给所有主机,此时称为导出给world
/www2    172.16.1.1(rw,async)       # 仅导出给单台主机172.16.1.1
/www3    172.16.0.0/16(rw,async) 192.168.10.3(rw,no_root_squash)   # 导出给网段172.16.0.0/16,还导出给单台
                                                                   # 主机192.168.10.3,且它们的导出选项不同
/www4    www.a.com(rw,async)        # 导出给单台主机www.a.com主机,但要求能解析该主机名
/www     *.b.com(rw,async)          # 导出给b.com下的所有主机,要求能解析对应主机名

以下是常用的一些导出选项说明,更多的导出选项见man exports:常见的默认项是:ro,sync,root_squash,no_all_squash,wdelay。

导出选项

(加粗标红为默认)

选项说明

rw、ro

导出目录可读写还是只读(read-only)。

sync、async

同步共享还是异步共享。异步时,客户端提交要写入的数据到服务端,服务端接收数据后直接响应客户端,但此时数据并不一定已经写入磁盘中,而同步则是必须等待服务端已将数据写入磁盘后才响应客户端。也就是说,给定异步导出选项时,虽然能提升一些性能,但在服务端突然故障或重启时有丢失一部分数据的风险。

当然,对于只读(ro)的导出目录,设置sync或async是没有任何差别的。

anonuid

anongid

此为匿名用户(anonymous)的uid和gid值,默认都为65534,在/etc/passwd和/etc/shadow中它们对应的用户名为nfsnobody。该选项指定的值用于身份映射被压缩时。

root_squash

no_root_squash

是否将发起请求(即客户端进行访问时)的uid/gid=0的root用户映射为anonymous用户。即是否压缩root用户的权限。

all_squash

no_all_squash

是否将发起请求(即客户端进行访问时)的所有用户都映射为anonymous用户,即是否压缩所有用户的权限。

对于root用户,将取(no_)root_squash和(no_)all_squash的交集。例如,no_root_squash和all_squash同时设置时,root仍被压缩,root_squash和no_all_squash同时设置时,root也被压缩。

有些导出选项需要配合其他设置。例如,导出选项设置为rw,但如果目录本身没有w权限,或者mount时指定了ro挂载选项,则同样不允许写操作。

至于别的导出选项,基本无需去关注。

在配置文件写好要导出的目录后,直接重启nfs服务即可,它会读取这些配置文件。随后就可以在客户端执行mount命令进行挂载。

例如,exports文件内容如下:

/vol/vol0       *(rw,no_root_squash)
/vol/vol2       *(rw,no_root_squash)
/backup/archive *(rw,no_root_squash)

1.4.2 挂载nfs文件系统

然后去客户端上挂载它们。

[root@xuexi ~]# mount -t nfs 172.16.10.5:/vol/vol0 /mp1
[root@xuexi ~]# mount 172.16.10.5:/vol/vol2 /mp2
[root@xuexi ~]# mount 172.16.10.5:/backup/archive /mp3

挂载时"-t nfs"可以省略,因为对于mount而言,只有挂载nfs文件系统才会写成host:/path格式。当然,除了mount命令,nfs-utils包还提供了独立的mount.nfs命令,它其实和"mount -t nfs"命令是一样的。

mount挂载时可以指定挂载选项,其中包括mount通用挂载选项,如rw/ro,atime/noatime,async/sync,auto/noauto等,也包括针对nfs文件系统的挂载选项。以下列出几个常见的,更多的内容查看man nfs和man mount。

选项

参数意义

默认值

suid

nosuid

如果挂载的文件系统上有设置了suid的二进制程序,

使用nosuid可以取消它的suid

suid

rw

ro

尽管服务端提供了rw权限,但是挂载时设定ro,则还是ro权限

权限取交集

rw

exec/noexec

是否可执行挂载的文件系统里的二进制文件

exec

user

nouser

是否运行普通用户进行档案的挂载和卸载

nouser

auto

noauto

auto等价于mount -a,意思是将/etc/fstab里设定的全部重挂一遍

auto

sync

nosync

同步挂载还是异步挂载

async

atime

noatime

是否修改atime,对于nfs而言,该选项是无效的,理由见下文

 

diratime

nodiratime

是否修改目录atime,对于nfs而言,该挂载选项是无效的,理由见下文

 

remount

重新挂载

 

以下是针对nfs文件系统的挂载选项。其中没有给出关于缓存选项(ac/noac、cto/nocto、lookupcache)的说明,它们可以直接采用默认值,如果想要了解缓存相关内容,可以查看man nfs。

选项

功能

默认值

fg/bg

挂载失败后mount命令的行为。默认为fg,表示挂载失败时将直接报错退出,如果是bg,

挂载失败后会创建一个子进程不断在后台挂载,而父进程mount自身则立即退出并返回0状态码。

fg

timeo

NFS客户端等待下一次重发NFS请求的时间间隔,单位为十分之一秒。

基于TCP的NFS的默认timeo的值为600(60秒)。

 

hard/soft

决定NFS客户端当NFS请求超时时的恢复行为方式。如果是hard,将无限重新发送NFS请求。

例如在客户端使用df -h查看文件系统时就会不断等待。

设置soft,当retrans次数耗尽时,NFS客户端将认为NFS请求失败,从而使得NFS客户端

返回一个错误给调用它的程序。

hard

retrans

NFS客户端最多发送的请求次数,次数耗尽后将报错表示连接失败。如果hard挂载选项生效,

则会进一步尝试恢复连接。

3

rsize

wsize

一次读出(rsize)和写入(wsize)的区块大小。如果网络带宽大,这两个值设置大一点能提升传

输能力。最好设置到带宽的临界值。

单位为字节,大小只能为1024的倍数,且最大只能设置为1M。

 

注意三点:

(1).所谓的soft在特定的环境下超时后会导致静态数据中断。因此,仅当客户端响应速度比数据完整性更重要时才使用soft选项使用基于TCP的NFS(除非显示指定使用UDP,否则现在总是默认使用TCP)或增加retrans重试次数可以降低使用soft选项带来的风险。

如果真的出现NFS服务端下线,导致NFS客户端无限等待的情况,可以强制将NFS文件系统卸载,卸载方法:

umount -f -l MOUNT_POINT

其中"-f"是强制卸载,"-l"是lazy umount,表示将该文件系统从当前目录树中剥离,让所有对该文件系统内的文件引用都强制失效。对于丢失了NFS服务端的文件系统,卸载时"-l"选项是必须的。

(2).由于nfs的客户端挂载后会缓存文件的属性信息,其中包括各种文件时间戳,所以mount指定时间相关的挂载选项是没有意义的,它们不会有任何效果,包括atime/noatime,diratime/nodiratime,relatime/norelatime以及strictatime/nostrictatime等。具体可见man nfs中"DATA AND METADATA COHERENCE"段的"File timestamp maintainence"说明,或者见本文末尾的翻译。

(3).如果是要开机挂载NFS文件系统,方式自然是写入到/etc/fstab文件或将mount命令放入rc.local文件中。如果是将/etc/fstab中,那么在系统环境初始化(exec /etc/rc.d/rc.sysinit)的时候会加载fstab中的内容,如果挂载fstab中的文件系统出错,则会导致系统环境初始化失败,结果是系统开机失败。所以,要开机挂载nfs文件系统,则需要在/etc/fstab中加入一个挂载选项"_rnetdev"或"_netdev"(centos 7中已经没有"_rnetdev"),防止无法联系nfs服务端时导致开机启动失败。例如:

172.16.10.5:/www    /mnt    nfs    defaults,_rnetdev    0    0

当导出目录后,将在/var/lib/nfs/etab文件中写入一条对应的导出记录,这是nfs维护的导出表,该表的内容会交给rpc.mountd进程,并在必要的时候(mountd接受到客户端的mount请求时),将此导出表中的内容加载到内核中,内核也单独维护一张导出表。

1.4.3 nfs伪文件系统

服务端导出/vol/vol0、/vol/vol2和/backup/archive后,其中vol0和vol1是连在一个目录下的,但它们和archive目录没有连在一起,nfs采用伪文件系统的方式来桥接这些不连接的导出目录。桥接的方式是创建那些未导出的连接目录,如伪vol目录,伪backup目录以及顶级的伪根,如下图所示。

当客户端挂载后,每次访问导出目录时,其实都是通过找到伪文件系统(文件系统都有id,在nfs上伪文件系统的id称为fsid)并定位到导出目录的。

1.5 showmount命令

使用showmount命令可以查看某一台主机的导出目录情况。因为涉及到rpc请求,所以如果rpc出问题,showmount一样会傻傻地等待。

主要有3个选项。

showmount [ -ade]  host
-a:以host:dir格式列出客户端名称/IP以及所挂载的目录。但注意该选项是读取NFS服务端/var/lib/nfs/rmtab文件,
  :而该文件很多时候并不准确,所以showmount -a的输出信息很可能并非准确无误的
-e:显示NFS服务端所有导出列表。
-d:仅列出已被客户端挂载的导出目录。

另外showmount的结果是排序过的,所以和实际的导出目录顺序可能并不一致。

例如:

[root@xuexi ~]# showmount -e 172.16.10.5
Export list for 172.16.10.5:
/backup/archive *
/vol/vol2       *
/vol/vol0       *
/www            172.16.10.4
[root@xuexi ~]# showmount -d 172.16.10.5
Directories on 172.16.10.5:
/backup/archive
/vol/vol0
/vol/vol2

1.6 nfs身份映射

NFS的目的是导出目录给各客户端,因此导出目录中的文件在服务端和客户端上必然有两套属性、权限集。

例如,服务端导出目录中某a文件的所有者和所属组都为A,但在客户端上不存在A,那么在客户端上如何显示a文件的所有者等属性。再例如,在客户端上,以用户B在导出目录中创建了一个文件b,如果服务端上没有用户B,在服务端上该如何决定文件b的所有者等属性。

所以,NFS采用uid/gid <==> username/groupname映射的方式解决客户端和服务端两套属性问题。由于服务端只能控制它自己一端的身份映射,所以客户端也同样需要身份映射组件。也就是说,服务端和客户端两端都需要对导出的所有文件的所有者和所属组进行映射。

但要注意,服务端的身份映射组件为rpc.idmapd,它以守护进程方式工作。而客户端使用nfsidmap工具进行身份映射。

服务端映射时以uid/gid为基准,意味着客户端以身份B(假设对应uid=Xb,gid=Yb)创建的文件或修改了文件的所有者属性时,在服务端将从/etc/passwd(此处不考虑其他用户验证方式)文件中搜索uid=Xb,gid=Yb的用户,如果能搜索到,则设置该文件的所有者和所属组为此uid/gid对应的username/groupname,如果搜索不到,则文件所有者和所属组直接显示为uid/gid的值。

客户端映射时以username/groupname为基准,意味着服务端上文件所有者为A时,则在客户端上搜索A用户名,如果搜索到,则文件所有者显示为A,否则都将显示为nobody。注意,客户端不涉及任何uid/gid转换翻译过程,即使客户端上A用户的uid和服务端上A用户的uid不同,也仍显示为用户A。也就是说,客户端上文件所有者只有两种结果,要么和服务端用户同名,要么显示为nobody。

因此考虑一种特殊情况,客户端上以用户B(其uid=B1)创建文件,假如服务端上没有uid=B1的用户,那么创建文件时提交给服务端后,在服务端上该文件所有者将显示为B1(注意它是一个数值)。再返回到客户端上看,客户端映射时只简单映射username,不涉及uid的转换,因此它认为该文件的所有者为B1(不是uid,而是username),但客户端上必然没有用户名为B1的用户(尽管有uid=B1对应的用户B),因此在客户端,此文件所有者将诡异地将显示为nobody,其诡异之处在于,客户端上以身份B创建的文件,结果在客户端上却显示为nobody。

综上考虑,强烈建议客户端和服务端的用户身份要统一,且尽量让各uid、gid能对应上。

1.7 使用exportfs命令导出目录

除了启动nfs服务加载配置文件/etc/exports来导出目录,使用exportfs命令也可以直接导出目录,它无需加载配置文件/etc/exports,当然exportfs也可以加载/etc/exports文件来导出目录。实际上,nfs服务启动脚本中就是使用exportfs命令来导出/etc/exports中内容的。

例如,CentOS 6上/etc/init.d/nfs文件中,导出和卸载导出目录的命令为:

[root@xuexi ~]# grep exportfs /etc/init.d/nfs  
        [ -x /usr/sbin/exportfs ] || exit 5
        action $"Starting NFS services: " /usr/sbin/exportfs -r
        cnt=`/usr/sbin/exportfs -v | /usr/bin/wc -l`
                action $"Shutting down NFS services: " /usr/sbin/exportfs -au
        /usr/sbin/exportfs -r

在CentOS 7上则如下:

[root@xuexi ~]# grep exportfs /usr/lib/systemd/system/nfs.service      
ExecStartPre=-/usr/sbin/exportfs -r
ExecStopPost=/usr/sbin/exportfs -au
ExecStopPost=/usr/sbin/exportfs -f
ExecReload=-/usr/sbin/exportfs -r

当然,无论如何,nfsd等守护进程是必须已经运行好的。

以下是CentOS 7上exportfs命令的用法。注意, CentOS 7比CentOS 6多一些选项。

-a     导出或卸载所有目录。
-o options,...
       指定一系列导出选项(如rw,async,root_squash),这些导出选项在exports(5)的man文档中有记录。
-i     忽略/etc/exports和/etc/exports.d目录下文件。此时只有命令行中给定选项和默认选项会生效。
-r     重新导出所有目录,并同步修改/var/lib/nfs/etab文件中关于/etc/exports和/etc/exports.d/
       *.exports的信息(即还会重新导出/etc/exports和/etc/exports.d/*等导出配置文件中的项)。该
       选项会移除/var/lib/nfs/etab中已经被删除和无效的导出项。
-u     卸载(即不再导出)一个或多个导出目录。
-f     如果/prof/fs/nfsd或/proc/fs/nfs已被挂载,即工作在新模式下,该选项将清空内核中导出表中
       的所有导出项。客户端下一次请求挂载导出项时会通过rpc.mountd将其添加到内核的导出表中。
-v     输出详细信息。
-s     显示适用于/etc/exports的当前导出目录列表。

例如:

(1).导出/www目录给客户端172.16.10.6。

exportfs 172.16.10.6:/www

(2).导出/www目录给所有人,并指定导出选项。

exportfs :/www -o rw,no_root_squash

(3).导出exports文件中的内容。

exportfs -a

(4).重新导出所有已导出的目录。包括exports文件中和exportfs单独导出的目录。

exportfs -ar

(5).卸载所有已导出的目录,包括exports文件中的内容和exportfs单独导出的内容。即其本质为清空内核维护的导出表。

exportfs -au

(6).只卸载某一个导出目录。

exportfs -u 172.16.10.6:/www

1.8 RPC的调试工具rpcdebug

在很多时候NFS客户端或者服务端出现异常,例如连接不上、锁状态丢失、连接非常慢等等问题,都可以对NFS进行调试来发现问题出在哪个环节。NFS有不少进程都可以直接支持调试选项,但最直接的调试方式是调试rpc,因为NFS的每个请求和响应都会经过RPC去封装。但显然,调试RPC比直接调试NFS时更难分析出问题所在。以下只介绍如何调试RPC。

rpc单独提供一个调试工具rpcdebug。

[root@xuexi ~]# rpcdebug -vh
usage: rpcdebug [-v] [-h] [-m module] [-s flags...|-c flags...]
       set or cancel debug flags.
 
Module     Valid flags
rpc        xprt call debug nfs auth bind sched trans svcsock svcdsp misc cache all
nfs        vfs dircache lookupcache pagecache proc xdr file root callback client mount fscache pnfs pnfs_ld state all
nfsd       sock fh export svc proc fileop auth repcache xdr lockd all
nlm        svc client clntlock svclock monitor clntsubs svcsubs hostcache xdr all

其中:

-v:显示更详细信息
-h:显示帮助信息
-m:指定调试模块,有rpc/nfs/nfsd/nlm共4个模块可调试。
  :顾名思义,调试rpc模块就是直接调试rpc的问题,将记录rpc相关的日志信息;
  :调试nfs是调试nfs客户端的问题,将记录nfs客户端随之产生的日志信息;
  :nfsd是调试nfs服务端问题,将记录nfsd随之产生的日志信息;
  :nlm是调试nfs锁管理器相关问题,将只记录锁相关信息
-s:指定调试的修饰符,每个模块都有不同的修饰符,见上面的usage中"Valid flags"列的信息
-c:清除或清空已设置的调试flage

例如设置调试nfs客户端的信息。

rpcdebug -m nfs -s all

当有信息出现时,将记录到syslog中。例如以下是客户端挂载nfs导出目录产生的信息,存放在/var/log/messages中,非常多,所以排解问题时需要有耐心。

Jul 29 11:24:04 xuexi kernel: NFS: nfs mount opts=\'vers=4,addr=172.16.10.9,clientaddr=172.16.10.3\'
Jul 29 11:24:04 xuexi kernel: NFS:   parsing nfs mount option \'vers=4\'
Jul 29 11:24:04 xuexi kernel: NFS:   parsing nfs mount option \'addr=172.16.10.9\'
Jul 29 11:24:04 xuexi kernel: NFS:   parsing nfs mount option \'clientaddr=172.16.10.3\'
Jul 29 11:24:04 xuexi kernel: NFS: MNTPATH: \'/tmp/testdir\'
Jul 29 11:24:04 xuexi kernel: --> nfs4_try_mount()
Jul 29 11:24:04 xuexi kernel: --> nfs4_create_server()
Jul 29 11:24:04 xuexi kernel: --> nfs4_init_server()
Jul 29 11:24:04 xuexi kernel: --> nfs4_set_client()
Jul 29 11:24:04 xuexi kernel: --> nfs_get_client(172.16.10.9,v4)
Jul 29 11:24:04 xuexi kernel: NFS: get client cookie (0xffff88004c561800/0xffff8800364cd2c0)
Jul 29 11:24:04 xuexi kernel: nfs_create_rpc_client: cannot create RPC client. Error = -22
Jul 29 11:24:04 xuexi kernel: --> nfs4_realloc_slot_table: max_reqs=1024, tbl->max_slots 0
Jul 29 11:24:04 xuexi kernel: nfs4_realloc_slot_table: tbl=ffff88004b71

以上是关于第3章 NFS基本应用的主要内容,如果未能解决你的问题,请参考以下文章

第12章 使用Samba或NFS实现文件共享

nfs 深度讲解及inotify

NFS架构搭建及配置

NFS架构搭建及配置

spark考试

NFS共享存储服务部署