У нас есть настройка nginx/php-fpm на EC2, которая получает фрагменты файлов в папку «chunk», установленную NFS (специально для SoftNAS), которая распределяется между несколькими серверами приложений. У нас есть проблема, когда приложение проверяет наличие файла перед загрузкой готового файла на S3, но проверка файла не работает, даже если файл есть.PHP file_exists или is_file не отвечает правильно в течение 10-20 секунд в файлах NFS (EC2)
Приложение имеет clearstatcache() на месте перед файлом is_file() или file_exists() (мы пробовали оба), но файл не становится видимым для приложения в течение 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.
- Прикоснитесь к файлу перед записью на него в приложении 1.
- Прикоснитесь к файлу, прежде чем проверять, существует ли он на app2.
- Использование различных методов записи файла из app1 и , явно закрывающего поток записи и освобождение блокировки в файле .
- Изменение задержек между считываемыми циклами (например, без задержки или с задержкой до 1 секунды).
- Использование exec для «ls» каталога после записи в него из приложения 1.
- Использование exec для «ls» в каталоге перед каждым файлом существует проверка на app2.
Ничего подобного не имеет никакого значения. Мы не проводили подробных тестов по каждому варианту, но каждый из них, казалось, занимал слишком много времени, прежде чем файл будет проверен.
Есть одна вещь, которая действительно работала. Выполняя цикл «ls» на app2 в оболочке, файл мгновенно читается скриптом 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
Так, что-то в оболочке правильно очистить кэш NFS, но ясно команда кэш PHP не представляется никакой разницы.
(Edit) код в вопросе:
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, является неоптимальным решением.
'clearstatcache()' только очищает межсетевой кеш текущего процесса php-скрипта. Итак, 'file_exists ('file.a'); unlink ('file.a'); file_exists ('file.a');' здесь оба файла_exists выдают true. Исправлено 'file_exists ('file.a'); unlink ('file.a'); clearstatcache(); file_exists ('file.a');' теперь второй файл_файлы теперь дает false. Возможно, у вас есть проблемы с указателями файлов (из любого места), которые блокируют некоторые действия. – JustOnUnderMillions
Сначала покажите код: отладочный вывод без контекста кода бесполезен. Во-вторых, вы говорите 'is_file' (et al.) Call * blocks * для 10s-20s? В-третьих, что именно вы делаете в оболочке, которая «исправляет» это? – bishop
Нет, is_file() сообщает false в течение 10-20 секунд. Команда «ls» запускается в оболочке на сервере app2, в то время как файл написан на app1. Запуск «ls» заставляет app2 is_file() возвращать true сразу, а не через 10-20 секунд. –