做集群和高可用时,很快会遇到一个绕不开的问题:多台服务器怎么共享同一份文件?比如网站的两台 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 或分布式文件系统按场景取舍。
企业QQ咨询




