2017-01-18 12 views
2

У нас есть настройка 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, является неоптимальным решением.

+0

'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

+0

Сначала покажите код: отладочный вывод без контекста кода бесполезен. Во-вторых, вы говорите 'is_file' (et al.) Call * blocks * для 10s-20s? В-третьих, что именно вы делаете в оболочке, которая «исправляет» это? – bishop

+0

Нет, is_file() сообщает false в течение 10-20 секунд. Команда «ls» запускается в оболочке на сервере app2, в то время как файл написан на app1. Запуск «ls» заставляет app2 is_file() возвращать true сразу, а не через 10-20 секунд. –

ответ

1

Вот что происходит. Кэш статиста PHP использует атрибут atime, доступный из базовой VFS. Когда NFS передает VFS, атрибуты могут кэшировать, чтобы уменьшить количество обращений к серверу. К сожалению, они могут заставить PHP «лгать» о состоянии, потому что на самом деле сервер NFS не предоставил текущую информацию VFS.

Вы можете принудительно скорректировать согласованность с опцией крепления noac. Я рекомендую использовать это на любом сервере, где вам абсолютно необходима положительная информация в кратчайшие сроки:

Используйте параметр noac mount для обеспечения согласованности кеша атрибутов между несколькими клиентами. Почти каждая операция файловой системы проверяет информацию об атрибутах файла. Клиент сохраняет эту информацию в кэше в течение определенного периода времени, чтобы снизить нагрузку на сеть и сервер. Когда noac действует, кеш атрибута файла клиента отключен, поэтому каждая операция, которая должна проверять атрибуты файла, принудительно возвращается на сервер. Это позволяет клиенту просматривать изменения в файле очень быстро, за счет многих дополнительных сетевых операций.

Если noac работает слишком медленно, есть другие варианты монтирования, которые могут лучше настроить кеш для ваших нужд. См.: lookupcache и actimeo. Например, уменьшение actimeo снизит время, в течение которого NFS локально кэширует информацию: по умолчанию используется 30 секунд (минимум) до 60 секунд (максимум). Или, как еще один пример, lookupcache=positive обеспечит более быстрый интеллект при появлении новых файлов, но будет долго скрывать их существование даже после отмены.

Но почему, когда у вас нет этих параметров монтирования, ls в каталоге «исправить» проблему? Оказывается, что opendir и closedir последовательность отменяет кеш атрибутов NFS, что заставляет обратный вызов на сервер.

Итак, в вашем случае вы используете последовательность opendir()/closedir(), чтобы аннулировать кеш. Я не уверен, будет ли работать system("ls"), так как я считаю, что каждый процесс имеет другой вид кеша атрибутов, но стоит попробовать.

+0

Могу ли я использовать noac в сочетание с noatime и noadirtime или делает это недействительными? –

+0

@JeremyWilson Я считаю, что 'noac' является надмножеством' noatime' и 'nodiratime'. Лично я бы просто установил 'noac'. – bishop

+0

Использование opendir() решило проблему на уровне PHP, поэтому мне не нужно настраивать параметры NFS. Благодаря! –