做文件共享选型时,最常被扔到台面上的两个名字就是 SMB 和 NFS。我早期做混合环境运维时,也在这两者之间踩过不少坑:同一个文件服务,Windows 客户端连着 SMB 一直很稳,换成 Linux 挂载之后就各种超时;反过来,NFS 在嵌入式开发板上跑得飞快,同事拿到 Windows 上看目录却直接黑屏转圈。那时候才真正意识到,这两套协议不是谁替代谁的问题,而是各自带着鲜明的“出身”和“脾气”。这篇文章就结合我这些年的实际使用经历,把 SMB 和 NFS 的核心差异、适用场景、配置要点和排错思路完整捋一遍,给正在做选型或者被共享问题折磨的朋友一个能直接落地的参考。
1. SMB 与 NFS 的核心差异:从设计思想到实际表现
1.1 两者到底是怎么来的,决定了它们现在的行为方式
NFS 诞生于 UNIX 大家庭,设计初衷是让无盘工作站和服务器之间共享文件系统,整个协议从骨子里就带着“让机器之间高效率协作”的基因。早期的 NFS 是典型的状态少、结构简单,客户端发一个请求,服务器给一个回应,不太关心你是谁、从哪来,只关心权限位和文件路径。这种思路在局域网环境下极其高效,开销低、响应快,至今还是嵌入式、科学计算和 Linux 服务器集群的首选。
SMB 则是微软体系里的“会话型”协议,最早是为了支持 DOS 和 Windows 局域网内的文件打印共享而生。它强调的不是“高效传输”,而是“像本地磁盘一样被访问”——要有登录验证、要有会话保持、要有文件锁定、要有打印机管理、还要有各种扩展通知。你会发现 SMB 的交互流程比 NFS 重得多,但这恰恰是它在 Windows 生态里无人能敌的原因:域环境、ACL 权限、文件审计、脱机缓存,这些企业级需求全都被 SMB 吸收得明明白白。
用一个不严谨但好记的比喻:NFS 像“快递柜”,你把包裹放进去,取件人凭取件码来拿,过程简单直接;SMB 像“公司前台”,来人先登记、再引导、还记录每次进出,过程繁琐但安全可控。快递柜适合熟客提速,前台适合访客管理,选谁取决于你的场景更像“熟客”还是“访客”。
1.2 协议版本演进:NFS v3/v4 与 SMB 1/2/3 的路线差异
不少新手看到“NFS”和“SMB”就默认它们是单一协议,实际操作时才发现版本差异巨大。NFSv3 是最广泛使用的经典版本,无状态设计让它在网络抖动后恢复异常迅速,特别适合嵌入式环境。NFSv4 引入了有状态、锁管理和安全增强,还支持 Kerberos 认证,但付出的是更复杂的配置和更高的互动成本。NFSv4.1 加了 pNFS 并行数据路径,企业级存储阵列里用得比较多。如果你只是做普通的 Linux 间共享,或者给开发板挂载根文件系统,NFSv3 很多时候反而更省心。
SMB 这边的情况更“惊险”:SMB1 已经因为永恒之蓝等漏洞成了过街老鼠,现在任何正经环境里都应该禁掉。SMB2/3 才是现代 Windows 的默认协议,SMB3 更是加入了多通道、加密、RDMA、持续可用性等一堆特性,在企业级 NAS 和 Windows Server 上表现非常抢眼。安全意识差且历史包袱重的环境,最容易踩的坑就是 SMB1 残留,这在故障排查章节我会展开讲。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 性能表现与网络开销:同一批文件两种剧本
2.1 吞吐、延迟与小文件处理的真实差距
在纯 Linux 环境里做 10GbE 网络下的文件拷贝,NFSv3 往往能轻松跑满带宽,CPU 占用率明显低于 SMB。原因很简单:NFS 请求头短、状态少、不需要频繁的协商和确认。而 SMB 因为带了会话上下文、文件句柄状态和更重的消息头,同等硬件条件下吞吐量会打个折扣——尤其在大量小文件场景,SMB 的单请求处理链路明显比 NFS 更长。
但要注意,这个对比在 Windows 场景下并不适用。Windows 原生支持 SMB,微软在 SMB3 上做了多年的协议栈优化、多通道并行和 RDMA 硬件卸载,Windows 到 Windows 或 Windows 到企业级 NAS 的传输效率相当高。反而是 Windows 访问 NFS 时,通常需要安装 NFS 客户端服务,体验远不如 SMB 顺畅。所以性能高低不能脱离“客户端是谁”来谈,脱离场景谈协议优劣都是耍流氓。
2.2 锁机制、缓存一致性与“数据到底什么时候落盘”
NFSv3 的锁机制一直是它的软肋。因为无状态设计,NFSv3 的锁通过独立的 lockd 守护进程管理,一旦服务器重启,客户端很难感知锁状态的变化,就会导致“文件明明没人在写,却提示被锁定”的灵异现象。NFSv4 大幅改进了锁管理,把锁纳入有状态框架,但对于某些老旧应用,NFSv4 的锁行为反而让它们不习惯。很多 DBA 拒绝把数据库文件放在 NFS 上,就是怕锁和缓存一致性问题在关键时刻掉链子。
SMB 的锁机制相对健壮,面向 Windows 应用的 oplock(机会锁)和持续可用性功能,能让 Office 文档、数据库文件在多人编辑时保持较好的体验。代价是这种健壮性建立在较高的网络交互频率上,而且 SMB 默认的写入语义偏保守,某些情况下吞吐反而被锁操作拖累。如果共享的是静态文件或构建产物,NFS 很舒服;如果是多人同时编辑同一批文档,SMB 是更稳妥的答案。
3. 服务端搭建实操:Ubuntu 上让 NFS 和 SMB 同时跑起来
3.1 搭建 NFS 服务端:别只看 exportfs,还要注意版本和安全
Ubuntu 上搭建 NFS 服务本身不复杂,但很多人只配置了 /etc/exports 就以为完事了,结果客户端挂载时各种 permission denied 或 portmap 问题。
以 Ubuntu 22.04 为例,安装和基本配置步骤如下:
bash复制# 安装服务端
sudo apt install nfs-kernel-server
# 编辑导出配置文件
sudo vim /etc/exports
一个典型的 export 配置:
bash复制# 将 /data/share 共享给 192.168.1.0/24 网段,启用读写和 root squash
/data/share 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)
这里几个关键参数我单独解释一下:
sync:服务器在回复客户端写请求之前,先把数据刷入磁盘。代价是写入延迟提高,但数据安全性大幅提升。嵌入式调试场景建议保留sync,因为开发板随时可能断电重启,丢数据极难排查。no_root_squash:允许 root 用户保留 root 权限访问共享。NFS 默认会将客户端 root 映射为 nobody,这在多数安全场景是好事,但在嵌入式开发中,开发板需要挂载根文件系统并以 root 身份读写,不开这个参数会非常痛苦。no_subtree_check:禁用子树检查,减少目录层级变化时的不必要报错。一般共享整个目录时建议加上,减少客户端访问错乱的概率。
配置完成后执行:
bash复制sudo exportfs -rav
systemctl restart nfs-kernel-server
用 showmount -e localhost 可以检查导出的共享是否生效。常见问题:NFSv4 需要固定端口,如果客户端和服务器之间有防火墙,除了 2049 之外还要放行 rpcbind/mountd 等端口,便于稳定连接。
3.2 搭 SMB 服务端:Samba 配置的几个坑
Samba 是 Linux 上提供 SMB 服务的标准方案,但它的配置细节比 NFS 多一些,特别是权限模型与 Windows ACL 的映射关系。
安装:
bash复制sudo apt install samba
编辑 /etc/samba/smb.conf,在文件末尾追加:
ini复制[share]
path = /data/share
browseable = yes
read only = no
guest ok = no
valid users = smbuser
force user = smbuser
force group = smbgroup
create mask = 0664
directory mask = 0775
创建系统用户并设为 Samba 用户:
bash复制sudo useradd smbuser
sudo smbpasswd -a smbuser
sudo systemctl restart smbd
这里提醒三点。
第一,force user 和 force group 很关键。如果不强制用户映射,Windows 客户端写入的文件会以登录 SMB 账户的身份落盘,但你本地的 Linux 进程可能用的是另一个账户,最后就会发现“文件明明能看到,就是没权限删改”,这种错位非常折磨人。简单粗暴的解决办法是把所有 SMB 写操作强制落到一个专门的服务账户上。
第二,create mask 和 directory mask 控制新建文件的权限掩码。Windows 文件系统不像 Linux 有读写执行分离的权限体系,文件在共享里创建后,权限通常根据 Samba 进程的 umask 和掩码计算,弄不对就会导致 Linux 侧无法读取或执行。
第三,SMB 多通道是性能利器,但多网卡环境很容易出现“列表正常、传输断流”的问题。如果遇到症状,先看看是否启用了多个网卡,必要时在 smb.conf 中限制 interfaces 和 bind interfaces only,防止 SMB 流量在多网卡间跳来跳去。
3.3 客户端挂载:NFS 与 SMB 的差异细节
Linux 挂载 NFS 的标准命令:
bash复制mount -t nfs -o vers=4.2,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 192.168.1.10:/data/share /mnt/nfs
参数细节:vers=4.2 指定协议版本,rsize/wsize 尽量调大以提升吞吐,hard 表示网络恢复后继续挂载等待,timeo 是超时重传时间基数,单位是 0.1 秒。
SMB 挂载对应的命令:
bash复制mount -t cifs -o username=smbuser,password=xxx,uid=1000,gid=1000,file_mode=0664,dir_mode=0775,vers=3.0 //192.168.1.10/share /mnt/smb
注意:cifs 内核模块在现代 Linux 上对应的是 SMB 协议族,vers=3.0 明确指定使用 SMB3.0,避免某些系统默认协商到 SMB2 或 SMB1。密码写在命令行里会被 ps 看到,生产环境建议把凭据放到 /etc/cifs-creds 文件并用 credentials= 参数引用。这些细节看着小,实际踩过一遍的人都会觉得“早看到就好了”。
4. 嵌入式开发场景:RK3568 根文件系统通过 NFS 挂载全解析
4.1 为什么嵌入式开发离不开 NFS
最近不少做 RK3568 开发板的工程师都在搜“nfs 根文件系统挂载”相关的内容,这背后其实是被调试效率逼出来的选择。嵌入式开发时,内核和根文件系统动不动就要重新烧写,如果每次改一个应用都要重新刷写整块 Flash,整个过程会非常痛苦。通过 NFS 把根文件系统放在宿主机上,开发板通过网络挂载启动,改完代码直接生效,省掉反复烧录的环节。
使用 NFS 而非 SMB 做嵌入式根文件系统挂载,原因很实际:NFS 是 Linux 原生协议,内核自带客户端支持,挂载根文件系统贯穿内核启动流程,天然契合;SMB 的内核级客户端虽然也存在,但通常不支持作为根文件系统直接引导,而且初始化过程复杂、资源占用更高。嵌入式场景追求的是启动链路短、依赖少、挂载稳,NFSv3 几乎是唯一可靠的选择。
4.2 宿主机与开发板的完整配置流程
以我实际调 RK3568 的经验,整个流程可以拆成四步。
第一步,宿主机(Ubuntu)上创建根文件系统目录,比如 /opt/rk3568-rootfs,将编译好的 rootfs 内容解压或同步进去。
第二步,配置 NFS 导出目录,编辑 /etc/exports:
bash复制/opt/rk3568-rootfs 192.168.1.0/24(rw,sync,no_root_squash,no_subtree_check)
然后重启服务并确认导出列表:
bash复制sudo exportfs -rav
showmount -e localhost
第三步,在 U-Boot 引导阶段设置参数。RK3568 的 U-Boot 通常有一个 bootargs 环境变量,需要设置类似:
bash复制setenv bootargs 'root=/dev/nfs nfsroot=192.168.1.10:/opt/rk3568-rootfs,v3 ip=dhcp console=ttyS0,1500000n8'
saveenv
root=/dev/nfs 表示根文件系统走 NFS,nfsroot 指定服务器地址、路径和 NFS 版本,ip=dhcp 让开发板自动获取 IP。注意这里特意写了 v3,因为 NFSv4 在部分开发板的内核配置里没有得到完整支持,U-Boot 或内核启动早期阶段如果协商到 v4,有时会出现挂载失败或者挂载后 I/O 卡死的问题。嵌入式调试,NFSv3 是最省心的选择,虽然安全性弱化,但板子都在可控网络里,牺牲点安全换稳定性非常值得。
第四步,确认内核配置。编译内核时,需要开启以下选项:
text复制CONFIG_ROOT_NFS=y
CONFIG_NFS_V3=y
CONFIG_NFS_V4=y # 非必须,但建议预留
CONFIG_IP_PNP=y # 网络启动支持
如果内核没开 IP_PNP,设备在启动阶段无法自动配置网络,ip=dhcp 就只会变成一条无效参数,根文件系统自然挂不上。
4.3 调试过程的经验记录
RK3568 板子通过 NFS 启动时,我碰到最经典的问题是:启动到“VFS: Cannot open root device nfs”后卡死。排查顺序通常是:
- 先确认开发板和宿主机能互相 ping 通。别笑,这个问题出现频率之高远超想象,尤其是有多个网卡的宿主机,NFS 流量可能走了错误网卡。
- 在 U-Boot 里打印
printenv bootargs,确认变量确实被保存和加载。 - 在宿主机上执行
watch -n1 showmount -e,观察开发板启动时是否真的访问到 NFS 服务。 - 查看宿主机的
/var/log/syslog,重点搜mountd和nfsd相关报错。很多挂载失败其实是防火墙拦截或/etc/exports格式问题,日志会给出提示。
另外,rootfs 里的 /etc/init.d/rcS 等启动脚本经常依赖串口输出和设备节点,如果 NFS 挂载正常但启动后提示 can't open /dev/ttyS0,多半是 devtmpfs 没有正确挂载。这时需要在 cmdline 里提前加上 devtmpfs.mount=1,或者确认内核开了 CONFIG_DEVTMPFS_MOUNT=y。这类问题跟 SMB 没关系,但从现象看又很像“文件系统访问失败”,经验不足的人容易走弯路。
5. 场景选型指南:什么时候该选 SMB,什么时候该选 NFS
5.1 跨平台文件共享与办公协同:SMB 是默认答案
如果你面对的是 Windows 和 macOS 混合的办公室环境,共享文件夹主要用来存放 Office 文档、PDF、设计素材,让大家能访问、能多人编辑,SMB 几乎不需要动脑筋。Windows 自带 SMB 客户端,macOS 也从很早开始内置 SMB 支持,网络邻居直接就能看到。NAS 设备(群晖、威联通、绿联等)上默认开启的也是 SMB,开箱即用,权限管理界面友好。
这类场景下用 NFS 会非常别扭:macOS 挂载 NFS 需要命令行,Windows 开 NFS 客户端后权限映射也麻烦,普通用户根本搞不定。所以办公协同、个人文件备份、家庭媒体分享,SMB 是默认答案。
5.2 Linux 服务器之间与容器化环境:NFS 的效率优势
纯 Linux 环境里,NFS 的低开销是实打实的优势。比如构建服务器要把编译产物挂载到多个构建机共享,或者 Kubernetes 里用 ReadWriteMany 类型的存储供多个 Pod 同时读写,NFS 是更轻型的选择。同等硬件下,NFS 的协议解析开销比 SMB 更低,高吞吐传输时 CPU 占用更少,这在低配 ARM 小型服务器上体现得尤其明显。
另外,NFS 对内核线程和内存缓存的利用方式更直接,很多 Linux 原生应用对 NFS 的兼容性测试也更充分。比如 rsync、tar、find 这类工具在 NFS 挂载文件系统上的行为,比在 CIFS 挂载文件系统上的行为更稳定。
5.3 嵌入式、开发板与网络启动:NFS 几乎没悬念
前面已经聊了 RK3568 的例子,扩展到全系列嵌入式开发,结论也一致:只要目标是网络挂载根文件系统、内核远程调测、无盘启动,NFS 始终是主角。它协议轻、内核支持成熟、U-Boot 直接支持网启,流程链条短。SMB 在这个领域存在感很低,主要还是因为内核级客户端对启动阶段的支持不够完善。如果一个场景高度依赖 Linux 内核启动链,直接选 NFS 就好。
5.4 移动端与远程访问:Termux 上的 SMB 实践
另一个越来越多的人会遇到的场景,是在 Termux(Android 上的终端模拟器)中访问共享文件夹。很多玩家喜欢用 Termux 通过 SMB 连接电脑或 NAS,把手机当成一个文件便携终端。这时选择 SMB 的理由也很明确:Windows 和 NAS 的 SMB 共享是现成的,Termux 里有成熟的工具(比如 smbclient,或者通过 cifs 工具配合挂载),认证流程对移动端友好。相比之下,移动端 NFS 挂载往往需要 root 权限或特殊内核支持,普通用户操作门槛明显提高。
从实践角度看,Termux 里连接 SMB 的典型操作流程是:
bash复制pkg install samba-client
smbclient -L //192.168.1.10 -U username
smbclient //192.168.1.10/share -U username
轻量访问用 smbclient 足够,如果需要挂载成本地目录,可以在 Termux 里搭配 cifs-utils 和相应权限方案。这部分使用体验也印证了 SMB 在“多样客户端、跨品牌设备”场景中的生态优势。
5.5 选型决策对照表
我把常见的决策维度整理成一张表,方便大家按图索骥:
| 维度 | SMB | NFS |
|---|---|---|
| 客户端生态 | Windows/macOS/Linux/Android 全平台支持 | Linux/Unix 原生,Windows 支持有限 |
| 典型场景 | 办公共享、NAS、跨平台文件服务 | Linux 服务器集群、嵌入式网启、科学计算 |
| 性能特点 | SMB3 多通道、RDMA,重负载下稍高开销 | 无状态、轻量、高吞吐,小文件场景更具效率 |
| 权限模型 | 面向用户认证、域环境、ACL 丰富 | 基于 UID/GID 和权限位,映射逻辑直白 |
| 锁与一致性 | 锁机制成熟,适合多人协同编辑 | 锁管理相对弱,NFSv4 改善但仍有局限 |
| 嵌入式支持 | 内核级支持有限,不适合网启根文件系统 | U-Boot/内核级支持完善,网启首选 |
| 配置复杂度 | 需要处理用户映射、掩码、认证 | 配置直观,但需注意版本和参数细节 |
这张表的核心思想是:SMB 赢在“生态”,NFS 赢在“效率”和“系统底层”。遇到具体场景,先看客户端是谁,再看用途是什么,基本能锁定答案。
6. 共享访问失败的排查记录:先别急着把锅甩给 SMB
6.1 我经历过的一次典型误判
某次在客户环境里做文件共享迁移,对方的 NAS 是 Linux 底层,通过 Samba 提供 SMB 共享,Windows 客户端访问时断时续。同事第一反应是 SMB 协议配置有问题,反复调整加密、版本、多通道,问题都没解决。我上台之后从头来看,发现客户 NAS 有两块网卡,Samba 绑定的是 management 口的 IP,而 Windows 客户端走的是另一条业务网段。SMB 请求进来后被防火墙策略拦了一部分,另一部分因为多通道机制在两个网卡间来回跳,表现为“时通时断”。最后把 Samba 的 interfaces 限定到业务网卡,问题立刻消失。
这个案例给我们的教训是:共享访问失败,第一优先级是检查网络是通的、走的是不是期望的路径,第二优先级才是协议配置。很多时候 SMB 报错只是结果,不是原因。
6.2 常见问题速查表
我整理了一张共享访问问题的排查速查表,也是自己踩过坑之后的总结:
| 现象 | 大概率原因 | 验证与解决手段 |
|---|---|---|
| Windows 访问 SMB 共享提示“拒绝访问” | Samba 用户映射、文件夹权限不足 | 检查 force user 和系统目录权限,用 smbstatus 看当前会话 |
| Linux 挂载 SMB 显示“Host is down” | 防火墙拦阻、SMB 协议版本过低或过高 | 放行 445/139 端口,显式指定 vers=3.0 |
| Linux 挂载 NFS 报 “access denied by server” | /etc/exports 网段写错、root_squash 干扰 |
检查 exportfs 列表,确认客户端 IP 在授权网段 |
NFS 挂载后大量 input/output error |
NFS 版本不匹配、硬挂载下服务器失联 | 检查服务器状态,尝试 soft 挂载选项定位问题 |
| 高负载时 SMB 传输速度骤降 | 多通道跨网卡、加密开销过大 | 固定 interfaces,关闭不必要的 SMB 加密 |
| 嵌入式板 NFS 启动到一半卡死 | 内核缺配置、NFSv4 兼容问题、timeo 过短 | 开启 IP_PNP,改为 nfsroot=...,v3 |
6.3 排错时的几个独门习惯
第一,顺序永远从低到高排查:物理链路 -> IP 连通性 -> 端口放行 -> 服务状态 -> 协议版本 -> 权限映射。跳步排查是我们行业里最常见的低级错误。
第二,看日志比猜原因高效一百倍。Samba 日志默认在 /var/log/samba/log.smbd,NFS 排查重点看 /var/log/syslog 里的 mountd、nfsd、rpc.mountd 条目。客户端侧也可以加 -v 参数挂载,比如 mount -t cifs -v 会输出完整的协商细节。
第三,Windows 侧排查 SMB,用 net use 和 Get-SmbConnection 看会话状态。如果已经建立了连接但无法访问内容,问题基本可以锁定在权限层而非协议层;如果连接本身就建立不了,再去查网络和防火墙。
第四,别忽略时间同步。NFS 和 SMB 在开启 Kerberos 或高级安全特性后对时间同步敏感,客户端和服务器时间偏差超过几分钟,认证就会失败。嵌入式板上尤其容易忽略这点,因为板子 RTC 经常不准确。
这些经验总结起来就是一句话:共享文件夹访问失败,先确认“路通不通”,再确认“身份认不认”,最后才去调“协议稳不稳”。顺序错了,排查就是无头苍蝇。
7. 最后的体会与补充建议
我从一开始做文件共享到后来深入嵌入式开发,对这个话题最深的感受是:SMB 和 NFS 从来不是互斥的二选一,更多时候是同一套基础设施里各司其职的两个角色。家里或办公室的 NAS,用 SMB 给全平台设备提供随手可用的共享空间;服务器集群、构建系统、开发板网启,用 NFS 跑高效的底层数据通路。只要搞清楚这两者的脾性,选型其实是顺水推舟的事,不会纠结太久。
另外想补充一个容易被忽略的细节:如果你们的存储设备同时支持 SMB 和 NFS,千万别在一开始就贪多把两条链路全部开通,先按主要用途开一种,跑稳之后再逐步加。因为两种协议同时启用时,某些 NAS 的权限模型和锁管理会产生微妙的重叠,偶尔会引出“明明权限没问题却互相覆盖”的怪问题。我自己就遇到过:同一个目录同时被 SMB 和 NFS 访问,Windows 客户端改名的文件在 Linux 上消失了,差点被当成协议 bug,后来才发现是两边权限映射和缓存策略打架导致的。
再分享一个小技巧:无论用哪种协议,对共享目录做定期的文件系统一致性检查都很有必要。网络文件系统不像本地文件系统那么容易暴露错误,很多异常都是“久久没报错,一错错一片”的累积结果。尤其嵌入式开发环境里,开发板频繁断电重启,NFS 服务端的文件系统如果不干净,后续挂载后写文件可能突然报只读错误。日常巡检时用 dokcer 或 fsck 之类的工具做一次离线检查,能省掉后续大量莫名其妙的工时。
希望这篇基于实战经验的对比能帮你把 SMB 和 NFS 的优缺点看清,也让共享选型和排错的路走得更顺一点。如果实践中有新的问题,欢迎在评论区交流,我看到了会尽量回复。
