我有一个 NFS 挂载,文件(有时具有一定大小)正在由不同的系统写入,现在我正在轮询新文件。我需要等到文件完全完成才能使用我的脚本处理它。我不控制写入这些文件或其名称的过程。
fusionr 和 lsof 似乎检查了我的本地系统,但如果不同的系统正在写入 NFS 挂载,则无法正确处理。我不相信如果它是 v3,我可以监听文件事件(但我可以监听 v4?),并且不需要等待一段时间让文件大小停止增长(并祈祷网络不会出现问题),我不知道有什么方法可以保证它的完整性,就像您在本地查找文件句柄一样。有解决办法吗?如果没有,是否有适用于 NFSv4 的解决方案?
答案1
nfsv3是无状态的,没有办法保证它的状态。但是 NLM(网络锁定管理器)必须在两侧运行。
nfsv4 具有锁定操作 open/read/write/lock/close 并保持 OPEN CLOSE 状态。如果可以的话,您应该更改为 nfsv4。
答案2
理想的解决方案是发送者将文件放置在带有临时后缀 ( .tmp
) 的 NFS 共享上,并仅在复制完成后才重命名:
# Sender
# There are better ways of writing this code; it's just an illustration
#
if cp /from/source/data.xml /to/nfs/share/data.xml.tmp
then
# copy succeeded; rename
mv -f /to/nfs/share/data.xml.tmp /to/nfs/share/data.xml
fi
即使在 NFS 上,重命名也是原子的,因此只要接收者忽略带有后缀的文件.tmp
,任何其他文件(data.xml
在本示例中)都会在接收者看来立即完全到达 NFS 共享。
但是,您解释说不幸的是您无法控制发件人。
在这种情况下,您实际上无法做太多事情来保证文件已完全传输。各种选项包括在数据中查找 END 标记(特定于正在传输的数据的标记,不一定是文字“END”字符串),或在处理文件之前尝试解析文件。以下是检查 XML 文件的示例:
# XML validation
if xmlstarlet validate /to/nfs/share/data.xml
then
# An XML file validated so it must be complete
...
fi
将此方法加入到仅考虑文件几分钟内未更改的方法中,您可能会得到一个可行的解决方案:
find /to/nfs/share -type f -mmin +5 -name '*.xml' -print0 |
while IFS= read -d '' file
do
if validate-the-file "$file"
then
process-the-file "$file"
rm -f "$file"
fi
done
或者
find /to/nfs/share -type f -mmin +5 -name '*.xml' -exec sh -c '
for file in "$@"
do
process-the-file "$file"
rm -f "$file"
done
' _ {} +