Странное поведение с Perl NFS Lock - PullRequest
0 голосов
/ 25 февраля 2020

Я испытываю странное поведение из File :: NFSLock в Perl v5.16. Я использую устаревшую опцию ожидания как 5 минут. Допустим, у меня есть три процесса. Один из них занял более 5 минут, прежде чем снять блокировку, и процесс 2 получил блокировку. Однако даже процесс 2 имеет блокировку менее 5 минут, идет третий процесс и удаляется файл блокировки, что приводит к сбою 2-го процесса при удалении удерживаемого NFSLock.

Моя теория гласит, что процесс 3 неправильно прочитал последний измененное время блокировки, как записано процессом 1, а не процессом 2. Я пишу блокировку nfs на разделах, смонтированных на NFS.

Кто-нибудь имеет идею или сталкивался с подобной проблемой с perl NFSLock? Смотрите приведенный ниже снимок

my $lock = new File::NFSLock {file      => $file,
                              lock_type => LOCK_EX,
                              blocking_timeout   => 50,     # 50 sec
                              stale_lock_timeout => 5 * 60};# 5 min

$DB::single = 1;
if ($lock) {
    $lock->unlock()
}

Если я блокирую в точке отладчика для процесса 1 более 5 минут, я наблюдаю это поведение

1 Ответ

1 голос
/ 26 февраля 2020

Из просмотра кода на https://metacpan.org/pod/File :: NFSLock Я вижу, что блокировка реализована только физическим файлом в системе. Я работаю почти во всех проектах с одним и тем же логикой c блокировки процесса.

При использовании блокировки процесса крайне важно не устанавливать слишком жесткий stale_lock_timeout. Или произойдет " Состояние гонки ", как это также упоминается в комментариях к коду.

Как вы упомянули, 3 процесса начинают конкурировать за одну и ту же блокировку, потому что задание занимает > 5 мин и вы установите tale_lock_timeout на 5 мин. Если у вас есть фиксатор времени, такой как crond, он будет запускать процесс каждые 5 минут. Каждый процесс примет блокировку как устаревшую , потому что 5 минут уже прошло, хотя процесс занимает более > 5 минут

Для описания возможного сценария: Некоторое задание БД занимает 4 минуты, но в перегруженной системе это может занять до 7 минут и более. Теперь, если служба crond запускает процесс каждые 5 минут В 0 минут первый процесс process1 найдет задание как новое, установит блокировку и запустит задание, которое займет до 7 минут. Теперь через 5 минут Служба crond запустит process2, который обнаружит блокировку process1, но решит, что она уже устаревшая , потому что уже 5 минут с момента блокировки создан и будет принят как устаревший . Так что process2 снимает блокировку и забирает ее для себя. Позже через 7 минут process1 уже завершил задание и, не проверяя, является ли он его блокировкой, снимает блокировку process2 и завершает работу. Теперь через 10 минут process3 запускается и не обнаруживает никаких блокировок, поскольку блокировка process2 уже была освобождена process1 и устанавливает свою собственную блокировку. На самом деле этот сценарий действительно проблематичен c, поскольку он приводит к накоплению процессов и накоплению рабочей нагрузки, а также к непредсказуемым результатам.

Предложение для устранения этой проблемы:

  1. Установите stale_lock_timeout на сумму, намного большую, чем та, что потребуется для работы (например, 10 минут или 15 минут). stale_lock_timeout, но больше, чем график выполнения.
  2. Установите график выполнения более просторным, чтобы дать каждому процессу достаточно времени для завершения sh своей задачи (каждые 10 минут или каждые 15 минут)
  3. Рассмотрите возможность объединения Задания process1, process2 и process3 в один только process_master, который запускает каждый процесс после завершения предыдущих этапов.
...