ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

NFS与iSCSI怎么选?从原理到实战的存储协议选型指南

NFS与iSCSI怎么选?从原理到实战的存储协议选型指南 很多人第一次认真研究存储往往会在NFS和iSCSI之间纠结。我在虚拟化和数据中心运维这块摸爬滚打了十几年从家里的单盘NAS玩到公司的全闪存储每次给新项目定存储协议总能看到同样的问题明明都是走网络为什么有的场景NFS顺风顺水换iSCSI却动不动崩反过来的情况也常见。这篇文章不搞教科书那套我直接把两个协议从原理到实战拆开讲穿插测试命令和踩坑记录帮你一次性搞清楚NFS和iSCSI到底怎么选。先说结论方向这两个协议不是竞争对手而是工具不同的螺丝刀。NFS适合多台机器共享文件iSCSI适合让一台机器拿到一块高性能网络盘。但实际部署中选错协议的人非常多尤其是跑到虚拟化、容器和Windows安装场景时那问题一个接一个。所以我们先把底层逻辑说透。1. 先理清协议本质NFS是文件共享iSCSI是块设备映射1.1 NFS把遥远目录变成你Linux机器上的普通文件夹NFSNetwork File System从诞生起就解决一个问题让多台主机通过网络访问同一份文件就像一个共享文件夹。它工作在文件系统层服务端把某个目录导出export客户端通过挂载mount把这个目录当成自己本地路径的一部分。你在这个目录里ls、cp、vi系统底层通过RPC调用和远程服务端通信文件如何存储、权限怎么校验都由服务端文件系统完成。NFS最舒服的一点是天然具备文件级共享协商机制。比如我用两台服务器同时挂载同一个NFS目录A机器创建文件B机器立刻能看到两台机器同时编辑同一个文件时NFS会提供锁服务。虽然锁的粒度、性能有争议但至少文件语义是对的数据不会莫名其妙错乱。这在虚拟化模板存储、容器持久化、代码构建以及备份目录这类场景里非常省心。1.2 iSCSI把网络另一端的硬盘识别成你机器上的一块本地磁盘iSCSI则是另一套玩法。它把SCSI命令封装进TCP/IP包在客户端initiator和服务端target之间建立一条通道服务端把一个块设备比如ZFS的zvol、LVM的逻辑卷或者一块裸盘通过网络暴露给客户端。客户端得到的是“一块硬盘”需要你自己分区、格式化、建文件系统。对操作系统来说它和本地插入的SATA盘几乎没有区别。这个“看起来像本地盘”的特性让iSCSI在很多重数据库和高性能应用里很受欢迎。因为应用不需要经过网络文件系统那一层直接就能拿到块设备的IO能力。但代价是你自己要负责文件系统的健康多台机器能不能同时访问这块盘也得你自己处理。默认情况下你格式化一块iSCSI盘为ext4或XFS之后只允许一台机器独占读写第二台机器再挂上去访问极大概率会把文件系统写坏。这和NFS的“多机器友好”完全不同。1.3 一张表对比两者在共享、锁、性能和部署方式上的差异为了大家快速建立整体判断我先把核心差异压成一张表。对比维度NFSiSCSI协议层次文件级File-level块级Block-level客户端看到的东西目录树裸设备需要格式化多客户端共享简单文件天然支持不支持需上层集群文件系统配合多客户端同时高效写一般危险需要专门协调性能上限受文件系统语义和网络延迟影响更接近本地盘延迟低部署复杂度相对简单一条mount指令需要target/initiator配置和网络规划典型场景文件共享、虚拟机模板、容器存储数据库盘、虚拟机系统盘、高性能卷持久化语义由服务端文件系统保证由客户端文件系统保证看这张表你大概明白为什么很多老运维都持有“能NFS就NFS万不得已再上iSCSI”的观点。但这不是说iSCSI不行而是它要求你有更清晰的使用边界一旦越界代价就是数据损坏。2. 性能与测试什么时候用fio能不能拿NFS当本地盘用2.1 协议开销差在哪数据包处理、TCP连接和缓存机制性能问题的本质在于协议栈处理的路径长短。NFS每一次文件操作比如open、read、write、getattr都有可能通过网络发一个RPC请求到服务端服务端完成文件系统操作后再把结果返回。NFSv4虽然加入了compound操作可以把多个请求合并在一个RPC里减少来回次数但整体上它仍然是在“模拟文件操作”比直接在本地块设备上写数据多了一层语义转换。iSCSI则不同。客户端发出去的是SCSI命令CDB服务端收到后直接操作块设备返回的数据就是扇区内容。它不需要关心文件是什么类型、权限如何因此应用层看到的是一个标准块设备内核可以使用完整的本地页缓存机制、块调度算法和设备队列。很多测试里iSCSI的随机写延迟比NFS低一半以上原因就在这里。但这不代表NFS一定慢。我实测下来在万兆网络和低速机械盘环境下NFS的开销基本被磁盘延迟盖住了两者差异不大。真正拉开差距的是高速NVMe存储和大量小文件操作。如果你拿NVMe全闪阵列跑4K随机写NFS的网络交互次数会让性能掉得非常明显而iSCSI因为接近本地块设备可以更轻松打满万兆甚至25G网卡。2.2 小文件密集型场景localpath本地路径与NFS实测对比容器场景里经常听人提到localpath和NFS。Kubernetes里的本地路径卷local-path-provisioner其实就是把每个节点自己的磁盘目录直接分配给Pod它不需要网络所有IO都走本地文件系统性能自然是最高的。但localpath的问题在于数据只在当前节点Pod一旦调度到别的节点数据就没了共享存储这块NFS是最常见的方案。我做过一轮对比测试同一台机器本地NVMe SSD写10000个1KB小文件大约耗时15秒同样这批文件写到同网段的NFS共享耗时在40秒左右。原因不难猜每创建一个小文件NFS至少经历create和open两步每个操作都伴随网络往返而localpath只需要一个文件名操作。如果你的业务是大量日志碎片写入建议不要用NFS当主要存储优先堆本地盘再加异步备份到NFS。但如果你更看重数据全局一致性和多节点调度NFS牺牲一些IOPS是值得的。作为折中方案把NFS的挂载参数调好减少网络来回能显著改善小文件性能。后面我会专门讲到常用参数。2.3 用fio测NFS的经典命令与坑fio是存储性能测试绕不开的工具。测NFS时如果只是跑一下fio默认参数结果基本没有参考价值。因为NFS有服务端缓存和客户端缓存测试数据可能根本没落到真正的磁盘。我平时会这样测# 测NFS读使用direct绕过客户端page cache防止缓存命中影响结果 fio --namenfs_read --rwread --size4G --bs1M --numjobs4 \ --iodepth16 --direct1 --ioenginelibaio --time_based --runtime60 \ --directory/mnt/nfs-test # 测NFS写同样开direct同时用fsync模拟真实落盘 fio --namenfs_write --rwwrite --size4G --bs1M --numjobs4 \ --iodepth16 --direct1 --ioenginelibaio --group_reporting \ --time_based --runtime60 --directory/mnt/nfs-test \ --fsync64这里有两个关键点。第一--direct1必须开否则客户端页缓存会掩盖真实网络延迟。第二写测试加--fsync64可以强迫服务端定期落盘否则NFS服务端的异步写入会给出一个虚高的“缓存写入速度”。测出来的数字一定要和你的业务读写模式对照。比如你要跑数据库光测顺序读写没意义还要测--rwrandwrite --bs8k --iodepth32这种随机小IO。还有个大坑同一份NFS目录一边有业务在跑一边跑fio容易把业务IO打爆。所以测试前最好用nfsstat -m确认挂载方式并且单独建一个测试目录测完马上删除。如果服务端磁盘是共享给多台客户端并发访问的fio的数字只代表这条链路的极限不代表单客户端真实体验要在报告里写清楚测试环境。3. 实战部署NFS挂载、TrueNAS iSCSI多节点以及根文件系统挂载3.1 Ubuntu下最快搭建NFS服务端和客户端实际部署NFS并不复杂。服务端以Ubuntu为例# 服务端安装 apt update apt install -y nfs-kernel-server # 创建共享目录并设置权限 mkdir -p /srv/nfs-data chown nobody:nogroup /srv/nfs-data chmod 755 /srv/nfs-data # 编辑/etc/exports添加一行 echo /srv/nfs-data 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash) /etc/exports # 生效并查看状态 exportfs -ra systemctl restart nfs-server systemctl status nfs-server这里解释两个容易踩坑的参数。sync表示服务端收到写请求后先写盘再返回确认牺牲一点速度换数据安全如果你用的是带电池或电容保护的企业级阵列可以改async提升性能但个人用户我建议保持sync。no_root_squash允许客户端root用户以root权限访问共享目录这是双刃剑开了方便但安全风险也高如果只给普通业务用建议去掉它让客户端root映射成nobody。客户端挂载apt install -y nfs-common mount -t nfs4 192.168.1.100:/srv/nfs-data /mnt/data # 如果要长期挂载写进/etc/fstab echo 192.168.1.100:/srv/nfs-data /mnt/data nfs4 defaults,_netdev,noatime,nodiratime,vers4.2 0 0 /etc/fstab挂载参数里_netdev非常关键它告诉systemd不要启动时就盲目挂载网络盘防止因为网络没起来导致挂载失败、开机卡住。noatime,nodiratime能少写很多访问时间戳对提升NFS性能立竿见影。vers4.2则保证使用NFSv4.2特性比如服务端复制和原子写。3.2 TrueNAS上创建iSCSI target并允许多个PVE节点连接TrueNAS是目前很流行的NAS系统iSCSI配置也算简单。但“允许多个PVE连接”这个话题我建议你先搞清楚自己的真实需求。TrueNAS可以说“允许”但PVE是虚拟化平台多个PVE节点同时连接同一个iSCSI LUN时默认文件系统PVE会在iSCSI LUN上创建LV或ext4是不支持多主机并发读写的。如果两个PVE节点同时挂载同一个LUN轻则性能抖动重则虚拟机磁盘直接损坏。合理的使用方式有两种。第一种是标准的“共享存储热迁移”方式在TrueNAS上给每台PVE主机分别创建独立的iSCSI LUN哪个虚拟机跑在哪台节点就让它独占对应的LUN。虚拟机的live migration需要另外配置通常还要配合集群文件系统。第二种是干脆不用iSCSI做VM共享盘改用NFS共享目录存放虚拟机的qcow2镜像这样多PVE节点可以同时读取同一份镜像文件配合PVE的migration机制最顺滑。如果你确实要测试多节点连接同一iSCSI target过程可以这样走在TrueNAS的Web界面里先创建zvol再到Sharing Block Shares (iSCSI)里创建Target和Extent注意Extent选择刚才的zvol。在Target Global Configuration里配置允许访问的Initiator组把PVE节点的IP和initiator名称加白名单。PVE端接iSCSI的命令如下apt install open-iscsi systemctl enable --now iscsid iscsiadm -m discovery -t sendtargets -p 192.168.1.100:3260 iscsiadm -m node -T iqn.2023-01.local.truenas:pve-lun1 -p 192.168.1.100:3260 --login登录成功后lsblk应该能看到sdb之类的磁盘然后你再自己分区和格式化。这里我强烈建议在多个节点上轮流做删除重建测试没问题但千万不要同时开两个节点对同一块盘做格式化或数据库写操作底层没有分布式锁崩了只能认栽。3.3 用NFS挂载根文件系统PXE和磁盘启动两种方式“NFS挂载根文件系统”这个操作比普通数据挂载硬核得多常见于无盘工作站、PXE装机实验和嵌入式设备开发。核心思路是系统内核启动早期initramfs从NFS目录里挂载根目录之后所有系统文件都通过NFS读取和写入。以Ubuntu为例磁盘启动时想要NFS root需要修改引导参数。在GRUB菜单按e编辑启动项在linux那一行末尾追加root/dev/nfs nfsroot192.168.1.100:/srv/nfs-root,vers4.2 ipdhcp这里root/dev/nfs是告诉内核用NFS作为根设备nfsroot服务器IP:目录指定远端路径ipdhcp让客户端在启动时申请IP。如果客户端静态IP要写成ip192.168.1.50::192.168.1.1:255.255.255.0::::eth0这种形式比较繁琐。为了让initramfs支持这个流程可能还要确认系统里有nfs-common和nfs-client工具并在initramfs中启用NFS模块apt install -y nfs-common echo nfs4 /etc/initramfs-tools/modules update-initramfs -u无盘PXE方式更复杂涉及TFTP引导和DHCP配置但核心NFS参数是通用的。我踩过最大的坑是systemd依赖关系默认开启systemd-networkd后NFS root挂载要先于网络就绪执行导致挂载失败。解决办法是给initramfs加入ipdhcp并保证内核网络驱动正常。如果你只做实验建议先用传统ifupdown网络管理反而少很多麻烦。3.4 Windows访问NFS挂载分区以及那个“必须安装在NFS分区”的经典报错Windows对NFS的支持一直很别扭。Windows Server和Windows Pro以上版本自带“Services for NFS”功能可以在控制面板里启用NFS客户端然后通过mount命令把远程NFS目录映射为盘符# 启用NFS客户端后在CMD里挂载 mount -o anon \\192.168.1.100\srv\nfs-data Z:但这个玩法只能用于文件访问Windows安装程序完全不认NFS。现实中很多人尝试用Windows安装盘在NFS目录里建分区结果弹出“Windows无法安装到这个硬盘空间分区”的报错然后就懵了。原因很简单Windows安装程序只接受它能识别的本地磁盘、USB盘、iSCSI/FC/FCoE这类块设备NFS是文件系统共享协议对安装程序来说它既不是物理磁盘也不是可挂载的卷自然无法分区和安装。正确做法是要么把NFS目录作为网络共享在Windows安装完成后映射盘符使用要么改用iSCSI让Windows看到一块真实磁盘。在iSCSI initiator里连接target后Windows安装程序里的磁盘列表会出现这块盘这时你才能正常创建分区、格式化、装系统。很多人遇到这个报错后第一反应找分区工具实际上方向就错了应该退回去检查自己到底用的是哪种存储协议。4. 常见问题与排查技巧实录4.1 Windows安装提示“无法安装到这个硬盘空间分区”的原因与解决这个问题上面提到了但值得再展开。报错出现时先看磁盘接口类型Windows磁盘列表里如果已经是“磁盘0/磁盘1”说明是本地盘或iSCSI盘无法安装通常是分区表或驱动问题如果连磁盘都没有只有“网络位置”或UNC路径说明你走的是NFS这样的文件共享协议安装程序根本不把它当盘。我遇到过的实际案例是运维想用PXE加NFS给Windows客户端装机装了整整一天都在折腾分区工具最后换成iSCSI启动几分钟就搞定。如果你不想上iSCSI还有一个便宜方案先在正常Windows机器上把VHD/VHDX文件做到NFS共享里目标机器通过iSCSI或本地启动并从VHD引导但复杂度更高。总之请记住“Windows系统盘必须使用块设备”这个底线。4.2 NFS挂载后卡顿/慢网络、版本、lookupcache和文件锁NFS挂载后卡顿是群里最常出现的问题。排查线索按影响程度排个序首先是网络质量。NFS走的是TCPv4.2必走TCP一旦链路有丢包或MTU不一致客户端会频繁重传表现为整个挂载目录反应极慢。先检查网卡协商速率、ping延迟、交换机端口丢包计数。其次是版本差异。NFSv3和NFSv4在文件锁和安全性上差别很大如果服务端默认只开v3而客户端挂载参数带v4会自动降级但是性能会有变化。建议两端统一到4.2。再往下就是挂载参数。除了前面说的noatime,nodiratime还有一个参数是actimeo。默认NFS会缓存目录属性和文件属性但如果缓存时间太短频繁getattr会让所有ls和stat操作都很慢。可以适当加大mount -t nfs4 -o actimeo3,noatime,nodiratime,hard,intr \ 192.168.1.100:/srv/nfs-data /mnt/datahard表示IO失败时客户端持续重试而不是给应用返回EIO适合重要业务intr允许中断长时间阻塞的请求防止应用永久卡死。不过intr在NFSv4里有争议新内核基本会忽略它不用纠结。最后是文件锁。多客户端同时访问同一个文件如果某个客户端异常断开但没释放锁其他客户端可能一直等锁。检查服务端进程cat /proc/fs/nfsd/clients nfsstat -l必要时重启NFS服务端或手动下调/proc/sys/fs/nfs/nfs_congestion_kb等参数。但这些操作别在生产环境乱来最好先在测试环境验证。4.3 iSCSI多节点同时写入出现文件系统损坏如何避免这块我在前面反复强调了。多节点连同一块iSCSI LUN并直接格式化为ext4/XFS写入时基本必毁。排查流程一般是某天看到某个节点读写盘报错重启后发现文件系统需要fsck赶紧查是不是别的节点也登录了同一台target。用iscsiadm -m session看本机会话列表再到存储端看活动连接。正确的多节点共享块设备方案是使用集群文件系统比如OCFS2、GFS2或者走虚拟化的共享磁盘配合VMware/Proxmox的锁定机制。TrueNAS另一个方案是提供iSCSI的多initiator支持但一般只做故障转移不推荐并发读写。如果你只是想利用iSCSI的性能请老老实实给每台PVE节点分配独立的LUN互不共享。这样即使节点故障也不会拖累整个集群。4.4 权限错乱nobody/nogroup与匿名映射NFS挂载后文件所属用户变成nobody是常见问题。原因是NFS在客户端用UID/GID数字与服务器匹配如果两端用户ID不一致客户端显示为nobody。比如服务端有一个uid1000的用户alice客户端上uid1000的用户叫bob但NFS返回的文件属主是数字1000客户端查不到对应名字时就会显示为nobody。排查思路是统一UID/GID。最简单的做法是在所有客户端和服务端创建同名同uid的用户或者在/etc/exports里使用anonuid和anongid映射访问NFS的所有客户端用户/srv/nfs-data 192.168.1.0/24(rw,all_squash,anonuid1000,anongid1000)all_squash会把所有客户端用户压制成一个指定UID适合公共共享目录但要做权限管控时别用。如果你要保留多用户个人目录最好用Kerberos/NFSv4 ACL但那套东西更复杂一般团队没必要上。5. 最后聊聊我的选择建议5.1 中小规模虚拟化与容器NFS是怎么赢下我的在Proxmox VE和Kubernetes场景里我越来越偏向NFS。原因很简单运维简单迁移友好。PVE节点之间做虚拟机热迁移NFS数据存储让虚拟机镜像文件被所有节点可见可以直接协同锁容器持久化也一样NFS存储类能够让你任意调度Pod而localpath做不到共享。iSCSI虽然单机性能好但做成共享存储需要额外的集群文件系统这和Kubernetes的通用性背道而驰。我个人的经验是中小环境先把NFS服务端配好用一台NAS或专用存储节点万兆网络下跑虚机和容器日常完全够用。只有当数据库这类低延迟、高IOPS应用成为瓶颈时我才会在专门的机器上挂iSCSI盘。5.2 数据库和单机高性能要求iSCSI更合适如果业务是MySQL/PostgreSQL等需要低延迟随机写的场景iSCSI的价值就体现出来了。数据库一般自己管理缓存不希望在文件系统层被复杂的远程文件语义拖累。iSCSI给的是一个规范块设备数据库可以把它当本地盘使用跳过NFS那层getattr和文件锁开销。特别是当你把SSD阵列做成iSCSI target时随机读延迟可以控制在亚毫秒级别。不过要安装提醒iSCSI也很容易被性能瓶颈卡在网络上。单连接时1Gbps网卡理论上限只有大约125MB/s和一台普通SATA SSD的写入速度差不多想要发挥全闪性能网卡要用万兆甚至25G最好再开启多路径MPIO。否则你从iSCSI拿到的体验还不如本地盘。5.3 按场景给的速查表场景首推理由多台Linux主机共享文件NFS文件级锁与共享语义好Windows安装/系统盘iSCSIWindows不认NFS设备虚拟机镜像集中管理NFS易于迁移和备份数据库数据盘iSCSI低延迟更接近本地设备Kubernetes持久化存储NFS多节点共享灵活性高本地缓存目录localpath不跨节点性能最好最后再分享一个小技巧如果你确定不了选哪个先搭一套测试环境用fio跑一遍你业务最核心的IO模型同时记录NFS和iSCSI的真实使用体验。存储协议选型这种事参数再漂亮都不如实际环境跑几天来得靠谱。我一般会在同一台NAS上同时开NFS和iSCSI给不同业务各用各的这也是最省心的状态。希望这篇内容能帮你少踩几个坑。
返回列表