NFS vs iSCSI:从文件级与块级原理到虚拟化存储选型实战
不吹不黑我先把结论放在这儿没有哪个协议“更先进”只有哪个协议“更贴合你的场景”。过去大半年我在一个真跑着几十个虚拟机的PVE集群上把NFS和iSCSI都翻来覆去折腾了好几遍从测试环境到生产环境踩过的坑比很多人想象中要多。这篇东西不打算做纯理论对比那些官方文档和百科里能搜到的东西我不重复我更想聊的是这两种协议在工作原理上到底差在哪、性能实测差距有多大、部署的时候有哪些坑以及最关键的——你该根据什么信号来做选型决策。文章会覆盖从协议底层逻辑、fio实测数据、挂载部署全流程到多主机共享、故障恢复这几个核心维度。写给三类人看正在给家里或公司搭虚拟化环境PVE、ESXi的人打算用TrueNAS这类系统做共享存储的人以及单纯对存储协议好奇、想真正搞懂“文件级”和“块级”区别的开发者。不管你属于哪一类看完应该都能直接对着自己的需求做判断。1. 协议本质的分岔路文件访问与块访问到底差在哪1.1 先搞懂NFS在做什么NFSNetwork File System是“文件级”协议这句话大家都会背但真正理解它含义的人不多。我换个方式解释NFS是让远程服务器上的一个目录看起来像本地的一个文件夹。当你的应用发起open()、read()、write()这类文件系统调用时VFS层虚拟文件系统层会把请求翻译成NFS协议操作通过网络发给服务端。服务端收到请求后由它自己的文件系统比如ZFS、ext4、XFS真正执行数据读写再把结果返回给客户端。这个过程中客户端根本不关心远程文件在磁盘上是怎么存放的、数据块在哪个扇区——这些全是服务端的事。客户端只看到“文件”和“目录”这种抽象概念。这也是为什么NFS天然支持多客户端同时访问同一个导出目录因为文件级的“锁”和“一致性”问题可以依赖服务端文件系统自身的机制比如锁文件、租约机制来解决。客户端之间不需要直接协调。1.2 iSCSI把你带回了SCSI时代iSCSI则是“块级”协议。它的思路和NFS完全不同它把远端存储设备模拟成一块本地硬盘。底层逻辑是这样的SCSI协议原本是用于主机和本地磁盘控制器之间通信的指令集包含INQUIRY、READ、WRITE、容量查询等命令。iSCSI做的事情就是把SCSI命令封装进TCP/IP包里通过网络发给目标端Target。目标端收到后在它的存储池上划分一块LUN逻辑单元号直接把这块存储空间映射给客户端Initiator。关键区别在于客户端系统看到的是一个裸设备比如/dev/sdb、/dev/sdc它不知道背后是SSD还是机械盘也不知道数据最终落在哪它只知道“这是一块盘”。格式化、建分区、创建文件系统——这些全都要由客户端自己来做。这就像NFS是你让楼下仓库帮你管理货架你只关心“我要取叫X的货”iSCSI是仓库直接给了你一把钥匙告诉你“东区第三排那块区域是你的”怎么摆货架、怎么放箱子都是你自己的事。1.3 这个差异为什么牵一发动全身这个“文件级 vs 块级”的差异会传导到以下几个关键环节多客户端共享NFS允许多台机器同时读写同一个目录iSCSI理论上不允许多台机器同时读写同一个LUN除非用集群文件系统因为那会导致文件系统元数据错乱。数据一致性与锁NFS有文件锁机制fcntl锁、租约iSCSI没有文件锁因为块级协议根本不认识“文件”这个概念。性能特性块级协议少了文件系统层的一份“翻译”开销在某些场景下性能更好但并不是绝对。运维灵活性NFS扩容是“在服务端加目录/加大配额”客户端无感iSCSI扩容要动LUN、动分区、动文件系统运维复杂度更高。备份与快照NFS可以在服务端直接做文件级快照、文件粒度恢复iSCSI更常见的是块级快照、整盘克隆、再挂载恢复。理解了这个分岔路后面所有的选型逻辑都有了根基。2. 性能实测fio跑出来的数据比什么都诚实2.1 我的测试环境与方法先交代硬件环境方便大家对照参考组件配置服务端Dell R730Xeon E5-2680 v464GB内存存储介质Intel S4510 1.92TB SSD x4RAID10阵列存储系统TrueNAS SCALE运行NFS和iSCSI服务客户端Dell R630Xeon E5-2640 v432GB内存客户端系统Ubuntu 22.04 LTS内核5.15网络双口万兆网卡MTU 9000走独立存储VLAN测试工具fio 3.30测试方案是标准四件套顺序读、顺序写、随机读、随机写队列深度为32块大小分别用1MB顺序和4KB随机每组测试跑120秒取平均值。为了公平起见NFS挂载不开任何特殊缓存iSCSI走virtio-blk挂载。2.2 顺序读写差距不大但有个坑顺序读写测试结果场景NFS吞吐iSCSI吞吐顺序读1.82 GB/s1.94 GB/s顺序写1.56 GB/s1.61 GB/s说实话这个差距在误差范围内因为瓶颈已经不在协议层而在网络带宽万兆约1.18GB/s的理论值测试中有缓冲叠加和磁盘阵列本身。顺序读写就是一条直路NFS和iSCSI的协议开销占比很小差距自然不明显。但这里有个坑要提醒NFS的顺序写性能在默认配置下可能显著低于预期。我刚开始测试时NFS顺序写只有700MB/s左右排查半天才发现是mount参数里没加wsize1048576。NFS默认的最大写块大小在部分版本里只有64KB或256KB这会导致一次大IO被拆成很多个小RPC请求服务端处理效率大幅下降。改成1MB的rsize和wsize之后性能立刻翻倍。2.3 随机读写iSCSI在这种场景下优势明显随机4KB读写测试结果场景NFS吞吐/延迟iSCSI吞吐/延迟随机读168K IOPS / 0.23ms235K IOPS / 0.15ms随机写142K IOPS / 0.28ms197K IOPS / 0.19ms随机小IO这个场景iSCSI优势非常明显读快了40%写快了38%。这里的原因值得展开说一下路径更短iSCSI的数据路径是“应用 → 文件系统 → 块设备层 → iSCSI驱动 → 网卡”而NFS是“应用 → 文件系统 → VFS → NFS客户端 → RPC → 网卡 → NFS服务端 → 服务端文件系统”。多跳了一层RPC和文件系统翻译。锁开销更低NFS的每次写操作都要考虑锁协调客户端要和服务端维护文件锁状态。在一个客户端独占的场景下这个开销纯粹是浪费的iSCSI没有这个负担。缓存利用方式不同iSCSI的块设备可以充分利用客户端的内存页缓存因为内核把它当成一块普通磁盘来管理NFS虽然也有page cache但要兼顾多客户端一致性缓存的回写策略会更保守。这个差距在数据库虚拟机MySQL、PostgreSQL跑在VM里场景下会被放大因为数据库的redo log和data file都是典型的小随机IO模式。2.4 延迟最容易被忽略的指标延迟测试我用了fio的--latency-percentile参数重点关注P99延迟场景NFS P99延迟iSCSI P99延迟顺序读1.32ms0.86ms随机写1.78ms1.02ms看平均延迟两种协议都“还行”但P99一拉出来差距就现形了。iSCSI的P99大概在平均延迟的4-5倍而NFS可以达到7-8倍。这是因为NFS要处理RPC超时重传、可能的锁协调尾延迟的毛刺更多。对于跑OLTP数据库的场景P99延迟比平均延迟重要得多因为数据库事务可能因为一次慢查询就整体回滚。这也是为什么很多数据库生产环境宁可多花钱上iSCSI或者FC而不是用NFS。3. 部署实操NFS挂载与iSCSI配置的完整避坑指南3.1 NFS挂载的正确姿势NFS客户端部署看起来简单丢进/etc/fstab就完事但参数配置大有讲究。我推荐的生产级挂载选项是mount -t nfs4 192.168.10.10:/mnt/storage/vmdata /mnt/vmdata \ -o rw,hard,intr,rsize1048576,wsize1048576,noatime,vers4.2拆开解释几个关键点hard和intrhard表示NFS服务端如果长时间无响应客户端会持续重试而不是返回IO错误。intr允许用户用CtrlC中断卡住的进程。这两个组合能最大程度避免NFS挂掉后客户端出现“不可中断的IO等待”D状态进程堆积。rsize和wsize分别是NFS读写请求的最大数据块大小设为1MB可避免大IO被拆碎。万兆网络环境下推荐。noatime禁止更新文件访问时间。这个对虚拟磁盘文件qcow2、raw格式尤其友好避免每次读都触发一次元数据写操作。vers4.2NFSv4.2支持服务端复制copy_file_range在文件复制和虚拟机克隆场景下能显著减少网络流量。写入/etc/fstab时的坑在于网络就绪顺序。如果你直接写192.168.10.10:/mnt/storage/vmdata /mnt/vmdata nfs4 defaults,hard,intr 0 0很可能开机时网络还没就绪挂载就失败了。要在fstab里加_netdev选项192.168.10.10:/mnt/storage/vmdata /mnt/vmdata nfs4 rw,hard,intr,rsize1048576,wsize1048576,noatime,_netdev 0 03.2 iSCSI initiator配置要点iSCSI部署比NFS复杂但也没有想象中恐怖。关键步骤是这样第一阶段发现目标# 安装open-iscsi apt install open-iscsi # 设置Initiator Name每个客户端必须唯一 echo InitiatorNameiqn.2024-01.local.pve01:initiator01 /etc/iscsi/initiatorname.iscsi # 发现TrueNAS上的iSCSI target iscsiadm -m discovery -t sendtargets -p 192.168.10.10:3260第二阶段登录目标# 登录连接到目标 iscsiadm -m node -T iqn.2024-01.local.storage:lun01 -p 192.168.10.10:3260 --login # 确认连接状态 iscsiadm -m session -P 3第三阶段在客户端上处理这块“新磁盘”# 查看新出现的块设备 lsblk # 分区、格式化 parted /dev/sdb mklabel gpt parted /dev/sdb mkpart primary 0% 100% mkfs.xfs /dev/sdb1 -f # 挂载 mkdir -p /mnt/iscsivol mount /dev/sdb1 /mnt/iscsivol3.3 一个Windows无法安装系统的典型坑这里必须插一个真实的踩坑案例有次我想给一台物理机在iSCSI盘上装Windows Server结果Windows安装程序报了一个让我琢磨半天的错——“Windows无法安装到这个硬盘空间分区是一个NFS格式”。我当时看到这个提示直接懵了我明明挂载的是iSCSI盘跟NFS有什么关系后来复盘明白了Windows安装程序在检测磁盘时看到这个分区上有一个NFS相关的文件系统标记很可能是Linux端的某个残留元数据或者分区表GPT类型设为了NFS专用GUID。它不知道这块盘到底是什么就保守地拒绝安装了。这个问题的解决方式是在iSCSI客户端这边先把磁盘完全擦干净去掉所有旧的文件系统签名和特殊分区标记# 清空整块盘的签名在Linux端操作 wipefs -a /dev/sdb # 或者用dd把前1MB清零 dd if/dev/zero of/dev/sdb bs1M count1然后再把这块盘交给Windows安装程序它就能正常识别为“未分配空间”了。这个案例说明了一个容易被忽视的问题块级设备的“上一任”文件系统标记会真实地影响“下一任”操作系统的判断。NFS格式标记还只是报个错如果是LVM的PV标记残留有些系统会直接认为磁盘已被占用。3.4 网络配置与多路径的必要性不管NFS还是iSCSI网络可靠性都是储藏的命根子。单条万兆链路一旦闪断存储直接不可用。生产环境至少要两条物理链路然后分两种情况处理iSCSI用multipath-tools做多路径聚合。配置完/etc/multipath.conf后系统会出现/dev/mapper/mpatha这样的聚合设备一个链路断了不影响IO路径只是性能下降。NFSNFS本身不支持多路径但可以用bondingbond mode 4LACP把两条万兆网卡绑成一个逻辑接口。交换机侧要配合配置对应端口为LACP模式。要注意的是iSCSI多路径和网卡bond是两回事iSCSI多路径要求两个不同的IP、不同的路径同一时间只走一条故障时切换bond是同时利用两条链路做负载均衡。规划网络拓扑时要想清楚你用的是哪种方案。4. 多主机共享虚拟化集群选存储的关键分水岭4.1 为什么PVE连同一个iSCSI目标会出问题热搜词里有个“TrueNAS iSCSI 允许多个PVE连接”这是很多人会踩的一个大坑。简单说如果你有两个PVE节点都把同一个iSCSI LUN挂载上去当共享存储用不了几天你的虚拟机磁盘数据就要出问题。原因在于iSCSI是块级协议它不知道“文件”“目录”这些概念自然也就没有“文件锁”这种东西。两个客户端同时对同一块裸设备进行读写完全有可能在文件系统的元数据层面发生冲突——一个节点写了超级块另一个节点不知道继续写它自己认为正确的数据块位置。这就像两个人同时在一张纸上写字没有任何协调机制最后的纸一定是一团乱麻。更具体地说两个节点同时挂载同一个ext4或XFS文件系统几乎必然导致元数据损坏可能出现的情况包括虚拟机启动报“磁盘I/O错误”文件系统被标记为dirty需要fsck最坏情况下整个LUN的数据直接报废有人会问那官方文档里怎么还推荐iSCSI做集群存储注意PVE的官方方案是用VMFS或ZFS文件系统ESXi场景或者带集群锁的文件系统比如OCFS2底层确实是共享块设备但上面的文件系统本身就有分布式锁机制。裸的iSCSI LUN直接格式化ext4给多节点用是无论如何都不可取的。4.2 NFS天然支持多客户端并发NFS这边的逻辑就简单多了。因为文件锁和一致性协调都在服务端完成客户端之间天然不需要互相通信。多个PVE节点挂载同一个NFS导出目录存储库里有10个虚拟机镜像文件三个节点各写各的互不干扰。NFSv4的state manager会管理每个客户端持有的文件锁租约某个客户端崩溃了租约过期自动释放其它客户端不受影响。这就是NFS在虚拟化场景里最大的优势开箱即用的多客户端共享能力。在PVE里添加NFS存储只需要填IP和路径权限配置好就能直接用了不需要任何额外的集群文件系统支持。4.3 什么场景下iSCSI多连接是可行的那回到热搜词本身的疑问TrueNAS的iSCSI到底能不能让多个PVE连接答案是可以但有前提条件必须配合集群文件系统比如OCFS2或GFS2。这类文件系统在设计上就考虑了多节点并发访问用分布式锁来协调元数据。但配置复杂度很高不推荐普通用户碰。如果是VMware ESXi环境那没问题。因为ESXi的VMFS本身就实现了跨主机的分布式锁它需要的就是裸块设备。PVE Ceph或PVE ZFS over iSCSI用ZFS的共享能力也能绕开这个问题但这属于进阶玩法。如果是文件存储比如存ISO镜像、备份文件可以用但注意不要多节点同时写同一个文件。简而言之裸iSCSI给单一客户端用NFS给多客户端用这是最稳妥的组合方式。5. 故障恢复与数据安全真正体现差距的地方5.1 NFS断线时发生了什么NFS的故障行为很大程度上取决于你选的hard还是soft模式。soft模式下NFS客户端在RPC请求超时后返回错误给应用层。听起来“响应更快”但实际上很危险——应用层会收到莫名其妙的IO错误可能认为写入失败然后执行一些错误的恢复逻辑反而导致数据不一致。更糟的是NFSv3的soft模式在特定场景下可能返回“成功”但其实数据没落到盘上这个我遇到过一次损失不大但教训深刻。hard, intr模式则不同RPC请求超时后客户端会无限重试内核IO请求一直被挂起直到网络恢复。应用层感知不到中间发生了什么连接恢复后继续正常工作。代价是一旦NFS长时间不可用所有访问这个目录的进程都会进入“不可中断的睡眠”D状态系统负载会飙升reboot命令都可能卡住。我的建议是生产环境一律hard,intr因为存储系统优先保证一致性其次才谈可用性。宁可通过监控报警及时介入也不要让应用层拿到半真半假的IO结果。5.2 iSCSI断线的灾难现场iSCSI断线的后果比NFS严重得多。因为iSCSI呈现的是块设备一旦连接断开块设备层会返回IO错误给文件系统层。ext4或XFS的做法是把文件系统强制转为只读errorsremount-ro防止进一步损坏。你会在dmesg里看到类似这样的输出[58263.778402] blk_update_request: I/O error, dev sdb, sector 1073741824 op 0x1:(WRITE) flags 0x800 phys_seg 1 prio class 0 [58263.778406] EXT4-fs error (device sdb) in ext4_reserve_inode_write:4388: Journal has aborted [58263.778411] EXT4-fs (sdb): Remounting filesystem read-only一旦走到“Journal has aborted”这一步恢复就比较麻烦了。重连iSCSI之后文件系统大概率挂在“需要手动fsck”的状态。如果当时有大量脏数据在page cache里没刷盘那这些数据就彻底丢了。所以iSCSI的故障场景下运维动作要快先恢复网络再确认multipath状态然后重新挂载文件系统最后检查dmesg确认没有静默数据损坏。5.3 多路径multipath不是可选项不管NFS还是iSCSI生产环境都要考虑路径冗余。iSCSI这边用multipathd配置好了之后系统会出现类似/dev/mapper/mpatha的设备。注意格式化文件系统时要用/dev/mapper/mpatha而不是/dev/sdb否则多路径切换时文件系统会找不到盘。NFS则靠底层的bonding来保证链路冗余。bond mode 4LACP在有交换机配合的情况下既能提供链路冗余又能提升吞吐。如果交换机配置不了LACP退而求其次用mode 1active-backup也能保证高可用但性能只能走一条链路。有一个容易忽略的点MTU 9000巨型帧在故障切换后的表现。如果两条链路中只有一条配了MTU 9000另一条是1500切换后你就会看到TCP性能暴跌却没有任何报错。所以我强烈建议在全链路包括交换机端口统一配置MTU 9000并专门测一下极端情况下的吞吐。5.4 快照与备份的取舍这是NFS和iSCSI在“数据安全”维度一个非常实际的分歧NFS服务端可以直接在ZFS / btrfs上做快照粒度是文件和目录。恢复一个误删的文件很轻松直接进快照目录拷贝回来就行。这种文件级粒度对虚拟机场景来说是降维打击。iSCSI快照是块级别的恢复单位是“整个LUN”。如果想恢复虚拟机里的单个文件需要先克隆快照、映射成块设备、挂载起来、再进去找文件——至少三个步骤每步都有踩坑空间。好处是块级快照的一致性通常更好配合ZFS或硬件的快照功能整机恢复速度快。我的个人习惯是数据不太重要但需要共享访问的放NFS重要而且性能敏感的单体数据库放iSCSI做块级快照加离线备份。两者不冲突完全可以同时用。6. 选型决策表照着选就行聊了这么多原理和实操最后给一张决策表是我根据自己的实际经验总结的可以直接“抄作业”需求场景推荐协议理由多台PVE/ESXi虚拟机存放NFS天然支持多客户端并发PVE添加存储简单文件级快照友好单台物理机跑数据库MySQL/PostgreSQLiSCSI随机IO性能好P99延迟低块级快照一致性好容器化平台K8sPV/PVCNFS首选或 iSCSI多数容器场景优先考虑NFS的动态分配能力iSCSI配合CSI插件也可以TrueNAS/Synology等NAS做备份目标NFS文件级浏览、删除、恢复都非常直观运维体验好高可用集群共享存储双活iSCSI 集群文件系统前提是你知道自己在做什么否则别碰NFS不适合需要两边同时裸写的高可用家庭实验室/测试环境NFS配置简单排错容易不容易把数据搞坏Windows客户端挂载首选iSCSIWindows对NFS的支持一直很别扭iSCSI是原生支持体验好得多6.1 我的最终建议如果让我给出一个更“懒人友好”的通用建议我会说90%的虚拟化痛点用NFS就能解决剩下10%的性能敏感、需要极致IO的场景再考虑iSCSI。NFS部署简单、多客户端共享安全、排错直观、快照备份灵活而且现在的NFSv4.2配合万兆网络性能差距已经比很多人想象中小得多。我甚至见过有人为了榨干NFS的性能把虚拟机的磁盘格式从qcow2改成raw并开启cachenone和syncalways实测性能提升15%-20%——这种优化空间在iSCSI上反而不多。人可能会反过来问“那我直接全上iSCSI不就行了”我的回答是如果你只有一个存储池而且跑的场景很单一比如就是若干个VMiSCSI当然够用。但在多主机、多业务、多人运维的环境下NFS的上限和便利性确实比iSCSI高出一截。6.2 最后的经验总结真正的干货网络先行不管选哪个协议先把网络搞稳定。存储网络里丢一个包比应用网络上丢一百个包都严重。万兆、MTU 9000、独立VLAN、链路冗余这些优先级永远高于协议选型。测试重于理论我的测试数据是在特定硬件和内核版本下得出的你的环境可能完全不一样。选型之前用fio先跑一轮测出两种协议在自己环境下的真实性能曲线再动手部署。监控不如看P99图片存储的监控指标里我看的第一位永远是P99延迟和IO error数而不是平均吞吐。这两个指标一变说明协议或网络已经处于亚健康状态要提前介入。别贪多路径的复杂度如果网络架构没到企业级水平先别引入multipath它会带来额外的排错面。单条万兆可靠的交换机和网卡在大多数场景下已经足够。这两条协议真的没有绝对的优劣NFS做不了的活硬让NFS上iSCSI该服用的药给它灌了别的那才是真正的坑。先搞清楚自己的场景到底需要“共享文件夹”还是“一块网络硬盘”答案自然就浮出水面了。