【Linux从入门到精通】第37篇:NFS网络文件系统——无状态的数据共享

目录

一、引言:当多台服务器需要同一份文件

二、NFS服务端配置

[2.1 安装NFS服务](#2.1 安装NFS服务)

[2.2 创建共享目录](#2.2 创建共享目录)

[2.3 配置exports文件](#2.3 配置exports文件)

[2.4 应用配置并启动](#2.4 应用配置并启动)

三、客户端挂载

[3.1 安装客户端工具](#3.1 安装客户端工具)

[3.2 查看服务端共享的目录](#3.2 查看服务端共享的目录)

[3.3 挂载到本地](#3.3 挂载到本地)

[3.4 开机自动挂载](#3.4 开机自动挂载)

[四、hard vs soft:NFS卡死的根源](#四、hard vs soft:NFS卡死的根源)

[4.1 hard模式(默认)](#4.1 hard模式(默认))

[4.2 soft模式](#4.2 soft模式)

[4.3 深入理解:为什么hard会导致D状态?](#4.3 深入理解:为什么hard会导致D状态?)

[4.4 如何选择?生产环境的折中方案](#4.4 如何选择?生产环境的折中方案)

五、NFS故障排查

[5.1 诊断命令](#5.1 诊断命令)

[5.2 常见问题](#5.2 常见问题)

六、现代替代方案简介

七、本篇小结

动手练习

八、下篇预告


一、引言:当多台服务器需要同一份文件

假设你的Web应用部署在3台服务器上,用户上传的头像需要所有服务器都能访问。你会怎么解决?

  • 方案一:每台服务器存一份?存储浪费,更难搞的是"数据一致性"------用户换头像后,三台机器上哪份是最新的?

  • 方案二:FTP/SCP手动同步?太慢,而且文件一多就乱套

  • 方案三 :用一台服务器专门存文件,其他服务器像访问本地目录一样访问它

方案三就是NFS的设计初衷。NFS是1984年由Sun公司开发的网络文件系统协议,至今已有40年历史。它的核心理念是:把远程服务器上的目录,挂载到本地目录树上,让用户和应用程序感觉不到它在远程

二、NFS服务端配置

2.1 安装NFS服务

bash

复制代码
# Ubuntu/Debian
sudo apt update && sudo apt install nfs-kernel-server -y

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

2.2 创建共享目录

bash

复制代码
sudo mkdir -p /srv/nfs/shared
sudo chown nobody:nogroup /srv/nfs/shared
sudo chmod 755 /srv/nfs/shared

为什么用nobody用户? NFS默认会对客户端的root用户做"权限压缩"(root squash),将client端的root映射为nobody,防止客户端以root身份任意修改服务端文件。这是NFS的一项安全设计。服务端目录的属主设为nobody:nogroup,配合这个机制使用。

2.3 配置exports文件

NFS通过/etc/exports文件控制哪些目录被共享、共享给谁、以什么权限共享:

bash

复制代码
sudo vim /etc/exports

text

复制代码
/srv/nfs/shared 192.168.1.0/24(rw,sync,no_subtree_check)

字段逐一解读

这条共享规则由三部分组成:共享目录 + 允许访问的客户端网段 + (选项)

组件 内容 含义
共享目录 /srv/nfs/shared 要共享出去的本地目录
客户端 192.168.1.0/24 允许访问的IP网段,也可以用*允许所有(不推荐),或写具体IP
选项 rw 读写权限(ro为只读)
选项 sync 同步写入:客户端写入操作必须等数据真正写入磁盘后才返回确认。数据安全性高,性能略低
选项 no_subtree_check 不检查子目录权限,提升性能

async vs sync的关键区别

选项 行为 优缺点
sync 数据必须写入磁盘后才回复客户端"写入完成" 数据安全性高,性能略低(推荐
async 数据写入内存后立即回复,延迟写入磁盘 性能好,但服务器突然宕机可能丢失数据

安全建议 :生产环境如果不确定所有客户端都是可信的,建议加root_squash(通常默认开启)让客户端的root用户操作被映射为nobody,限制其对共享目录的权限。

2.4 应用配置并启动

bash

复制代码
# 重新加载exports配置(不中断现有NFS连接)
sudo exportfs -ra

# 查看当前已共享的目录
sudo exportfs -v

# 确保NFS服务开机自启
sudo systemctl enable --now nfs-kernel-server   # Ubuntu/Debian
sudo systemctl enable --now nfs-server          # CentOS/RHEL
  • exportfs -r:重新读取/etc/exports并更新共享列表

  • -a:导出所有在exports中定义的目录

  • -v:显示详细输出

三、客户端挂载

3.1 安装客户端工具

bash

复制代码
# Ubuntu/Debian
sudo apt install nfs-common -y

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

3.2 查看服务端共享的目录

在挂载之前,先看看服务器提供了哪些共享:

bash

复制代码
# 列出NFS服务器上的所有共享目录
showmount -e 192.168.1.100

输出示例:

text

复制代码
Export list for 192.168.1.100:
/srv/nfs/shared 192.168.1.0/24

3.3 挂载到本地

bash

复制代码
# 创建本地挂载点
sudo mkdir -p /mnt/nfs

# 挂载
sudo mount -t nfs 192.168.1.100:/srv/nfs/shared /mnt/nfs

验证:

bash

复制代码
df -h | grep nfs
cd /mnt/nfs
echo "Hello NFS" > test.txt
# 如果能在服务端 /srv/nfs/shared 目录下看到这个文件,说明挂载成功

3.4 开机自动挂载

编辑/etc/fstab,添加一行:

text

复制代码
192.168.1.100:/srv/nfs/shared  /mnt/nfs  nfs  defaults  0  0

关于fstab的配置,我们在第13篇讲过。这里的defaults相当于rw,suid,dev,exec,auto,nouser,async。你可能会注意到async------这是客户端挂载的默认选项,它控制的是客户端缓存 行为,与第2节服务端的sync选项(控制服务端写入行为)是不同的概念。

安全建议:如果NFS用于敏感数据,建议在fstab中显式指定安全选项,如:

text

复制代码
192.168.1.100:/srv/nfs/shared  /mnt/nfs  nfs  rw,hard,intr,noexec  0  0

四、hard vs soft:NFS卡死的根源

这是NFS最核心的两个挂载选项,直接决定了NFS出问题时客户端的行为。

4.1 hard模式(默认)

当NFS服务器无响应时,hard模式下的行为是:

  • 客户端持续不断重试,直到NFS服务器恢复正常

  • 在此期间,访问NFS挂载点的进程会进入不可中断睡眠状态(D状态) ,无法被kill -9杀死

  • 这就是第11篇进程管理中提到的D状态------你在服务器上执行df -h,如果恰好挂载了一个无响应的NFS目录,df命令就会挂住不动,Ctrl+C也无效

适用场景:数据完整性要求高,短暂的"卡住等待"可以接受。

4.2 soft模式

soft模式下,当NFS服务器无响应时:

  • 客户端重试指定的次数后,放弃并向应用程序返回错误

  • 进程不会永久挂起,可以被正常终止

  • 代价是数据可能丢失------如果写入操作在服务端宕机时返回了错误,应用需要自行处理重试

适用场景:可用性优先,宁可让请求失败也不能让进程挂死。

4.3 深入理解:为什么hard会导致D状态?

NFS的hard模式利用了内核的RPC(远程过程调用)机制。当I/O请求发出后,内核RPC层会不断重试,如果服务器持续不响应,调用进程就卡在内核的RPC等待队列中,形成不可中断睡眠(D状态)。

这种设计在理论上保证了数据可靠性(服务恢复后操作继续),但在实践中,如果NFS服务器长时间宕机,所有依赖NFS的进程都会像"排队等一个永远不回来的人"。

4.4 如何选择?生产环境的折中方案

bash

复制代码
# hard模式 + intr + timeo(推荐:既保证数据可靠,又允许Ctrl+C中断)
sudo mount -t nfs -o hard,intr,timeo=30 192.168.1.100:/srv/nfs /mnt/nfs
参数 含义 典型值
hard 服务器不响应时重试(保证数据可靠性) 默认
intr 允许用信号(Ctrl+C)中断hard模式的挂死操作 推荐添加
timeo=N 重试超时(单位:0.1秒) timeo=30即3秒
retrans=N 重试次数,超过后放弃 retrans=3
soft 超时后直接返回错误 非关键数据可用
retry=N 后台挂载重试时间(分钟) retry=1(系统启动时如果NFS不可用,后台尝试1分钟后放弃)

选择策略

  • 核心业务数据(如数据库文件、用户上传)→ hard,intr

  • 日志归档、临时缓存等可恢复数据 → soft

  • 系统启动时如果NFS依赖可能导致启动卡死 → fstab中加retry=1,让系统在NFS不可用时不至于无限等待

五、NFS故障排查

5.1 诊断命令

bash

复制代码
# 查看NFS挂载状态
nfsstat -m

# 查看RPC服务状态
rpcinfo -p 192.168.1.100

# 查看NFS服务器的共享列表
showmount -e 192.168.1.100

# 实时日志
sudo journalctl -u nfs-server -f

5.2 常见问题

问题一:客户端mount卡住不动

通常是防火墙阻止了NFS或RPC端口。NFS除了NFS主端口(2049)外,还依赖mountd、statd、lockd等RPC服务(端口不确定)。解决方案:

bash

复制代码
# 使用NFS v3时,需要放行RPC端口
sudo firewall-cmd --add-service=nfs --permanent
sudo firewall-cmd --add-service=rpc-bind --permanent
sudo firewall-cmd --add-service=mountd --permanent
sudo firewall-cmd --reload

NFS v4的简化优势 :如果客户端和服务端都支持NFSv4,可以在挂载时指定-o nfsvers=4,NFSv4只需要TCP 2049一个端口,极大简化防火墙配置。

问题二:Permission denied

客户端用户的UID与服务端文件属主的UID不匹配。NFS默认使用UID来判断权限,如果客户端和服务端上同名用户的UID不一致(如客户端zhangsan是UID 1001,服务端是UID 1002),就会出现权限拒绝:

bash

复制代码
# 检查客户端当前用户的UID
id -u

# 检查服务端共享目录的属主UID
ls -ln /srv/nfs/shared

解决方案:统一两边的UID(创建用户时指定useradd -u 统一UID),或使用NFSv4的Kerberos认证。

问题三:服务端重启后客户端挂载点卡死

如果服务端意外重启,客户端以hard模式挂载的NFS目录会持续重试,直到服务端恢复。检查客户端是否受影响:

bash

复制代码
df -h | grep nfs   # 如果输出卡住 = NFS挂死
lsof | grep /mnt/nfs   # 查看哪些进程在使用NFS挂载点

六、现代替代方案简介

NFS虽然经典,但在现代云原生环境中,有更适合的替代方案:

方案 特点 适用场景
GlusterFS 分布式文件系统,无中心节点,横向扩展 自建分布式存储
CephFS 高性能、可大规模扩展的分布式文件系统 私有云存储平台
MinIO 兼容S3 API的对象存储,单机部署简单 对象存储(图片、视频等非结构化数据)
rsync + inotify 半实时同步(1-3秒延迟),配置简单 少量服务器间的轻量级同步(下一篇详解)

如果你的需求是"多台Web服务器共享上传的图片",MinIO的S3接口通常比NFS更合适;如果有大量小文件需要强一致性共享,NFS依然是成熟、简单的选择。

七、本篇小结

NFS工作流程

text

复制代码
服务端:sudo apt install nfs-kernel-server
       vim /etc/exports → /srv/nfs/shared 192.168.1.0/24(rw,sync)
       exportfs -ra

客户端:showmount -e 服务器IP(查看共享)
       mount -t nfs 服务器IP:/共享目录 /本地挂载点

hard vs soft选择

选项 服务器故障时 数据安全性 适用场景
hard(默认) 进程进入D状态,持续重试 核心业务数据
hard,intr 可用Ctrl+C中断挂死 推荐折中方案
soft 超时后返回错误 低(丢失风险) 临时文件、缓存

动手练习

在两台虚拟机之间搭建NFS:

bash

复制代码
# === 服务端(NFS服务器) ===
# IP: 192.168.1.100
sudo apt install nfs-kernel-server -y
sudo mkdir -p /srv/nfs/shared
sudo chown nobody:nogroup /srv/nfs/shared
echo "/srv/nfs/shared 192.168.1.0/24(rw,sync,no_subtree_check)" | sudo tee -a /etc/exports
sudo exportfs -ra
sudo exportfs -v   # 验证共享列表

# === 客户端 ===
# IP: 192.168.1.101
sudo apt install nfs-common -y
showmount -e 192.168.1.100   # 先查看共享
sudo mkdir -p /mnt/nfs
sudo mount -t nfs 192.168.1.100:/srv/nfs/shared /mnt/nfs
echo "Hello from client" | sudo tee /mnt/nfs/test.txt   # 写入测试
# 切回服务端验证
cat /srv/nfs/shared/test.txt   # 应该看到客户端的写入

八、下篇预告

NFS解决了"多台服务器共享同一份数据",但它的同步是实时的------文件一写入,所有客户端都能立刻看到。如果不需要那么高的实时性,而是需要"定期把文件同步到备份服务器",rsync是更好的选择。

下一篇我们将学习rsync与inotify------rsync负责增量同步(只传变化的部分),inotify负责监控文件变化并自动触发同步。两者组合,实现"文件一变,秒级同步到备份机"的效果。


延伸思考 :NFS协议本身是无状态的。这意味着服务器端不记录"哪些客户端打开了哪些文件"------如果你在客户端A上打开了一个文件,服务器宕机重启后,客户端A需要重新建立连接,而文件锁可能丢失。这与Samba(SMB协议)的状态化设计形成对比。理解"无状态"和"有状态"的取舍,是做好分布式系统选型的基础。

相关推荐
暴力求解4 小时前
Linux---保存信号
linux·运维·服务器·开发语言·操作系统
Bruce_Liuxiaowei4 小时前
CVE-2026-31431 (Copy Fail) 漏洞复现与验证记录
linux·安全·漏洞复现·cve-2026-31431
Name_NaN_None4 小时前
Android 手机投屏 iPad :公网+局域网免费方案
网络·计算机外设·电脑·远程工作
2401_873479404 小时前
深度解析IP查询工具与普通IP库的核心区别:选型指南与业务场景对照
网络协议·tcp/ip·php
张晓℡¹⁸⁰³⁷¹⁸²⁵⁵⁸4 小时前
海外盲盒APP玩法集合,海外盲盒多国语言
小程序·php
bqq198610264 小时前
Ubuntu vs CentOS
linux·服务器
古城小栈4 小时前
rust 亿级并发模型,实践完成
开发语言·网络·rust
垦利不4 小时前
websocket通信
网络·websocket·网络协议