php-fpm генерирует большую нагрузку при сбросе opcache, что делает сервер не отвечающим

В последние недели мы столкнулись с негативным явлением при развертывании кода: сервер иногда зависает на несколько минут.

Вот пример нагрузки на сервер, когда это произошло:

Единственный связанный журнал, который я могу найти, от /var/log/php7.2-fpm.log и иногда (но не всегда) я вижу записи, подобные этой (примечание: это из события, отличного от изображения, показанного выше, тем не менее, происходит то же самое):

[22-Mar-2019 15:33:50] WARNING: [pool api] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 0 idle, and 231 total children
[22-Mar-2019 15:33:52] WARNING: [pool api] server reached pm.max_children setting (250), consider raising it
[22-Mar-2019 15:34:05] WARNING: [pool app] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 8 children, there are 47 idle, and 104 total children

Случилось так, что мы сделали развертывание на этом сервере:

  • git status --porcelain проверить на наличие модификаций
  • git pull origin master обновить файлы
  • сброс opcache, то есть мы вызываем конечную точку, которая выполняет opcache_reset()
  • очистка файлов локального кэша

После некоторых экспериментов я мог бы уменьшить проблему нагрузок до следующего: opcache_reset()

Когда я выполняю этот вызов (независимо от каких-либо предыдущих или более поздних этапов развертывания, это происходит также изолированно, когда я просто вызываю эту конечную точку), существует вероятность внезапного скачка загрузки системы.

Если это происходит, и нагрузка "слишком высока" (я бы сказал, из опыта> 200 или около того), система перестает отвечать на запросы в течение секунд или минут, в зависимости от того, как долго все это успокаивается.

Технические характеристики:

  • ВМ работает на VMWare (не мы сами, у нас есть партнер)
  • 4 виртуальных ЦП
  • 8 ГБ ОЗУ
  • Пространство подкачки 8GB
  • Ubuntu 18.04 TS
  • nginx 1.14.0 (по умолчанию в Ubuntu)
  • PHP 7.2 (через https://launchpad.net/~ondrej/+archive/ubuntu/php)

Конфигурация PHP-FPM:

  • Мы используем 6 пулов с разными виртуальными хостами
  • start_servers непосредственно составляет до 320 php-fpm процессов (также подтверждено с помощью ps auxw|grep -i fpm|grep -v grep |wc -l)
  • общее количество max_children из всех бассейнов будет около 870

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

С помощью htop, система обычно выглядит так:

И, как правило, нагрузка низкая, если у нас нет этого всплеска, который связан со сбросом opcache (о котором я недавно узнал):

Я понимаю, что сброс кеша, и теперь все процессы должны его заново заполнять, потребляет процессор.

Но что я не понимаю

  • это только начало происходить недавно, например, может быть, через 1-2 месяца, но только в последние две недели безразличие было заметно
  • так бывает не всегда, иногда при сбросе кеша ничего не происходит

Вот вывод opcache_get_status(false) прямо перед развертыванием:

{
  "opcache_enabled": true,
  "cache_full": false,
  "restart_pending": false,
  "restart_in_progress": false,
  "memory_usage": {
    "used_memory": 67353640,
    "free_memory": 66864088,
    "wasted_memory": 0,
    "current_wasted_percentage": 0
  },
  "interned_strings_usage": {
    "buffer_size": 8388608,
    "used_memory": 5215176,
    "free_memory": 3173432,
    "number_of_strings": 89109
  },
  "opcache_statistics": {
    "num_cached_scripts": 2873,
    "num_cached_keys": 5063,
    "max_cached_keys": 7963,
    "hits": 633581523,
    "start_time": 1553172771,
    "last_restart_time": 1553248200,
    "oom_restarts": 0,
    "hash_restarts": 0,
    "manual_restarts": 6,
    "misses": 9512,
    "blacklist_misses": 0,
    "blacklist_miss_ratio": 0,
    "opcache_hit_rate": 99.9984987161316
  }
}

и вот потом:

{
  "opcache_enabled": true,
  "cache_full": false,
  "restart_pending": false,
  "restart_in_progress": false,
  "memory_usage": {
    "used_memory": 57745856,
    "free_memory": 76471872,
    "wasted_memory": 0,
    "current_wasted_percentage": 0
  },
  "interned_strings_usage": {
    "buffer_size": 8388608,
    "used_memory": 4337168,
    "free_memory": 4051440,
    "number_of_strings": 75163
  },
  "opcache_statistics": {
    "num_cached_scripts": 2244,
    "num_cached_keys": 3925,
    "max_cached_keys": 7963,
    "hits": 5893926,
    "start_time": 1553172771,
    "last_restart_time": 1553265235,
    "oom_restarts": 0,
    "hash_restarts": 0,
    "manual_restarts": 7,
    "misses": 4962,
    "blacklist_misses": 0,
    "blacklist_miss_ratio": 0,
    "opcache_hit_rate": 99.91588245106536
  }
}

Другие вещи, которые я наблюдал:

  • php-fpm довольно скоро перестает отвечать
  • nginx все еще работает, если нагрузка не становится ДЕЙСТВИТЕЛЬНО высокой; Я подтвердил это, потому что когда php-fpm в основном недоступен, nginx доставляет сконфигурированную страницу 500

Что на самом деле вызывает эти скачки нагрузки? Как я могу избежать их?

Обновить после принятия ответа:

В основном просто не звонит opcache_reset и возвращение большинства моих настроек настройки opcache к значениям по умолчанию (т.е. не навязывая их) исправило это.

Этот шаг был частью моего развертывания в течение буквально лет. Я попытался выяснить первоначальную причину и, насколько я мог видеть, это было связано с проблемами развертывания, когда классы ссылались на новый код, который еще не был загружен / обновлен.

Оглядываясь назад, я даже не уверен, что это была настоящая проблема, но мы здесь.

1 ответ

Решение

По умолчанию PHP проверяет временную метку файла, чтобы сделать недействительной запись opcache. Это можно отключить, и это единственный сценарий, в котором я могу представить opcache_reset() будет использоваться. Конечно, это также вызывает проблему, с которой вы столкнулись.

Я рекомендую вернуться к значениям по умолчанию:

opcache.validate_timestamps = 1
opcache.revalidate_freq = 2
opcache.revalidate_path = 0
Другие вопросы по тегам