前言
说起NFS,我估计很多搞运维的兄弟都有一肚子话要说。这玩意儿吧,看起来简单,用起来坑多,但是真正搞明白了又觉得挺香的。
前几天有个朋友问我,说他们公司要搭建一个文件共享系统,问我推荐什么方案。我第一反应就是NFS,毕竟这货在Linux环境下用了这么多年,虽然毛病不少,但胜在稳定可靠。结果这哥们儿一脸懵逼地看着我:“NFS是啥?”
好吧,看来有必要写篇文章好好聊聊NFS了。我从2020年开始接触这东西,到现在也算是爱恨交加了。今天就把我这些年踩过的坑和积累的经验分享给大家。
NFS到底是个什么鬼
NFS全称Network File System,网络文件系统。简单来说,就是让你可以像访问本地文件一样访问远程服务器上的文件。听起来很牛逼对吧?实际上原理也不复杂。
NFS的工作原理其实就是客户端和服务端的通信。服务端把某个目录"导出"(export),客户端就可以把这个远程目录"挂载"(mount)到本地的某个挂载点上。挂载完成后,你在客户端操作这个目录,实际上就是在操作服务端的文件。
不过这里有个坑,NFS默认使用的是UDP协议,在网络不稳定的环境下容易出问题。现在一般都推荐用TCP,虽然性能稍微差一点,但稳定性好很多。
搭建NFS服务的那些事儿
服务端配置
在CentOS系统上安装NFS还是比较简单的:
yum install -y nfs-utils rpcbind
安装完成后需要启动相关服务:
systemctl start rpcbind
systemctl start nfs-server
systemctl enable rpcbind
systemctl enable nfs-server
这里要注意一个细节,rpcbind必须先启动,因为NFS依赖RPC服务。我之前就因为这个顺序问题折腾了半天。
接下来就是配置导出目录了,编辑/etc/exports
文件:
/data/share 192.168.1.0/24(rw,sync,no_root_squash,no_subtree_check)
/home/backup 192.168.1.100(ro,sync,root_squash)
这个配置文件的语法看起来有点奇怪,但其实很好理解。第一行表示把/data/share
目录共享给192.168.1.0/24网段的所有主机,权限是读写,同步写入,不压缩root权限。
说到权限配置,这里面的坑可不少。no_root_squash
这个选项要慎用,它允许客户端的root用户在NFS服务器上也有root权限。如果你的网络环境不够安全,这就是个巨大的安全隐患。
配置完成后,重新加载配置:
exportfs -ra
可以用exportfs -v
查看当前的导出状态。
客户端挂载
客户端的配置相对简单一些,同样需要安装nfs-utils:
yum install -y nfs-utils
然后就可以挂载了:
mount -t nfs 192.168.1.10:/data/share /mnt/nfs
不过我建议在挂载时指定一些参数:
mount -t nfs -o tcp,rsize=32768,wsize=32768,hard,intr 192.168.1.10:/data/share /mnt/nfs
这些参数的含义:
- tcp:使用TCP协议
- rsize/wsize:读写缓冲区大小
- hard:硬挂载,网络中断时会一直重试
- intr:允许中断
如果要开机自动挂载,可以在/etc/fstab
中添加:
#添加完成一定要记得mount -a,检查下配置是否正确!!!!
192.168.1.10:/data/share /mnt/nfs nfs tcp,rsize=32768,wsize=32768,hard,intr 0 0
性能调优这个老大难问题
NFS的性能一直是个让人头疼的问题。我记得有一次,业务部门抱怨说文件传输太慢了,让我优化一下。当时我就想,这能有多慢?结果一测试,好家伙,传输速度只有几MB/s,这在千兆网络环境下简直不能忍。
网络层面的优化
网络配置对NFS性能影响很大。我发现很多人在配置时都忽略了网络参数的调整。
在服务端,可以增加NFS守护进程的数量:
# 编辑 /etc/sysconfig/nfs
RPCNFSDCOUNT=16
默认情况下,NFS只启动8个守护进程,在高并发场景下明显不够用。我一般会根据CPU核心数来设置,比如16核的服务器就设置16个进程。
另外,网络缓冲区的大小也很关键:
# 在 /etc/sysctl.conf 中添加
net.core.rmem_default = 262144
net.core.rmem_max = 16777216
net.core.wmem_default = 262144
net.core.wmem_max = 16777216
存储层面的考虑
NFS的性能很大程度上取决于底层存储。如果你的服务器用的是机械硬盘,那性能肯定好不到哪里去。我之前在一个项目中,把NFS服务器的存储从SATA硬盘换成SSD,性能提升了好几倍。
文件系统的选择也很重要。ext4虽然稳定,但在大文件和高并发场景下性能一般。如果条件允许,我更推荐使用XFS文件系统,特别是在处理大文件时。
挂载参数的调整
客户端的挂载参数对性能影响也不小。我一般会这样配置:
mount -t nfs -o tcp,rsize=65536,wsize=65536,hard,intr,timeo=14,intr 192.168.1.10:/data/share /mnt/nfs
rsize和wsize设置得大一些可以减少网络往返次数,但也不能设置得太大,否则可能会出现网络包分片的问题。
安全配置不能马虎
NFS的安全性一直是个争议话题。说实话,NFS在设计之初就没有太多考虑安全问题,所以在使用时需要格外小心。
网络层面的安全
最基本的安全措施就是限制访问网段。在/etc/exports
中,一定要明确指定允许访问的IP地址或网段,千万不要使用通配符。
我见过有人这样配置:
/data/share *(rw,sync,no_root_squash)
这简直就是在裸奔!任何能访问到你服务器的主机都可以挂载你的NFS共享,而且还有root权限。
正确的做法应该是:
/data/share 192.168.1.100(rw,sync,root_squash)
/data/share 192.168.1.101(rw,sync,root_squash)
防火墙配置
NFS使用的端口比较多,除了固定的111端口(rpcbind)和2049端口(nfs)外,还有一些随机端口。为了方便防火墙配置,可以固定这些端口。
在/etc/sysconfig/nfs
中添加:
RQUOTAD_PORT=875
LOCKD_TCPPORT=32803
LOCKD_UDPPORT=32769
MOUNTD_PORT=892
STATD_PORT=662
然后在防火墙中开放这些端口:
firewall-cmd --permanent --add-port=111/tcp
firewall-cmd --permanent --add-port=2049/tcp
firewall-cmd --permanent --add-port=875/tcp
firewall-cmd --permanent --add-port=32803/tcp
firewall-cmd --permanent --add-port=32769/udp
firewall-cmd --permanent --add-port=892/tcp
firewall-cmd --permanent --add-port=662/tcp
firewall-cmd --reload
用户权限管理
NFS的用户权限管理是个比较复杂的话题。默认情况下,NFS会根据UID和GID来判断用户权限,这就要求客户端和服务端的用户ID必须一致。
在实际使用中,我一般会创建专门的NFS用户:
# 在服务端和客户端都创建相同的用户
useradd -u 1001 nfsuser
然后把共享目录的所有者设置为这个用户:
chown -R nfsuser:nfsuser /data/share
故障排查的血泪经验
搞NFS这么多年,遇到的奇葩问题不计其数。有些问题看起来很简单,但排查起来却让人抓狂。
挂载失败的常见原因
最常见的问题就是挂载失败。每次遇到这种问题,我都会按照这个顺序排查:
- 检查网络连通性
ping 192.168.1.10
telnet 192.168.1.10 2049
- 检查服务状态
systemctl status rpcbind
systemctl status nfs-server
- 检查导出状态
exportfs -v
showmount -e 192.168.1.10
有一次我遇到一个很奇怪的问题,showmount可以看到导出的目录,但就是挂载不上。折腾了半天才发现是SELinux的问题。
setsebool -P nfs_export_all_rw 1
setsebool -P nfs_export_all_ro 1
性能问题的排查
性能问题相对比较难排查,因为影响因素太多了。我一般会从这几个方面入手:
网络层面,用iperf测试网络带宽:
# 服务端
iperf -s# 客户端
iperf -c 192.168.1.10
存储层面,用dd测试磁盘性能:
dd if=/dev/zero of=/data/share/testfile bs=1M count=1024
NFS层面,用nfsstat查看统计信息:
nfsstat -c # 客户端统
nfsstat -s # 服务端统计
有一次我就是通过nfsstat发现了问题,客户端的retrans(重传)次数特别高,说明网络有问题。后来发现是交换机的某个端口有故障。
文件锁的诡异问题
NFS的文件锁机制真的是让人又爱又恨。理论上很美好,实际使用中问题一大堆。
我印象最深的一次是,有个应用程序在NFS上创建了文件锁,结果服务器突然断电了。重启后,这个锁就一直释放不掉,导致应用程序无法正常工作。
当时试了各种方法,最后只能这样解决:
# 停止相关服务
systemctl stop nfs-server
systemctl stop rpc-statd# 清理锁文件
rm -rf /var/lib/nfs/sm/*
rm -rf /var/lib/nfs/sm.bak/*# 重启服务
systemctl start rpc-statd
systemctl start nfs-server
不过这种方法比较暴力,会影响所有客户端。在生产环境中要慎用!!!!!!!!!!!
实际应用场景的经验分享
这么多年下来,我在不同的场景中都用过NFS,每种场景都有自己的特点和坑点。
Web服务器集群的文件共享
最常见的应用就是Web服务器集群了。多台Web服务器需要共享静态文件,比如图片、CSS、JS等。
在这种场景下,我一般会这样配置:
# 服务端导出配置
/var/www/html/static 192.168.1.0/24(ro,sync,root_squash,no_subtree_check)
注意这里用的是只读权限,因为静态文件一般不需要在Web服务器上修改。如果需要上传文件,我会单独配置一个可写的目录。
客户端挂载时,我会使用这样的参数:
mount -t nfs -o tcp,ro,rsize=32768,wsize=32768,hard,intr,noatime 192.168.1.10:/var/www/html/static /var/www/html/static
noatime参数很重要,它可以避免每次读取文件时更新访问时间,能显著提升性能。
数据库备份的存储
另一个常见场景就是数据库备份。我们有多台数据库服务器,需要把备份文件统一存储到一个地方。
这种场景下,安全性比性能更重要:
# 服务端配置
/data/backup 192.168.1.100(rw,sync,root_squash,no_subtree_check)
/data/backup 192.168.1.101(rw,sync,root_squash,no_subtree_check)
客户端挂载时,我会设置比较保守的参数:
mount -t nfs -o tcp,rw,rsize=8192,wsize=8192,hard,intr,timeo=30 192.168.1.10:/data/backup /backup
缓冲区设置得小一些,超时时间长一些,确保数据的完整性。
开发环境的代码共享
在开发环境中,经常需要多个开发者共享代码。这时候NFS就很方便了,大家都可以直接在自己的机器上编辑代码。
不过这种场景下要注意权限问题。我一般会创建一个开发组:
groupadd -g 2000 developers
然后把所有开发者都加到这个组里,共享目录的权限设置为组可写:
chgrp -R developers /data/code
chmod -R g+w /data/code
NFS的替代方案思考
虽然我用NFS用了这么多年,但不得不承认,它确实有不少局限性。在某些场景下,其他方案可能更合适。
SSHFS的优势
SSHFS基于SSH协议,安全性比NFS好很多。配置也特别简单:
sshfs user@192.168.1.10:/data/share /mnt/sshfs
我在一些对安全性要求比较高的项目中会选择SSHFS。虽然性能比NFS差一些,但胜在安全可靠。
分布式文件系统的崛起
现在越来越多的公司开始使用分布式文件系统,比如GlusterFS、CephFS等。这些系统在可用性和扩展性方面比NFS强很多。
我之前参与过一个项目,就是把原来的NFS系统迁移到GlusterFS。虽然迁移过程比较复杂,但迁移完成后,系统的可用性确实提升了不少。
对象存储的兴起
在云计算时代,对象存储也是个不错的选择。比如AWS的S3、阿里云的OSS等。虽然访问方式和传统文件系统不太一样,但在某些场景下更适合。
一些实用的小技巧
这些年积累了不少NFS使用的小技巧,分享给大家:
自动挂载的配置
手动挂载NFS比较麻烦,可以配置自动挂载。安装autofs:
yum install -y autofs
编辑/etc/auto.master
:
/mnt/auto /etc/auto.nfs --timeout=60
创建/etc/auto.nfs
:
share -tcp,rw 192.168.1.10:/data/share
这样,当你访问/mnt/auto/share
时,系统会自动挂载NFS。
监控脚本的编写
NFS服务的稳定性监控很重要,我写了个简单的监控脚本:
#!/bin/bash
NFS_SERVER="192.168.1.10"
NFS_PATH="/data/share"
MOUNT_POINT="/mnt/nfs"if ! mountpoint -q $MOUNT_POINT; thenecho "NFS not mounted, trying to mount..."mount -t nfs $NFS_SERVER:$NFS_PATH $MOUNT_POINT
fiif ! timeout 5 ls $MOUNT_POINT > /dev/null 2>&1; thenecho "NFS access failed, remounting..."umount -f $MOUNT_POINTmount -t nfs $NFS_SERVER:$NFS_PATH $MOUNT_POINT
fi
把这个脚本加到crontab里,每分钟执行一次,可以自动处理一些常见的NFS问题。
性能测试的方法
想要知道NFS的性能如何,可以用这个简单的测试:
# 写入测试
time dd if=/dev/zero of=/mnt/nfs/testfile bs=1M count=1024# 读取测试
echo 3 > /proc/sys/vm/drop_caches # 清理缓存
time dd if=/mnt/nfs/testfile of=/dev/null bs=1M
这个测试虽然简单,但能大致反映NFS的性能水平。
踩过的坑和经验教训
说了这么多技术细节,最后想分享一些我踩过的坑,希望大家能避免。
不要忽视网络质量
有一次,业务部门反映NFS访问特别慢,我检查了服务器配置、存储性能,都没问题。最后发现是网络设备有问题,丢包率达到了5%。在这种网络环境下,NFS的性能肯定好不了。
所以在部署NFS之前,一定要先测试网络质量。
备份配置文件的重要性
还有一次,我在调整NFS配置时,不小心把/etc/exports
文件搞坏了。结果所有客户端都挂载不上了,业务直接中断。
幸好我有备份配置文件的习惯,很快就恢复了。从那以后,我每次修改配置前都会先备份:
cp /etc/exports /etc/exports.bak.$(date +%Y%m%d)
权限问题要提前规划
NFS的权限管理比较复杂,如果不提前规划好,后期会很麻烦。我建议在部署之前就把用户权限体系设计好,包括用户ID的分配、组的设置等。
监控和告警不能少
NFS服务虽然相对稳定,但也会出现各种问题。一定要做好监控和告警,及时发现问题。
我一般会监控这些指标:
- NFS服务的运行状态
- 挂载点的可用性
- 网络连通性
- 磁盘空间使用率
总结
写了这么多,感觉还有很多东西没有涉及到。NFS这个东西,说简单也简单,说复杂也复杂。关键是要在实践中不断积累经验。
我的建议是:
- 在内网环境下使用,不要暴露到公网
- 做好安全配置,不要图省事给过大权限
- 根据实际场景调整性能参数
- 做好监控和备份,及时发现和解决问题
- 在高可用要求的场景下考虑其他方案
NFS虽然有这样那样的问题,但在合适的场景下,它依然是个不错的选择。特别是在中小型企业的内网环境中,NFS的简单易用还是很有优势的。
当然,技术在不断发展,新的文件共享方案也在不断涌现。我们要保持学习的心态,根据实际需求选择最合适的方案。
希望这篇文章能帮到正在使用或者准备使用NFS的朋友们。如果你们在使用过程中遇到什么问题,或者有更好的经验分享,欢迎在评论区交流讨论!
记得关注微信公众号@运维躬行录,我会持续分享更多实用的运维经验和技术干货。如果这篇文章对你有帮助,别忘了点赞转发,让更多的朋友看到!
公众号:运维躬行录
个人博客:躬行笔记