Один день под нагрузкой на irk.ru
Только что мне написал главный редактор irk.ru о том, что на сайте находится 4000 человек. Я с остороженностью отношусь к цифрам больше 2000 - это уже серьезная нагрузка на сервер.
Нужно подключаться и следить за работой системы в реальном времени.
Что же первым делом я делаю, когда чувствую, что сайт может лечь?
Этим я и хочу поделиться с вами в этой заметке. Первым делом я захожу на сервер, который принимает входящие соединения от пользователей. Там крутится nginx
, который без устали обрабатывает запросы и который является первым рубежом на пути трафика.
Ngxtop
Я запускаю ngxtop
- эта программа в реальном времени показывает статистику из аксесс-лога nginx
.
Тут сразу же видно, на какие адреса идет больше всего запросов и какие ответы видят пользователи по этим адресам. В идеале ошибок 4xx
и 5xx
быть не должно.
Видно, что трафик идет на страницы:
- https://www.irk.ru/news/20200410/prolong/ - новость
- https://www.irk.ru/ - главная
- https://www.irk.ru/news/articles/20200410/daughter/ - статья
У нас бекенд настроен так, что в случае экзепшна показывает пользователю ошибку 404
. Поэтому ошибки 4xx
на скриншоте - на самом деле какие-то сбои в процессе работы приложения под нагрузкой.
Когда система достигает своих пределов и что-то отваливается, ошибки 500 начинают нарастать лавинообразно, с бешеной скоростью, и это та ситуация, в которую я хотел бы попасть меньше всего.
Кстати, ngxtop
показывает только данные из лога. Поэтому если у вас для какого-то location
прописан access_log off
- то статистику вы не увидите. Не отключайте логи ради оптимизации.
Дальше.
Смотрим error log
sudo tail -f /var/log/nginx/error-irk.log
Как правило, под нагрузкой, если что-то не так, в этот лог будет с огромной скоростью сыпаться ошибки. Этот водопад оказывает большое психологическое давление, нужно выдерживать.
Еще одна интересная особенность этого лога - там может быть что угодно. Потому что обычно рвется там, где ты совсем не ждешь.
В моем логе я сегодня увидел гору вот таких ошибок:
2020/04/10 13:07:55 [error] 14362#14362: *264689442 upstream timed out (110: Connection timed out) while connecting to upstream, client: 176.209.67.22, server: ww
w.irk.ru, request: "POST /hydra/material/scroll_depth/ HTTP/1.1", upstream: "http://10.0.0.2:8086/hydra/material/scroll_depth/", host: "www.irk.ru", referrer: "ht
tps://www.irk.ru/news/articles/20200410/daughter/?utm_referrer=https%3A%2F%2Fzen.yandex.com"
Видно, что один из внутренних сервисов, который логирует глубину просмотра страницы, не справляется с нагрузкой. Позже я увидел, что на бекенд шло 220 запросов в секунду. Очевидно, что один воркер торнадо не успевал их все обработать, поскольку на каждый он тратил около 5 мс (что невероятно быстро). Надо будет добавить воркеров.
Так же видно, что наша статья попала в Яндекс.Дзен. Это очень здорово.
Я решил временно отключить этот микросервис. Потому что соединения с ним потребляют ресурсы сервера - сокеты. А если их перестанет хватать на обработку соединений с клиентами, то пойдут ошибки 500, а этого надо избежать.
Перенастроим nginx
:
location ~* ^/hydra/(.+) {
return 200;
}
И заставим его перечитать конфиг: sudo nginx -s reload
Посмотрим на бекенд
В моей схеме подключения, сервер nginx
передает запросы на uwsgi
-воркеры на бекенде. Как себя чуствует бекенд?
Зайдем и выполним sudo htop
:
Ох.
24-ядерный сервер загружен почти почти до предела. Еще чуть-чуть и он перестанет успевать обрабатывать запросы.
Единественная быстрая мера, которую я знаю - это включить кеширование. Если nginx
будет хотя бы часть запросов отдавать из кеша, не загружая бекенд, это сильно поможет нам выдержать нагрузку.
Nginx cache
К счастью, буквально вчера я изучил вопрос кеша и внес заготовки в конфиг. Потому что вчера тоже был тот еще денек.
Пора опробовать мои наработки в деле.
Я сделал отдельный файл /etc/nginx/conf.d/irk.ru.ext.conf
вот такого содержимого:
uwsgi_cache irk;
# ключ зависит от куки irk
uwsgi_cache_key "$request_method|$scheme|$proxy_host|$uri|$args|$cookie_irk";
uwsgi_cache_valid 200 10s;
uwsgi_ignore_headers "Set-Cookie" "Vary" "Cache-Control" "Expires";
uwsgi_hide_header "Set-Cookie";
add_header X-Cache-Status $upstream_cache_status;
И подключил его на самые загруженные страницы:
# статья попала в дзен
location /news/articles/20200410/daughter/ {
include conf.d/irk.ru.ext.cache;
uwsgi_cache_valid 200 60s;
include uwsgi_params;
uwsgi_pass backend;
}
# кеш главной страницы
location = / {
include conf.d/irk.ru.ext.cache;
uwsgi_cache_valid 200 60s;
include uwsgi_params;
uwsgi_pass backend;
}
# кеш всех новостей сегодня
location ~ ^/news/20200410/([a-z0-9]+)/ {
include conf.d/irk.ru.ext.cache;
uwsgi_cache_valid 200 60s;
include uwsgi_params;
uwsgi_pass backend;
}
Нагрузка на бекенд тут же упала:
Может показать незначительным, но для сервера значение в 2000 rpm - пороговое. По опыту помню, что за ним начинаются нехорошие вещи. Нужно держаться от него подальше.
Посмотрим на ngxtop
спустя полтора часа работы:
Как видите, закешированные страницы не выдали ни одной ошибки 400 и 500. В то время как некешированная страница /news/
выдала 104 ошибки на 8487 запросов - 1.2%.
Bonus
Наш сайт не рассчитан на кеширование в nginx
. Например, в заголовке у нас для авторизованных пользователей выводится аватар:
Если такая страница попадет в кеш, то каждый посетитель увидит мой аватар в шапке. Как же быть?
Если вы внимательно посмотрите конфиг выше, то обратите внимание, что у нас ключ кеширования зависит от куки $cookie_irk
.
Каждый авторизованный пользователь имеет свой уникальный ключ сессии в куке с названиемirk
. И для каждого пользователя мы кешируем страницу на 60 секунд. Если я зайду сейчас и через 10 секунд, то первый раз страница откроется с бекенда, а второй раз - из кеша.
Но в чем же смысл? Разве есть прирост производительности в такой схеме?
Есть!
Дело в том, что из дзена приходит массовый наплыв неавторизованных пользователей. А для них у нас сессия не создается. И кука не ставится. Поэтому хоть тысяча, хоть две - все они увидят одну страницу из быстрого кеша за 20 мс
А мне пора заканчивать.
Final
Если хотите послушать еще мои истории, то оставьте свой емейл в форме под этим постом. Правда, единственное, что стоит сделать на этом сайте - подписаться на рассылку. Со мной вы не останетесь неподготовленными ко встрече с наплывом людей из дзена! А без почтовых подписчиков я лучше буду писать заметки в своей голове а вы не сможете их получить и ничему научиться.