NFS 服务部署与性能调优实战:从共享目录到生产可用

NFS 是内网共享存储里最常用的方案:部署简单、原生支持 Unix 权限语义,适合多台主机共享数据目录、备份落点和应用上传目录。本文把一台 Rocky Linux 9 主机做成「生产可用」的 NFS 服务端,并带上客户端挂载、自动挂载、性能要点和排障方法。Ubuntu 差异会在相应步骤注明。

前置条件

  • 服务端一台(node-01,IP 192.0.2.10),客户端若干台,网络互通,均有 sudo/root 权限;
  • 共享目录所在磁盘空间充足,已规划挂载点(这里用 /data/share);
  • 了解 NFSv4 走 TCP 2049 端口,NFSv3 还需 rpcbind 等辅助服务,本文以 NFSv4 为主。

第一步:安装并准备共享目录

Rocky Linux 9 上两端都装 nfs-utils:

sudo dnf install -y nfs-utils
sudo mkdir -p /data/share
sudo chown nobody:nobody /data/share
sudo chmod 755 /data/share

Ubuntu 对应命令为 sudo apt install -y nfs-kernel-server nfs-common,客户端只装 nfs-common。目录属主先设 nobody 是为了让 squash(用户映射)行为可预期,业务目录按读写进程的 UID/GID 设置。

第二步:编写 exports 并逐项理解权限选项

共享清单写在 /etc/exports,每行格式为「目录 允许的主机(选项)」。生产推荐写法:

/data/share 192.0.2.0/24(rw,sync,no_subtree_check,root_squash)

逐项解释这几个最关键的选项:

  • rw / ro:可写 / 只读。目录本身还要有文件系统权限,exports 放行不等于目录可写。
  • sync:写操作落盘后才回复客户端,数据安全;async 先回复后落盘,性能好但宕机丢数据,只用于可再生数据。
  • no_subtree_check:关闭子树检查。导出完整文件系统时可提升稳定性;导出子目录时保留默认的 subtree_check 更安全。
  • root_squash:把客户端 root 映射成 nobody,这是默认值,务必保留。no_root_squash 等于把服务端目录的 root 权限交给客户端 root,能控制客户端的人就能改共享文件,只在磁盘镜像、安装源等特殊场景短暂使用。
  • all_squash + anonuid/anongid:把所有用户映射为指定 UID,适合公共投递目录。

改完配置后导出并启动服务:

sudo exportfs -ra
sudo systemctl enable --now nfs-server
sudo firewall-cmd --permanent --add-service=nfs
sudo firewall-cmd --reload

firewalld 放行 nfs 服务即可(NFSv4 只需 2049/TCP)。Ubuntu 用 ufw 时:sudo ufw allow from 192.0.2.0/24 to any port 2049 proto tcp。

第三步:客户端挂载与自动挂载

客户端手工挂载验证连通性,再谈自动挂载:

sudo dnf install -y nfs-utils
sudo mkdir -p /mnt/share
sudo mount -t nfs -o vers=4.2,rw,hard,timeo=600,retrans=2 192.0.2.10:/data/share /mnt/share

开机自动挂载有两种主流方案,要看场景取舍:

  • /etc/fstab:写法直观,但服务端不可达会拖慢开机,加 _netdev,nofail 兜底:
192.0.2.10:/data/share  /mnt/share  nfs  defaults,_netdev,nofail,hard  0  0
  • systemd automount:开机不挂载、首次访问才挂、空闲自动卸载,服务端偶尔停机时更稳妥。建与挂载点同名的两个单元:
# /etc/systemd/system/mnt-share.automount
[Unit]
Description=Automount NFS share

[Automount]
Where=/mnt/share
TimeoutIdleSec=600

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now mnt-share.automount

取舍:持续写入型目录用 fstab 常驻挂载;偶尔访问的归档目录用 automount。

第四步:性能要点

  • rsize/wsize:单次读写块大小。现代内核默认值(最大 1M)通常已足够,不要盲目抄老文章的 8192;千兆以上网络可显式写 rsize=1048576,wsize=1048576 并实测对比。
  • nconnect(内核 5.3+):为一个挂载点建多条 TCP 连接,高并发小文件场景提升明显:mount -o nconnect=4 ...,一般 2–4 条即可。
  • async 的代价:服务端 async 能显著提升写吞吐,但宕机丢数据;只在备份中转这类数据可重建的场景考虑。
  • 服务端线程数:并发高时调大 /etc/nfs.conf 中 threads=(默认 8),配合观察 nfsstat -s。
  • atime:客户端加 noatime 减少无谓的元数据写入。

验证

# 服务端看导出清单
sudo exportfs -v
# 客户端看挂载与连通性
showmount -e 192.0.2.10
findmnt /mnt/share
echo hello > /mnt/share/test.txt && cat /mnt/share/test.txt

预期:exportfs -v 能看到目录与选项,showmount 列出导出目录,客户端写入后服务端 /data/share 下出现 test.txt。

常见问题

  • 挂载卡死无响应:多半用了 soft 挂载或网络不通。生产坚持 hard 挂载(一直重试而非报错丢数据),网络恢复后进程自动继续。要强制中断先试 umount -f /mnt/share,仍无效用 umount -l 懒卸载。
  • Stale file handle(文件句柄过期):服务端目录被删除重建、文件系统重挂载后,客户端旧句柄失效。客户端 umount /mnt/share && mount /mnt/share 重挂即可;根因上别在服务端直接删除正在导出的目录。
  • Permission denied 但 exports 明明放行:依次查三点:目录权限与属主(UID/GID 两端不一致最常见)、root 被 root_squash 拒绝属正常行为(改用业务用户)、SELinux 开启时需 sudo setsebool -P nfs_export_all_rw on。
  • showmount 超时、rpcinfo 查不到:NFSv3 依赖 rpcbind(111 端口)与 mountd,防火墙只放 2049 时就会这样;只用 NFSv4 时挂载参数明确写 vers=4.2。用 rpcinfo -p 192.0.2.10 看各程序注册情况。

小结

NFS 不难,难的是把选项语义搞清楚:sync 保数据、root_squash 保安全,这两项不要为了省事关掉。自动挂载按「服务端是否会停机、客户端开机是否能等」在 fstab 与 systemd automount 之间选。性能上先保证 hard 挂载和合理线程数,再按实测调 nconnect。

发表回复

后才能评论