gpt4 book ai didi

PHP file_exists 或 is_file 在 NFS 文件 (EC2) 上无法正确回答 10-20s

转载 作者:太空狗 更新时间:2023-10-29 11:50:04 26 4
gpt4 key购买 nike

我们在 EC2 上有一个 nginx/php-fpm 设置,它将文件 block 接收到一个 NFS 安装的“ block ”文件夹(特别是 SoftNAS),该文件夹在多个应用程序服务器之间共享。我们遇到一个问题,应用程序在将完成的文件上传到 S3 之前检查文件是否存在,但即使文件存在,文件检查也失败。

应用在 is_file() 或 file_exists() 之前有一个 clearstatcache()(我们都试过了),但该文件在 10-20 秒内对应用不可见。

这是该测试的一些运行的输出:

 app1 write timestamp 1484702190.5575
app2 read timestamp 1484702216.0643
25.5068 seconds

app1 write timestamp 1484702229.0130
app2 read timestamp 1484702246.0652
17.0522 seconds

app1 write timestamp 1484702265.6277
app2 read timestamp 1484702276.0646
10.4369 seconds

app1 write timestamp 1484702286.0136
app2 read timestamp 1484702306.0645
20.0509 seconds

app1 write timestamp 1484702314.4844
app2 read timestamp 1484702336.0648
21.5804 seconds

app1 write timestamp 1484702344.3694
app2 read timestamp 1484702366.0644
21.6950 seconds

app1 write timestamp 1484702374.0460
app2 read timestamp 1484702396.0645
22.0185 seconds

app1 write timestamp 1484702404.0346
app2 read timestamp 1484702426.0647
22.0301 seconds

app1 write timestamp 1484702434.2560
app2 read timestamp 1484702456.1092
21.8532 seconds

app1 write timestamp 1484702466.0083
app2 read timestamp 1484702486.1085
20.1002 seconds

app1 write timestamp 1484702496.5466
app2 read timestamp 1484702516.1088
19.5622 seconds

app1 write timestamp 1484702525.2703
app2 read timestamp 1484702546.1089
20.8386 seconds

app1 write timestamp 1484702558.3312
app2 read timestamp 1484702576.1092
17.7780 seconds

我们已经尝试了多种检查文件的方法:

  • 在检查文件是否存在时使用 is_file 和 file_exists 函数存在于 app2 上。
  • 使用 clearstatcache 函数的所有变体在检查文件是否存在于 app2 之前。
  • 在 app1 上写入文件之前触摸该文件。
  • 先触摸该文件,然后再检查它是否存在于 app2 上。
  • 使用不同的方法从 app1 和显式关闭写流并释放锁文件。
  • 读取循环之间的不同延迟(例如无延迟或最多延迟 1 秒)。
  • 在从 app1 写入目录后使用 exec 来“ls”目录。
  • 在检查 app2 上的每个文件之前使用 exec 来“ls”目录。

这些事情似乎都没有任何区别。我们没有对每个选项进行广泛的测试,但在文件存在检查通过之前,每个选项似乎都花费了过长的时间。

有一件事确实奏效了。在 shell 中的 app2 上运行“ls”循环,app2 脚本可立即读取该文件。

 app1 write timestamp 1484703581.3749
app2 read timestamp 1484703581.3841
0.0092 seconds

app1 write timestamp 1484703638.81 00
app2 read timestamp 1484703638.8139
0.0039 seconds

app1 write timestamp 1484703680.8548
app2 read timestamp 1484703680.8576
0.0028 seconds

因此,shell 中的某些内容正确地清除了 NFS 缓存,但 PHP 中的清除缓存命令似乎没有任何区别。

(编辑)有问题的代码:

public static function get($filepath) {

clearstatcache(TRUE, $filepath);

if (file_exists($filepath)) {
$instance = new static::$_class;
$instance->init($filepath);
return $instance;
} else {

// Sometimes a new file is not found with the first is_file() attempt.
// Clear the stat cache and try to find the file again.

clearstatcache(TRUE, $filepath);

if (file_exists($filepath)) {
$instance = new static::$_class;
$instance->init($filepath);
return $instance;
}
}

Log::error("AJRFSFILE " . $_SERVER['PATH_INFO'] . " " . $_SERVER['HTTP_DEVICE'] . " " . $filepath . " " . json_encode(stat($filepath)));

return false;
}

(Edit2) 结果表明,在代码中使用“ls”运行 exec() 可以成功清除系统级发生的任何文件级缓存,但出于显而易见的原因,每次执行 file_exists 时 exec() 都是一个次优解。

最佳答案

这是正在发生的事情。 PHP 统计缓存依赖于 atime 属性,该属性可从底层 VFS 获得。当 NFS 为 VFS 提供动力时,属性会被缓存以减少服务器往返。不幸的是,这些可能导致 PHP 对状态“撒谎”,因为实际上 NFS 服务器没有提供 VFS 当前信息。

您可以使用 noac 挂载选项强制立即保持一致性。我建议在您绝对肯定地需要在尽可能短的时间内获得最新信息的任何服务器上使用它:

Use the noac mount option to achieve attribute cache coherence among multiple clients. Almost every file system operation checks file attribute information. The client keeps this information cached for a period of time to reduce network and server load. When noac is in effect, a client’s file attribute cache is disabled, so each operation that needs to check a file’s attributes is forced to go back to the server. This permits a client to see changes to a file very quickly, at the cost of many extra network operations.

如果 noac 太慢,还有其他挂载选项可能会根据您的需要更好地调整缓存。请参阅:lookupcacheactimeo。例如,减少 actimeo 将减少 NFS 本地缓存信息的时间:默认值为 30 秒(最小值)到 60 秒(最大值)。或者,作为另一个示例,lookupcache=positive 将提供有关新文件外观的更快智能,但即使在取消链接后也会长期缓存它们的存在。

但是,为什么在没有这些挂载选项的情况下,目录中的 ls 会“修复”这个问题?结果是 opendirclosedir 序列使 NFS 属性缓存无效,这会强制调用回服务器。

因此,在您的情况下,您使用 opendir()/closedir() 序列来使缓存无效。我不确定 system("ls") 是否有效,因为我相信每个进程对底层属性缓存都有不同的看法,但值得一试。

关于PHP file_exists 或 is_file 在 NFS 文件 (EC2) 上无法正确回答 10-20s,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41723458/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com