踩坑笔记 NFS坑-2个pod读写文件延迟问题

文章目录

现象

有2个服务通过NFS去共享文件,一个服务创建,一个服务读取。

  • A服务在podA上创建文件
  • B服务在podB上查找A创建的文件

问题: 偶先的B服务查找不到A创建的文件

排查

排查过程如下

1.查看A和B服务POD的磁盘挂载和使用情况

sh 复制代码
#查看磁盘挂载和使用情况
df -h

发现使用了nfs挂载以及挂载的目录

2.复现文件,去日照查找指定文件

我会在B服务查找文件的代码,前后打印当前文件夹下的文件

ini 复制代码
listfiles("list - pre") // 增加日志
xxxfile.exits()
listfiles("list - post")// 增加日志
ini 复制代码
#查找日志
grep 'list - ' *.log
07:28:40,382 ...
07:28:45,390 ...
07:28:50,400 ...
07:28:55,411 ...
07:29:00,414 ...

发现在当时的场景中文件夹中的确没有要查询的文件。

3.查找指定问题文件

sh 复制代码
#查找文件
find /nfs/pic -name abc.jpg
find . -name abc.jpg
#查找目录
find . -type d -name abc

发现文件时存在的

4.查找文件详细信息创建时间

sh 复制代码
ll --full-time
nobody nobody 2023-10-11 07:08:40.144 abc.jpg

发现创建时间是在程序读取后的时间。

就怀疑是NFScache问题,查找相关资料总结如下

原因

1.在传统磁盘中,所有的数据都会被缓存在PageCache中,修改过的Page会被异步刷回服务端,所以磁盘的延时都比较低。

2.但在NFS文件系统中,NFS不会将新创建的文件或者新写入的内容缓存在PageCache中,而是尽快刷回NAS服务端。

因此,当多个服务器共享一个NFS协议文件系统时,NAS所有的操作都会比磁盘多一次网络调用开销,这个开销一般在100us ~ 1ms之间。其中,尽快刷回NAS服务端,则涉及NAS所提供的如下多节点一致性模型:

  • 模型1 基于超时的最终一致性

NFS会缓存目录或者文件的属性(FileAttr),操作系统会根据FileAttr是否发生变化,来判断这个目录或者文件是否在其他ECS被修改过。同时,加载FileAttr后,操作系统在T时间内,会认为Cache(例如,文件的内容、目录下的文件列表)有效;超过T时间后,会去服务端重新获取一次FileAttr,如果FileAttr未发生变化,操作系统会认为与此文件相关的Cache全部还是有效的。

说明

  • T为自适应的值。默认值:1s~60s。
  • 文件内容Cache:指缓存了这个文件的内容。
  • 目录子项Cache:缓存了这个目录下存在哪些文件、不存在哪些文件。

文件内容Cache示例

  1. ECS-1读取了文件X的0~4K:第一次读,cache不命中,访问服务器,读取数据,并缓存在本地。
  2. ECS-2更新了文件X的0~4K:数据写到服务端,更新FileAttr中的mtime。
  3. ECS-1再次读文件X的04K:第二次读,如果时间距离第一次小于T,由于FileAttr还没有过期,因此,直接使用缓存中的04K。
  4. ECS-1再次读文件X的0~4K:第三次读,如果时间距离第一次大于T,则去访问服务端,获取新的FileAttr,然后发现mtime变了,因此丢弃cache中的数据,去服务端读。

我们遇到的问题就是这个原因 ,第一次查询文件时,发现文件不存在就缓存了一个不存在的cache,导致下次直接查缓存,还是不存在。

目录子项Cache示例:

  1. ECS-1尝试查找/a:第一次查找,发现a不存在,于是在目录/下缓存一个a不存在的信息。
  2. ECS-2创建文件/a。
  3. ECS-1再次查找/a:第二次查找,由于时间小于T,直接使用cache,然后向用户报错文件不存在。
  4. ECS-1 再次访问/a:第三次查找,由于时间大于T,访问服务端,获取目录/最新的FileAttr,发现mtime有变化,则丢弃cache中的数据,去服务端查询/a。

更多有关NFS超时的最终一致性模型内容,请参见NFS

  • 模型二 基于文件close/open的CTO一致性

由于超时的最终一致性无法保证ECS-2可以立刻读ECS-1写入的数据。因此,为了提升一致性,NFS还提供了基于文件的CTO(close-to-open)一致性保证,即当两个及以上计算节点同时读写相同的文件时,ECS-1的修改在ECS-2不一定能立即看到。但是,一旦ECS-1打开一个文件,写入若干数据,然后执行了文件关闭操作,之后在任何一个计算节点重新打开该文件都可以保证能访问到新写入的数据。

例如,生产者ECS生产了文件X,生产完毕后执行了close。

然后给消息队列发一条消息 说,文件X生产完毕。

消费者ECS订阅消息队列,读到消息X(文件X生产完毕),

此时,消费者ECS再去open这个文件,通过open返回的fd去读取这个文件,则一定能够读到文件X的所有内容。如果消费者ECS在生产者ECS生产完毕之前,就open了文件X,并且持有了fd,当收到消息后,直接用这个fd去读,是不保证能够读取到最新数据的。


问题简化为:ECS-1创建了文件abc,但是ECS-2需要过一段时间才能看到ECS-1创建的文件abc,有时会延迟1s,有时甚至会到1分钟,这是为什么?

综合一下上面的一坨:这是Lookup Cache导致的,符合预期T时间。例如,ECS-2在ECS-1创建文件abc前进行了访问,导致ECS-2发生文件不存在,于是缓存了一条文件abc不存在的记录。在T时间内,由于FileAttr还没有过期,ECS-2再次访问时,仍会访问第一次缓存到文件abc不存在的记录。


解决方案

方案一

在程序中 循环检测(比如检测10次) ,注意间隔的时长 不要太长 1-2s,我们这边设置5秒时 有问题。

方案二

关闭ECS-2的Nagtive Lookup Cache,不缓存不存在的文件。该方案开销最小。

挂载时,添加lookupcache=positive(默认值lookupcache=all)字段,挂载命令如下所示:

sh 复制代码
sudo mount -t nfs -o vers=3,nolock,proto=tcp,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport,lookupcache=positive file-system-id.region.nas.aliyuncs.com:/ /mnt

方案三

关闭ECS-2的所有缓存。该方案会导致性能非常差,请根据业务实际情况选择合适的方案。

挂载时,添加actimeo=0字段,挂载命令如下所示:

sh 复制代码
sudo mount -t nfs -o vers=3,nolock,proto=tcp,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport,actimeo=0 file-system-id.region.nas.aliyuncs.com:/ /mnt

总结

尽管上述解决方案可以在一定程度上减轻NFS文件同步延迟问题 ,但它们仍然需要处理许多复杂的技术细节。然而,有一种更简单和可行的方法,可以彻底摆脱NFS的问题,那就是使用云对象存储服务(如OSS,对象存储服务)。

参考

相关推荐
ZJU_统一阿萨姆13 小时前
【推理优化进阶】通信关键路径:NCCL、RDMA 与计算通信重叠
开发语言·人工智能·语言模型·架构·系统架构
m0_5873830013 小时前
智慧场馆解决方案实战指南:从系统架构到落地部署全解析
java·spring boot·架构·系统架构
我不是疯子是傻子13 小时前
Qt 程序打包部署全攻略:从 windeployqt 到 Inno Setup 的静默安装与版本迭代实战
开发语言·qt
ZC跨境爬虫13 小时前
LeetCode 13. 罗马数字转整数(多解法详解 + Java Python 实现)
java·python·leetcode
省长13 小时前
Sa-Token v1.46.0 发布 🚀,来看看有没有令你心动的功能!
java·后端·开源
IT古董14 小时前
【WMS学习笔记系列】03-功能模块设计
笔记·学习·系统架构
LayZhangStrive14 小时前
融360 一面
java·面试·后端开发
城管不管14 小时前
重生——第十次面试之开源中国一面挂
java·linux·开发语言·算法·面试·职场和发展·开源
Java小白笔记14 小时前
Windows系统免软件命令激活
java·网络·人工智能·windows·ai·ai编程
爱敲键盘的猴子14 小时前
深入理解 Java HashMap
java·hashmap