У нас есть установка nginx / php-fpm на EC2, которая получает фрагменты файлов в папку «chunk», смонтированную по NFS (в частности, SoftNAS), которая используется несколькими серверами приложений. У нас есть проблема, когда приложение проверяет наличие файла перед загрузкой готового файла на S3, но проверка файла не выполняется, даже если файл там есть.
Приложение имеет 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
Мы попробовали несколько вариантов проверки файла:
Ни одна из этих вещей, кажется, не имеет никакого значения. Мы не запускали обширные тесты для каждого варианта, но каждый из них, казалось, занимал слишком много времени, прежде чем проверка файла прошла.
Есть одна вещь, которая сработала. При запуске цикла «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, похоже, не имеет никакого значения.
(Изменить) рассматриваемый код:
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) Оказывается, запуск exec () с «ls» в коде успешно удаляет любое кэширование на уровне файлов на системном уровне, но по очевидным причинам exec () каждый раз, когда мы выполняем file_exists, является неоптимальным решение.
Вот что происходит. Статистический кеш PHP основан на атрибуте atime, который доступен из базовой VFS. Когда NFS включает VFS, атрибуты подвергаются кэшированию, чтобы уменьшить количество обращений к серверу. Это, к сожалению, может заставить PHP «лгать» о состоянии, потому что на самом деле сервер NFS не предоставил текущую информацию VFS.
Вы можете добиться немедленной согласованности с noac
опция монтирования Я рекомендую использовать это на любом сервере, где вам абсолютно положительно нужна самая свежая информация в кратчайшие сроки:
Используйте параметр монтирования noac для достижения согласованности кэша атрибутов между несколькими клиентами. Почти каждая операция файловой системы проверяет информацию об атрибутах файла. Клиент хранит эту информацию в кэше в течение некоторого времени, чтобы снизить нагрузку на сеть и сервер. Когда действует noac, кэш атрибутов файлов клиента отключен, поэтому каждая операция, которая должна проверять атрибуты файла, принудительно возвращается на сервер. Это позволяет клиенту видеть изменения в файле очень быстро, за счет многих дополнительных сетевых операций.
Если noac
слишком медленный, есть другие варианты монтирования, которые могут лучше настроить кеш для ваших нужд. Увидеть: lookupcache
а также actimeo
, Например, уменьшение actimeo
уменьшит время локального кэширования информации NFS: по умолчанию 30 секунд (минимум) до 60 секунд (максимум). Или, как еще один пример, lookupcache=positive
обеспечит более быструю разведку появления новых файлов, но будет долго кешировать их существование даже после разрыва связи.
Но почему, когда нет этих опций монтирования, ls
в каталоге «исправить» проблему? Получается что opendir
а также closedir
Последовательность делает недействительным кэш атрибутов NFS, что вызывает обратный вызов на сервер.
Так что в вашем случае вы используете opendir()/closedir()
последовательность для аннулирования кэша. Я не уверен, если system("ls")
будет работать, так как я считаю, что каждый процесс имеет свое представление о кеше базовых атрибутов, но стоит попробовать.
Других решений пока нет …