Вопрос или проблема
Я управляю платформой управления школой на базе PHP 8.2 и Symfony 7, размещенной на VPS с 16 ГБ ОЗУ от Hostinger, работающей на Ubuntu и Nginx. Мое приложение — это традиционный сайт с серверной отрисовкой без динамического фронтенд-фреймворка.
Вот ситуация:
Когда пользователь инициирует действие, которое обрабатывает большой объем данных в базе данных, например, создавая табели успеваемости для целого класса из 60 учеников, или генерируя статистику класса, страница отображает ошибку “Невозможно подключиться к сайту” примерно через 30 секунд.
Наблюдения:
- Когда массовые данные обрабатываются в очереди, например, с использованием Symfony Messenger, процесс проходит безупречно, даже для более 1000.
- Если я сегментирую обработку данных, например, генерируя табели по 10 учеников за раз, процесс завершается быстро и без ошибок.
- В моей локальной среде разработки (Windows 10 с Apache, 8 ГБ ОЗУ) те же задачи выполняются успешно, независимо от размера данных (например, создание табелей или статистики для целого класса из 60 или более чем 120 учеников). Даже если процесс занимает от 1 до 10 минут или больше, он в конечном итоге генерирует ожидаемые результаты.
Я пытался отладить, когда возникала ошибка
-
Отладка с помощью команды **free -h** при генерации табелей:
описание изображения здесь -
Отладка с помощью команды htop при генерации табелей:
описание изображения здесь
Вот журналы
- sudo cat /var/log/nginx/error.log
описание изображения здесь - sudo grep “500” /var/log/nginx/access.log
описание изображения здесь
Что я пробовал
- Увеличение лимита php в php.ini из /etc/php/8.2/fpm/php.ini
- memory_limit=-1
- maximum_time_execution = 3600
- post_max_size = 100M
- upload_max_filesize = 100M
- Обновление конфигурации nginx из /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 1024;
# multi_accept on;
}
http {
# Глобальные таймауты
proxy_read_timeout 300s; # Время ожидания для прокси
fastcgi_read_timeout 300s; # Время ожидания для FastCGI
client_max_body_size 100M;
client_body_timeout 300s;
client_header_timeout 300s;
keepalive_timeout 300s;
send_timeout 300s;
....
} ...
- Вот моя конфигурация mysql
#
# Файл конфигурации сервера базы данных MySQL.
#
# Можно использовать все длинные опции, которые поддерживает программа.
# Запустите программу с --help, чтобы получить список доступных опций, и с
# --print-defaults, чтобы увидеть, какие из них она реально понимает и использует.
#
# Для объяснений см. http://dev.mysql.com/doc/mysql/en/server-system-variables.html
# Здесь представлены записи для некоторых конкретных программ
# Следующие значения предполагают, что у вас как минимум 32M ОЗУ
[mysqld]
#
# * Основные настройки
#
user = mysql
# pid-file = /var/run/mysqld/mysqld.pid
# socket = /var/run/mysqld/mysqld.sock
# port = 3306
# datadir = /var/lib/mysql
# Если MySQL работает в качестве репликационного слейва, это следует
# изменить. Смотрите https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_tmpdir
# tmpdir = /tmp
#
# Вместо отключения сетевых функций, по умолчанию используется прослушивание только на
# localhost, что более совместимо и не менее безопасно.
bind-address = 127.0.0.1
mysqlx-bind-address = 127.0.0.1
#
# * Тонкая настройка
#
#
innodb_buffer_pool_size = 6G
#innodb_log_file_size = 512M
innodb_redo_log_capacity = 1G
innodb_flush_log_at_trx_commit = 2
innodb_io_capacity = 1000
# Настройка памяти и производительности
key_buffer_size = 64M
max_allowed_packet = 128M
thread_stack = 256K
thread_cache_size = 8
# Кэш таблиц
table_open_cache = 2000
# Соединения
max_connections = 500
#wait_timeout = 3600
#innodb_lock_wait_timeout = 3600
# Временные таблицы
tmp_table_size = 64M
max_heap_table_size = 64M
# Временные таблицы
tmp_table_size = 64M
max_heap_table_size = 64M
# Опции восстановления MyISAM
myisam-recover-options = BACKUP
#
# * Логирование и репликация
#
# Оба местоположения поворачиваются кроновой задачей.
#
# Логирование всех запросов
# Учтите, что этот тип лога может снижать производительность.
# general_log_file = /var/log/mysql/query.log
# general_log = 1
# Файл журнала ошибок — должен содержать очень мало записей.
log_error = /var/log/mysql/error.log
# Здесь можно увидеть запросы с особенно долгим временем выполнения
# slow_query_log = 1
# slow_query_log_file = /var/log/mysql/mysql-slow.log
# long_query_time = 2
# log-queries-not-using-indexes
# Следующие параметры могут использоваться как легкие для воспроизведения резервные копии или для репликации.
# примечание: если вы настраиваете репликационный слейв, смотрите README.Debian для
# других настроек, которые могут потребоваться изменить.
# server-id = 1
# binlog_expire_logs_seconds = 2592000
max_binlog_size = 100M
# binlog_do_db = include_database_name
# binlog_ignore_db = include_database_name
- Я также пробовал это для PHP-FPM Wokers в /etc/php/8.2/fpm/pool.d/www.conf
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
Резюме проблемы:
- У меня есть локальная среда, отличная от производственной.
- Моя локальная среда — это Windows 10 + Apache + 8 ГБ ОЗУ, а моя производственная среда — Ubuntu 22 + Nginx + 16 ГБ ОЗУ.
- Моя локальная среда, менее мощная, чем производственная (локальная: 8 ГБ ОЗУ, прод: 16 ГБ ОЗУ) может сгенерировать 60 или 120 и более табелей, даже если это займет время, и если возникнет таймаут, он отобразится как явное сообщение о таймауте, а не “Невозможно подключиться к сайту” в браузере.
- Моя производственная машина с 16 ГБ ОЗУ и настройками на Ubuntu показывает в браузере “Невозможно подключиться к сайту” после примерно 30 секунд, когда я пытаюсь выполнить ту же задачу, которая работает на моей локальной машине, которая менее мощная.
- Я не знаю, является ли проблема таймаутом nginx или чем-то другим, потому что я попытался увеличить таймаут nginx, но проблема осталась той же.
- На сервере, где возникает проблема, система очередей работает корректно, но обработка больших объемов данных в базе данных с повторной загрузкой страниц не работает должным образом.
Любая помощь или предложение помогут. Заранее спасибо.
Ответ или решение
Проблема, с которой вы столкнулись, связана с ошибкой "Этот сайт недоступен", возникающей при загрузке страниц после обработки большого объема данных в базе данных на вашем сервере с помощью Nginx. Давайте разберем возможные причины и способы их решения.
Теория:
Ошибка "Этот сайт недоступен" обычно возникает, когда сервер не может обработать запрос в установленный лимит времени, и соединение разрывается. В вашем случае время до возникновения ошибки составляет около 30 секунд. Это может быть связано с настройками timeout, установленными на вашем сервере.
Ваш локальный сервер на Windows под Apache не имеет такой проблемы, что говорит о различиях в окружающей среде и конфигурациях между вашим локальным и продакшн-серверами. Основные различия включают различия в обработке запросов между Nginx и Apache, а также в стандартных настройках этих серверов.
Пример:
На вашем продакшн-сервере используются настройки Nginx, которые могут иметь наследственные короткие таймауты для состояния соединения, такие как proxy_read_timeout
, fastcgi_read_timeout
, и другие. Несмотря на то, что вы уже повысили значения для таймаутов в конфигурации Nginx, проблема осталась. Это может указывать на нерассмотренные аспекты, такие как сетевые настройки или настройки на уровне браузера.
Кроме того, использование Symfony Messenger и успешное выполнение заданий в очереди подтверждает, что проблема именно в обработке запросов через HTTP, а не в способности сервера справляться с обработкой данных.
Применение:
-
Проверьте таймауты на уровне браузера: В некоторых браузерах стандартный таймаут для ожидания ответа от сервера может быть установлен в 30 секунд. Попробуйте использовать другие браузеры или изменить настройки на этих уровнях для тестирования.
-
Дополнительная оптимизация PHP и Nginx:
- Убедитесь, что вы увеличили
request_terminate_timeout
в конфигурации PHP-FPM, чтобы избежать преждевременного завершения обработки скриптов. - Перепроверьте все уровни таймаута в конфигурации Nginx, включая
proxy_connect_timeout
,proxy_send_timeout
,proxy_read_timeout
, чтобы убедиться, что они соответствуют увеличенной длительности выполнения скриптов.
- Убедитесь, что вы увеличили
-
Используйте асинхронную обработку или генерацию страниц: Разделение обработки данных на меньшие части или улучшение асинхронных операций, где это возможно, может значительно снизить время ожидания для пользователя.
-
Мониторинг и логирование: Усильте логирование на сервере, чтобы более четко отслеживать, как отклоняются соединения, и проявляются ли ошибки таймаута или переполнения буфера.
Резюмируя, вы можете воздействовать на улучшение производительности и стабильности вашего продакшн-сервера с помощью глубокого анализа и точных настроек как серверной среды, так и конфигурации приложения, избегая тем самым ошибок, связанных с таймаутами и разрывами соединений.