多台服务器如何共享文件?NFS网络文件系统配置教程

做集群和高可用时,很快会遇到一个绕不开的问题:多台服务器怎么共享同一份文件?比如网站的两台 Nginx 都要读取用户上传的图片,两台应用服务器都要写日志,或者主备节点要访问同一份数据。如果每台机器各自存一份,就会出现文件不同步、上传到 A 机器而用户请求被 B 机器处理导致"图片 404"这类问题。解决办法之一,就是把文件集中放在一台服务器上,其他机器通过 NFS 挂载使用。

NFS(Network File System,网络文件系统)是 Linux 上最常用的文件共享方案,通过它可以把远程目录挂载到本地,像使用本地目录一样读写。这篇文章带你从零搭一套 NFS:服务端怎么配 /etc/exports,rw、ro、sync、no_root_squash 这些参数是什么含义、有什么风险,怎么启动 nfs-server 和 rpcbind,客户端怎么 mount、怎么写 /etc/fstab、怎么用 autofs 按需挂载,防火墙要放行哪些端口,以及性能、单点、锁与并发写这些生产里必须注意的问题。最后对比 NFS 与云 NAS 的取舍。

NFS 是什么,为什么需要它

NFS 是一种分布式文件共享协议,由服务端导出(export)一个或多个目录,客户端通过网络把这些目录挂载到本地路径。挂载之后,客户端读写这些目录,操作实际上是在服务端完成的,对应用程序而言和本地磁盘几乎没有区别。

它最常见的用途有三类。其一是多台 Web 服务器共享用户上传目录,保证任何一台服务器都能读到用户上传的文件。其二是集群里共享配置文件或只读数据,比如多台机器读取同一份字典、模板。其三是作为主备切换时的共享存储,让主备都能访问同一份数据。NFS 还常和 Kubernetes 的持久卷、容器共享存储一起使用。

NFS 有几个版本,目前主流是 NFSv3 和 NFSv4。NFSv3 依赖 rpcbind 做端口映射,端口分散;NFSv4 只用一个端口 2049,支持更完善的认证和状态管理,新环境优先用 v4。这篇文章的命令以 NFSv4 为主,同时说明 v3 的差异。

要提醒的是,NFS 解决的是"共享访问",不是"高可用"。NFS 服务端本身是单点,一旦宕机,所有挂载它的客户端读写都会卡住。后面会专门讲单点问题的应对。

服务端:安装与 /etc/exports 配置

先确认服务端和客户端的机器信息。示例环境:服务端 192.0.2.61,客户端 192.0.2.62、192.0.2.63,共享目录 /srv/nfs/data,网段 192.0.2.0/24。

在服务端安装 NFS 服务。RHEL/CentOS/Rocky 系安装 nfs-utils:

# RHEL / CentOS / Rocky 系
sudo dnf install -y nfs-utils
sudo systemctl enable --now nfs-server
sudo systemctl enable --now rpcbind

Debian/Ubuntu 系安装 nfs-kernel-server:

# Debian / Ubuntu 系
sudo apt update
sudo apt install -y nfs-kernel-server
sudo systemctl enable --now nfs-server
sudo systemctl enable --now rpcbind

创建共享目录并设置权限。示例让所有客户端以特定用户身份访问,这里创建一个专用目录:

sudo mkdir -p /srv/nfs/data
sudo chown -R nobody:nobody /srv/nfs/data
sudo chmod 755 /srv/nfs/data

核心配置在 /etc/exports,一行一个导出项,格式是"目录 客户端(选项)":

# /etc/exports
/srv/nfs/data 192.0.2.0/24(rw,sync,no_subtree_check)

这一行表示把 /srv/nfs/data 导出给 192.0.2.0/24 网段,可读写、同步写入、不检查子树。若只想给特定客户端只读权限,可以这样写:

/srv/nfs/data 192.0.2.62(ro,sync,no_subtree_check)
/srv/nfs/data 192.0.2.63(ro,sync,no_subtree_check)

改完配置后,让导出生效:

sudo exportfs -ra
sudo exportfs -v

exportfs -ra 重新导出所有配置,-v 显示当前导出列表,确认目录、客户端和选项正确。

关键选项与风险提示

理解导出选项,是安全配置 NFS 的关键。

rw 和 ro 控制读写权限。rw 允许客户端写入,ro 只读。共享上传目录用 rw,共享只读数据用 ro。

sync 和 async 控制服务端是否等数据真正落盘再响应。sync 更安全,但性能较低;async 性能好,但服务端突然断电可能丢数据。生产环境对数据可靠性敏感的目录用 sync,对性能要求极高且可容忍少量丢失的临时目录才考虑 async。默认且推荐 sync。

root_squash 和 no_root_squash 控制 root 权限映射。默认 root_squash 会把客户端的 root 用户映射成匿名用户(nobody),也就是说客户端 root 在共享目录里没有 root 权限,这是安全的默认行为。no_root_squash 则保留客户端 root 的权限——这是一个高风险选项:客户端机器的 root 用户可以对共享目录做任意操作,如果客户端被入侵,攻击者可以直接篡改或删除服务端共享数据。除非你完全信任所有客户端且确有需要(某些老应用必须以 root 写入),否则不要开 no_root_squash。

no_subtree_check 关闭子树检查,多数场景可以提升兼容性和性能,是推荐值。all_squash 把所有客户端用户都映射成匿名用户,适合只关心共享、不关心具体用户归属的场景。

可以用 showmount 在客户端查看服务端导出了哪些目录:

showmount -e 192.0.2.61

客户端:mount 与 /etc/fstab 持久化

客户端也要安装 nfs 客户端工具。RHEL/CentOS/Rocky 系同样装 nfs-utils,Debian/Ubuntu 系装 nfs-common:

# RHEL / CentOS / Rocky 系
sudo dnf install -y nfs-utils

# Debian / Ubuntu 系
sudo apt install -y nfs-common

创建本地挂载点并挂载:

sudo mkdir -p /mnt/nfs/data
# NFSv4 推荐写法,只写服务端 IP 和导出路径
sudo mount -t nfs -o vers=4.2 192.0.2.61:/srv/nfs/data /mnt/nfs/data

挂载后用 df -h 确认,往目录里写文件再回到服务端检查,验证共享是否生效。NFSv4 的路径是服务端的导出路径,若用 NFSv3 则可能写作 192.0.2.61:/srv/nfs/data 配合 rpcbind。

要让挂载在重启后自动生效,写入 /etc/fstab。但直接写死有个大坑:如果服务端不可达,客户端启动时会卡在挂载步骤,导致系统启动缓慢甚至失败。所以要用带容错选项的写法:

# /etc/fstab
192.0.2.61:/srv/nfs/data  /mnt/nfs/data  nfs  vers=4.2,_netdev,soft,timeo=30,retrans=2,noatime  0 0

这里几个选项很关键。_netdev 表示这是网络设备,等网络就绪后再挂载。soft 表示服务端无响应时超时返回错误,而不是无限等待(硬挂载 hard 会因为服务端宕机导致客户端进程永久卡死,需谨慎选择),soft 适合不希望被卡死的场景,但可能因超时导致数据写入不完整,需要应用能容忍。timeo 是超时时间(单位是 0.1 秒,30 即 3 秒),retrans 是重试次数。noatime 关闭访问时间更新,减少写操作。

改完 fstab 后先测试再重启,避免直接重启导致系统起不来:

# 风险提示:先验证配置,避免重启时挂载失败导致启动异常
sudo mount -a
findmnt /mnt/nfs/data

mount -a 会按 fstab 挂载所有未挂载项,出错会提示。确认无误后再考虑重启。风险提示: 如果误配 fstab 导致系统启动卡住,可在单用户模式或救援模式下注释掉对应行后重启。

用 autofs 实现按需挂载

fstab 是开机就挂载,长时间不用占着连接。autofs 则按需挂载:只有真正访问某个目录时才连接服务端,一段时间不访问自动卸载。它适合访问不频繁、客户端数量多的场景,也能避免服务端不可达时影响客户端启动。

安装 autofs。RHEL/CentOS/Rocky 系:

# RHEL / CentOS / Rocky 系
sudo dnf install -y autofs
sudo systemctl enable --now autofs

Debian/Ubuntu 系:

# Debian / Ubuntu 系
sudo apt install -y autofs
sudo systemctl enable --now autofs

配置主映射文件 /etc/auto.master,加一行指向子映射:

# /etc/auto.master
/mnt/nfs  /etc/auto.nfs  --timeout=300

再创建子映射 /etc/auto.nfs,定义具体挂载:

# /etc/auto.nfs
data  -fstype=nfs4,soft,timeo=30  192.0.2.61:/srv/nfs/data

这样访问 /mnt/nfs/data 时才触发挂载,300 秒无访问后自动卸载。改完重启 autofs:

sudo systemctl restart autofs

autofs 的好处是客户端不需要在 fstab 里写死每一条共享,维护更灵活,尤其适合共享目录经常增减的环境。

防火墙放行与端口说明

NFS 的防火墙配置是新手最容易卡住的地方。NFSv3 涉及多个端口:rpcbind 在 111(TCP/UDP),nfsd 在 2049,还有 mountd、statd 等动态端口,配置繁琐。NFSv4 只用一个 2049 端口,简单得多。

服务端放行 2049。RHEL/CentOS/Rocky 系用 firewalld:

# RHEL / CentOS / Rocky 系
sudo firewall-cmd --permanent --add-service=nfs
sudo firewall-cmd --permanent --add-service=mountd
sudo firewall-cmd --permanent --add-service=rpc-bind
sudo firewall-cmd --reload
sudo firewall-cmd --list-services

firewalld 内置了 nfs、mountd、rpc-bind 这几个服务定义,直接用 add-service 即可。若用 NFSv4,最小只需放行 nfs(2049)。

Debian/Ubuntu 系用 ufw,需要按端口放行,并把客户端来源限制在内网:

# Debian / Ubuntu 系
sudo ufw allow from 192.0.2.0/24 to any port 2049 proto tcp
sudo ufw allow from 192.0.2.0/24 to any port 111 proto tcp
sudo ufw allow from 192.0.2.0/24 to any port 111 proto udp
sudo ufw status verbose

NFSv3 还需要放行动态端口,通常做法是在 /etc/nfs.conf 或 /etc/sysconfig/nfs 里把 mountd、statd 的端口固定下来,再逐一放行。

风险提示: 修改防火墙前确认 SSH 端口已放行并有控制台可用,避免误封失联。NFS 坚决不要对公网开放,历史上大量数据泄露都是 NFS 未授权访问造成的,共享目录应只对可信内网地址导出。

性能、单点与锁的注意事项

NFS 用起来简单,但生产里这几个问题必须想清楚。

性能方面,NFS 的性能受网络、服务端磁盘和后端存储影响很大,通常不如本地磁盘。经验上,千兆网络下的 NFS 顺序读写大约能跑到 100 到 110 兆字节每秒,具体取决于磁盘和网络。大量小文件、随机 IO 的场景性能更差,因为每个操作都要走网络往返。可以考虑挂载时调整 rsize、wsize(读写块大小,NFSv4 下通常无需手动设置或设为 1M)来提升吞吐。对性能敏感的共享存储,建议用更高带宽的网络、SSD 后端,或者改用云 NAS。

单点方面,NFS 服务端是明确的单点,一旦宕机,所有客户端的挂载都会卡住,写入可能失败甚至丢数据。降低单点风险的思路有几种:用 DRBD 加 Keepalived 做 NFS 服务端的主备;用云厂商提供的托管 NAS 服务,由平台保证高可用;用分布式文件系统(如 CephFS、GlusterFS)替代单点 NFS。选择哪条路取决于业务对可用性和复杂度的容忍。

锁与并发写方面,NFS 支持文件锁(NLM 或 NFSv4 内建锁),但跨客户端的锁行为在不同版本和实现下有差异。多台客户端同时写同一个文件,非常容易出现内容交错、覆盖、损坏。正确做法是:尽量不要让多台机器写同一个文件;必须共享写入时,用应用层的锁或队列串行化;日志类场景让每台机器写自己的文件,避免共享追加。数据库文件、SQLite 这类文件也不适合放在 NFS 上共享写入,会导致数据损坏。

另外要注意,服务端重建、IP 变化、导出目录变更后,客户端的挂载可能失效,需要重新挂载。监控上要关注 NFS 服务端的状态和客户端的挂载健康度,出现 nfs: server not responding 这类日志要及时告警。

NFS 与云 NAS 的对比

对比项 自建 NFS 云 NAS(主流云厂商托管)
部署运维 自己安装配置维护 平台托管,开箱即用
高可用 需自行做主备或集群 平台保证多副本与容灾
扩容 受单机磁盘和带宽限制 通常可在线扩容
成本 服务器与带宽成本 按容量和流量计费
性能 取决于自身硬件和网络 多档规格,按需选择
适用场景 内网可控、成本敏感 云上业务、追求省心

自建 NFS 适合内网环境、对成本敏感、数据量不大的场景;云 NAS 适合已经上云、希望省去运维、对可用性有要求的场景。两者本质上都是网络文件共享,选择看的是运维能力和成本权衡。需要注意的是,无论哪种,都不适合多机并发写同一文件。

常见问题

客户端挂载后连不上或超时怎么办?

先确认服务端 2049(和 v3 的 111)端口可达,用 showmount -e 服务端IP 查看导出,检查 /etc/exports 里的客户端网段是否包含本机 IP,再看服务端防火墙是否放行。

挂载目录里的文件属主显示成 nobody 怎么办?

这是 root_squash 的默认行为,客户端的 root 被映射成匿名用户。若业务需要保留属主,可考虑 no_root_squash(有安全风险)或调整共享目录的属主和权限,让应用以固定用户访问。

NFS 服务端重启后客户端卡住怎么办?

客户端如果用了硬挂载(hard),服务端无响应时进程会一直等待。可以考虑改用 soft 选项,或配置自动重挂载和监控告警。服务端恢复后,部分客户端可能需要重新挂载。

多台机器同时写同一个文件会有问题吗?

会有问题。NFS 的跨客户端锁行为有限,并发写容易导致内容损坏。应避免多机写同一文件,改用每机独立文件或用应用层串行化。

NFS 能替代对象存储吗?

不能完全替代。NFS 提供文件系统语义,支持随机读写和文件锁;对象存储面向不可变对象,更适合海量非结构化数据和静态资源。场景不同,按需选择。

总结

  • NFS 让多台服务器共享同一份文件,服务端导出目录,客户端挂载后像本地目录一样使用,新环境优先用 NFSv4。
  • /etc/exports 用 rw/ro 控制读写、sync 保证落盘、no_subtree_check 提升兼容性,no_root_squash 有安全风险要慎用。
  • 客户端挂载建议写进 /etc/fstab 并加 _netdev、soft 等容错选项,访问不频繁的场景可用 autofs 按需挂载。
  • 防火墙放行 2049(NFSv4)或 111 等端口,NFS 只对可信内网导出,绝不能暴露公网。
  • NFS 服务端是单点,性能受网络和磁盘影响,多机并发写同一文件有风险,需与云 NAS 或分布式文件系统按场景取舍。