Оптимизация сайта под высокие нагрузки (php,nginx, mysql). Какие критерии доработок? Что необходимо сделать в первую очередь?

Доброго времени суток!
У нас имеется сайт с большой базой пользователей (700 тысяч). Сайт предназначен для записи на мероприятия и одна из его особенностей - БД с кучей полей у некоторых таблиц. Сайт написан на php, использует сервер nginx и СУБД MySQL
С увеличением количества пользователей, готовых участвовать в наших онлайн мероприятиях мы столкнулись с тем, что сайт зависает и жестко тупит, пока есть очередь из запросов пользователей: достаточно 2000-4000 человек, заходящих в течение 20 минут на сайт, чтобы его "положить на лопатки". Пользователи выполняют стандартный набор действий: авторизация, регистрация, запись на мероприятие. Сервер имеет следующую конфигурацию: 24 vCPU intel core ice lake, 128 Gb ОЗУ и SSD хранилище данных. БД, сервер и файлы сайта находятся на одной виртуальной машине, всё это добро размещено на яндекс облаке.

Встал вопрос в оптимизации сайта под высокие нагрузки

Что необходимо сделать в первую очередь в плане оптимизации?
Разработчики данного сайта предложили осуществить следующие работы:
1. Нагрузочные тесты и увеличение ресурсов сервера,
2. Подключение облачной сети быстрой доставки контента (CDN), для оптимизации доставки статического содержимого конечному пользователю и снижении нагрузки на целевой веб-сервер nginx.
3. Развертывание и подключение быстрого кеширующего сервиса REDIS в облачной среде для большей надежности и оптимизации.
4. Вынос MySQL в облачный сервер

Но мы сомневаемся, что этого будет достаточно... какие критерии к оптимизации сайта можно выставить, чтобы проверить выполненные работы и что ещё можно включить в данные работы, если предложения выше подходят для решения?
  • Вопрос задан
  • 2042 просмотра
Пригласить эксперта
Ответы на вопрос 9
ThunderCat
@ThunderCat Куратор тега Веб-разработка
{PHP, MySql, HTML, JS, CSS} developer
Как уже заметили коллеги - первое что нужно выяснить - что тормозит.

Спойлер: 90% что проблема в запросах к бд, так как сам по себе код в большинстве случаев банально отсылает запросы и принимает их результат, выводя его пользователю в несложных действиях. В редких случаях - запросы идут к внешним тормозящим сервисам, например к фейсбуку или другим СС. И крайне редко тормозит сам код, но тут уже опять же - 90% что это некомпетентность разраба, например, не способного построить нормальный запрос и сортирующий данные от бд в коде...

Что конкретно надо делать:
1) Взять за шкирку самого разбирающегося в коде (если таковой существует в проекте), и дать задание описать базовый стек вызовов, если это какой-то самопис, или сразу расставить код замера времени с метками в случае понятной архитектуры. Что то типа такого(класс - древний костыль, но работает, так что матом не ругаться):
Class Timer.php:
class Timer {

    static $start;
    static $end;
    static $marks = [];
    static $formats = [1=>''];

    static function init(){
        if(empty(self::$start)) self::$start = microtime(true);
    }

    static function setMark($markName = ''){
        $time = microtime(true);
        if($markName == '')$markName = $time;
        $data['name'] = $markName;
        $data['time'] = $time;
        $res['time'] = $time;
        if(count(self::$marks) > 1)$res['diff'] = $time - self::$marks[count(self::$marks)-2]['time'];
        else $res['diff'] = 0;
        $data['diff'] = $res['diff'];
        self::$marks[] = $data;
        return $res;
    }

    static function timeFormat($number,$format = ''){
        if(empty($format)) $format = 3;
        return number_format ($number,$format,'.','');
    }

    static function report(){
        self::$end = microtime(true);
        self::$marks['start'] = self::$start;
        self::$marks['end'] = self::$end;
        self::$marks['all_time'] =  self::$end - self::$start;
        if(!empty(self::$marks)) return self::$marks;
    }
}


In code:
\Timer::init()
//some code block 1
\Timer::setMark('after block 1');
//some code block 2
\Timer::setMark('after block 2');
...
//some code block n
\Timer::setMark('after block n');
//near end of code 
\Timer::setMark('end');
var_dump(\Timer::report());
exit;

2) Смотрите на блоки жрущие время, делите их до атомарных операций путем деления блоков пополам таймерами.
3) Смотрите что там происходит - оптимизируете*. И так по кругу.
4) Профит.

* Оптимизация
Запросы:
1) Смотреть план запроса (use explain, Luke!).
2) Расставить индексы которых явно не хватает
3) Смотреть не вызывается ли 50 запросов в цикле? Если да - выписать пенделя писавшему, затем переписать в 1 запрос с нормальным джоином.

Код:
Иногда запрос сложно оптимизировать, он вытаскивает много данных, хотя эти данные не часто обновляются. Такие запросы нужно кешировать, для чего используют быстрые ин-мемори хранилища типа редис или мемкеш. В крайнем случае в файлах...
Чаще всего код тормозит на регулярках, хотя "хороший" программист может придумать и более креативные способы погреть процессор.

Что нужно сделать обязательно кроме тестов и как тогда лучше спрашивать с разработчиков, если они предлагают размытые предложения? Хочется понять в какую сторону копать
Бить палкой не вариант? Тогда берите других, эти испортились. Если разработчик не знает как выявить узкие места кода - нахрена он нужен? Код написать сегодня любой чат может... Ну, на крайняк дайте им вышеприведенный вариант решения проблемы...

PS: Кстати, сервер может банально не выдерживать наплыв сетевых соединений, пните адимна, пусть глянет логи.

PPS:
достаточно 2000-4000 человек, заходящих в течение 20 минут на сайт
это равномерные 3-4 рпс, ну или пусть в пике 50 рпс, должно держать даже на несложной конфигурации... Копайте код.
Ответ написан
Комментировать
sergey-gornostaev
@sergey-gornostaev
Седой и строгий
Первым делом необходимо выполнить замеры и найти, что конкретно тормозит. Судя по предложениям разработчиков, подозреваю, что стоит ещё и их уволить.
Ответ написан
opium
@opium
Просто люблю качественно работать
Вы делаете какую то хрень без диагностики
Для начала тупо топ в линуксе что в такие моменты жрет больше всего ресурсов и уже это как то пытаться диагностировать и решать
А так вы на уровне у нас ни одного админа и программиста нет мы сделаем какую то хрень по советам интернета
Ответ написан
Комментировать
@pkokoshnikov
У вас довольно мощный сервер и его должно хватать на порядок больше нагрузки.
CDN не сильно поможет, так как нагрузка на чтение ни о чем, все и так должно работать. Nginx точно не узкое место. Поэтому я бы первым делом включил журналирование медленных запросов в mysql и посмотрел бы что там в топе. А так первый комментарий хороший, поможет найти проблему. Но в целом я бы посоветовал завести метрики и графану, и добавить метрики по операциям в коде и бд. Чтобы иметь представление на будущее. Не знаю насколько сложно это делать в php.
Ответ написан
Комментировать
Скорее всего эта проблема связана с БД. Вероятно есть SQL запросы, которые плохо оптимизированы под эту задачу. В этом случае тогда нужно оптимизировать запросы, возможно еще нужно создать индексы, возможно еще произвести тюнинг MySQL, увеличить некоторые буферы и другие настройки.

Для оптимизации нужно:

1. Нужно включить логирование медленных запросов. Много раз использовал эту методику для выявления узких запросов.
После уже можно понять какие php файлы являются проблемными, и их исправить.
Логирование медленных запросов включается так в разделе [mysqld] в файле my.cnf:
slow_query_log      = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time     = 1

Анализ лог файла делается так:
mysqldumpslow -s c -t 20 slow.log.1 > results.log

2. Также может помочь утилита mysqltuner.pl. Многократно ее использовал для определения проблемных запросов, индексов, которые нужно добавить в таблицы, и других проблем с MySQL/MariaDB.

3. Можно вручную провести анализ запросов при помощи EXPLAIN.

4. Можно сделать замеры выполнения кода, как вручную, через логирование блоков кода, так и через XDebug. И выявить долго выполняющиеся блоки, после этого оптимизировать их.

5. Кроме того нужно посмотреть процессы на сервере, которые занимают много процессорного времени и памяти, это можно сделать через atop или другие подобные утилиты. Можно на основании этого оптимизировать программный код и службы.

6. То что MySQL и сам сервер находятся на виртуальной машине это тормозит работу сервера, виртуальные ноды в любом случае работают медленнее, чем физический сервер. Рекомендую перенести это все на физический сервер с NVMe дисками, с современным процессором и ОЗУ не менее 128 Гб.

Могу помочь настроить логирование, анализ этого и выявить узкие места.
Ответ написан
Комментировать
@Alexandr_VM
Подозреваю что это банальная очередь запросов, php-fpm как-то настраивался? Nginx в данной цепочке является прокси-сервером, он ожидает ответ от php-fpm.
Ответ написан
Комментировать
@Eugene2701
Думаю необходимо в корне пересматривать структуру проекта.
На каждую сессию сервер резервирует 2 Мб.
То есть на 4000 пользователей это 8 Гб.
И из реальной жизненной ситуации - сервер на 166 Pentium' е, с 256 Мб памяти под FreeBSD и всем "стеком LAMP" обслуживал до 10 запросов в секунду, а здесь с ресурсами на несколько порядков выше 4 запроса в секунду ложат на лопатки.
Ответ написан
Комментировать
PiSaiK
@PiSaiK
IT куратор
Первое что можно сделать быстро.
Это индексы, как увидеть тормозящие запросы можно посмотреть тут https://electrictoolbox.com/show-running-queries-mysql/

Далее, оптимизация самой базы. Вот тут есть референсы
https://highload.today/mycnfexample-ram-16/
https://highload.today/index-php-2009-04-23-optima...
https://losst.ru/optimizatsiya-proizvoditelnosti-mysql
https://habr.com/ru/company/oleg-bunin/blog/328458/

И третье: это https://kafka.apache.org/. Строить балансировку для MySQL
Ответ написан
Комментировать
@darkfire13
Здесь и сейчас dieg.info
В первую очередь смотрим логи nginx. После этого в 80% случаях вам понадобится изменить
  1. limit.conf
  2. sysctl.conf
  3. пулы php-fpm
  4. и nginx.conf надеюсь тоже у вас не по умолчанию

А после этого, помолясь, смотрим логи Mysql. Если ошибок нет, включаем просмотр медленных запросов.
Часто, но скорей всего не в вашем случае, помогает установка redis. Но redis тоже настраивать нужно уметь и можно сделать просто хуже.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы