【问题标题】:Random corruption in file created/updated from shell script on a singular client to NFS mount从单个客户端上的 shell 脚本创建/更新到 NFS 挂载的文件中的随机损坏
【发布时间】:2013-12-25 22:47:02
【问题描述】:

我们有 bash 脚本(作业包装器),它写入文件、启动作业,然后在作业完成时将有关作业的信息附加到文件中。包装器在数千个批处理节点之一上运行,但只出现了几台批处理机器(我相信是 RHEL6)访问一个 NFS 服务器,以及在不同批处理节点上使用不同批处理作业的至少一个已知实例NFS 服务器。在所有情况下,只有一个客户端主机正在写入相关文件。有些作业需要几个小时才能运行,有些则需要几分钟。

在发生这种情况的同一时间段内,100,000 多个工作中似乎有 10-50 个问题。

这是我认为有效的作业包装器的(蒸馏)版本:

#!/bin/bash
## cwd is /nfs/path/to/jobwd
## This file is /nfs/path/to/jobwd/job_wrapper

gotEXIT()
{
    ## end of script, however gotEXIT is called because we trap EXIT
    END="EndTime: `date`\nStatus: Ended”
    echo -e "${END}" >> job_info
    cat job_info | sendmail jobtracker@example.com
}
trap gotEXIT EXIT

function jobSetVar { echo "job.$1: $2" >> job_info; }
export -f jobSetVar

MSG=“${email_metadata}\n${job_metadata}”
echo -e "${MSG}\nStatus: Started" | sendmail jobtracker@example.com
echo -e "${MSG}" > job_info

## At the job’s end, the output from `time` command is the first non-corrupt data in job_info
/usr/bin/time -f "Elapsed: %e\nUser: %U\nSystem: %S" -a -o job_info job_command

## 10-360 minutes later…
RC=$?
echo -e "ExitCode: ${RC}" >> job_info

所以我认为有两种可能:

  1. echo -e "${MSG}" > job_info
    此命令会抛出损坏的数据。

  2. /usr/bin/time -f "Elapsed: %e\nUser: %U\nSystem: %S" -a -o job_info job_command
    这会破坏现有数据,然后正确输出数据。

但是,某些作业(但不是全部)调用 jobSetVar,它最终不会损坏。

因此,我深入研究了 time.c(从 GNU 时间 1.7 开始)以查看文件何时打开。总而言之,time.c 实际上是这样的:

FILE *outfp;

void main (int argc, char** argv) {
  const char **command_line;
  RESUSE res;

  /* internally, getargs opens “job_info”, so outfp = fopen ("job_info", "a”) */
  command_line = getargs (argc, argv); 
  /* run_command doesn't care about outfp */
  run_command (command_line, &res);
  /* internally, summarize calls fprintf and putc on outfp FILE pointer */
  summarize (outfp, output_format, command_line, &res);  /
  fflush (outfp);
}

所以,time 让FILE *outfp(job_info 句柄)打开了整个作业时间。然后它在作业结束时写入摘要,然后实际上并没有关闭文件(不确定 fflush 是否需要这样做?)我不知道 bash 是否也同时打开了文件句柄.

编辑:

损坏的文件通常由损坏的部分组成,然后是未损坏的部分,如下所示:

损坏的部分,发生在未损坏的部分之前,通常主要是一堆 0x0000,可能混入了一些循环垃圾:

这是一个 hexdump 示例:

40000000 00000000 00000000 00000000 
00000000 00000000 C8B450AC 772B0000
01000000 00000000 C8B450AC 772B0000
[ 361 x 0x00] 

然后,在第 409 个字节处,它继续未损坏的部分:

Elapsed: 879.07
User: 0.71
System: 31.49
ExitCode: 0
EndTime: Fri Dec  6 15:29:27 PST 2013
Status: Ended

另一个文件如下所示:

01000000 04000000 805443FC 9D2B0000 E04144FC 9D2B0000 E04144FC 9D2B0000
[96 x 0x00]
[Repeat above 3 times ]
01000000 04000000 805443FC 9D2B0000 E04144FC 9D2B0000 E04144FC 9D2B0000

后面是未损坏的部分:

Elapsed: 12621.27
User: 12472.32
System: 40.37
ExitCode: 0
EndTime: Thu Nov 14 08:01:14 PST 2013
Status: Ended

还有其他文件有更多的随机损坏部分,但不止一些是与上述类似的循环。

编辑 2: 从echo -e 语句发送的第一封电子邮件正常。由于没有电子邮件元数据损坏,最后一封电子邮件永远不会发送。所以MSG 在那一点上没有损坏。假设 job_info 可能 在那时也没有损坏,但我们还无法验证这一点。这是一个没有进行重大代码修改的生产系统,我已经通过审计验证了没有同时运行的作业会触及这个文件。这个问题似乎是最近才出现的(过去 2 个月),但它可能以前发生过并被忽略了。此错误确实会阻止报告,这意味着作业被视为失败,因此通常会重新提交它们,但特定用户有大约 9 小时的作业,其中此错误特别令人沮丧。我希望我能想出更多信息或随意复制它的方法,但我希望有人可能已经看到了类似的问题,尤其是最近。我不管理 NFS 服务器,但我会尝试与管理员交谈,了解在这些问题(我相信是 RHEL6)运行时 NFS 服务器的更新。

【问题讨论】:

  • 有趣的效果!您能否举例说明损坏的文件通常是什么样的?
  • 我添加了几个例子

标签: bash time batch-processing nfs


【解决方案1】:

好吧,与损坏的 job_info 文件对应的电子邮件应该会告诉您 MSG 中的内容(这可能会照常营业)。您可能想检查 NFS 是如何运行的:您很可能在没有校验和的情况下通过 UDP 运行 NFS。这可以解释一些损坏的数据。我还听说 UDP/TCP 校验和不够强大,数据仍然可能最终损坏——也许你遇到了这样的问题(我以前至少见过一次损坏的数据包从网络堆栈中滑过,我很确定正在进行一些校验和)。据推测,MSG 作为一个单独的数据包出去,并且可能有一些东西使校验和与您看到的垃圾发生冲突的可能性更大。当然,它也可能是 NFS 错误(客户端或服务器)、服务器端文件系统错误、RAM 被破坏......这里的可能性几乎是无穷无尽的(尽管我看到它总是被损坏的 MSG 的事实如何使一些那些不太可能的)。问题可能与寻求(在追加期间发生)有关。你也可能在系统的其他地方有一个错误,导致多个客户端打开同一个 job_info 文件,使其变得混乱。

【讨论】:

  • 我添加了更多信息。明天我将与管理员联系,以了解有关操作系统和 NFS 客户端和服务器版本的信息。我不相信它是 RAM,因为它发生在至少六个不同的批处理节点和两个单独的服务器(都有 ECC、FWIW)上。我不认为它与网络有关,它只是在这个特定文件和这 2 台服务器上表现出 AFAIK。所以这很令人困惑,因为我至少希望这会出现在系统的其他地方,因为写入这个文件是相当基本的。
【解决方案2】:

您也可以尝试使用不同的文件来输出“时间”,然后在脚本末尾将它们与 job_info 合并。这可能有助于进一步隔离问题。

Shell 打开“job_info”文件进行写入,输出 MSG,然后在启动主作业之前关闭其文件描述符。 “时间”程序打开相同的文件作为流追加,我怀疑通过 NFS 的搜索没有正确完成,这可能会导致垃圾。无法解释原因,但通常这不会发生(也不会发生)。这种罕见的情况可能指向某处的某些竞争条件,可能是由于数据包交付顺序不正确(由于网络延迟峰值)或导致重复数据的重新传输,或某处的错误。乍一看我会怀疑一些错误,但该错误可能是由某些网络行为触发的,例如异常大的延迟或丢包峰值。

不同进程之间的文件访问由内核序列化,但为了额外的保护,可能值得添加一些人为延迟 - 例如输出之间的睡眠计时器。

网络不透明,尤其是大型网络。可能存在已知有时会导致应用程序问题的 WAN 优化设备。 CIFS 和 NFS 是通过 WAN 优化文件系统操作的本地缓存的良好候选者。可能值得与网络管理员一起寻找最近的变化..

要尝试的另一件事是通过 tcpdump 或 wireshark 捕获有趣的 NFS 会话,尽管由于很少发生可能会很困难。在非常困难的情况下,我们在客户端和服务器端同时进行捕获,然后比较协议逻辑以证明网络是否正常工作。这本身就是一个完整的话题,需要充分的准备和运气,但通常是绝望的故障排除的最后手段:)

【讨论】:

    【解决方案3】:

    事实证明,这实际上是另一个问题,显然与将过期页面写入磁盘有关。

    为 linux-nfs 实现提供了一个错误修复: http://www.spinics.net/lists/linux-nfs/msg41357.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-10
      • 2020-01-13
      • 1970-01-01
      相关资源
      最近更新 更多