Black Friday
У нас с друзьями есть традиция — каждую последнюю пятницу ноября мы делаем стресс-тест сайту. А после этого стресс-тест складу и колл-центру. Мы все очень любим стресс-тесты, поэтому возможности их устроить мы не упускаем.
Мы с друзьями — это компания modnaKasta, и на Black Friday мы устраиваем грандиозную распродажу. 2016 год очень примечателен тем, что в историческом соревновании маркетинга и разработки произошли изменения — в этом году сайт проработал всю пятницу. Всё прошло гладко, несмотря на усилия маркетинга, который пытался привести побольше людей, и самих людей, которые устроили нам главный стресс-тест года. :)
Год назад
Черная пятница в прошлом году заключалась в том, что мы лихорадочно исправляли все то, о чем узнали в хэллоуин (предыдущую крупную распродажу), потому что нормальное нагрузочное тестирование без настоящих людей мы не сделали. :) Я не верю, конечно, что можно сделать нагрузочное тестирование и оно покажет твои проблемы так же хорошо, как это делают настоящие люди . Фейсбуки и гуглы всякие, в конце-концов, релизы делают на небольшую аудиторию, а потом уже на всех — но стремиться-то к тому, чтоб проверить стрессоустойчивость без реальных пользователей всё равно надо.
А в понедельник наконец дошло, что показывать на одной странице все товары сразу ну прям слишком больно и для базы, и для рендеринга. Мы переделали страничку акции на подгрузку товаров по 30 штук, и это позволило всю пятницу очень неплохо жить. До 8 вечера. А в 8 случилось непоправимое и сайт сделал вид, что его тут не стояло. :)
У нас есть такое понятие, как “волны”. Волна — это когда стартуют акции, и люди приходят ровно к этому моменту.
27.11.2015 акции выходили каждый час, иногда — по несколько сразу, а иногда — они были особенно интересны. :) И вот в 8 вечера это был период самых интересных акций, которые успешно распродавались после 11 ночи следующие два дня просто потому, что с 20 до 22:30 сайт не отвечал.
Сначала у него случилась проблема с кэшем главной страницы. На странице выводился список акций за сегодня, уже идущих и еще собирающихся идти. Поверх будущих акций выводился таймер с обратным отсчетом и затемнение. И очевидно, в седой древности, когда создавали главную страницу, писали код так, чтоб акция не становилась автоматически активной, когда время наступало. В результате надо было обновить страницу, чтоб получить доступ к акциям. И страница умудрилась закэшироваться так, чтоб до старта акций всегда оставалось 18 секунд. 12 минут мы искали по всем кэшам, где же проблема — в основном их чисткой, а когда нашли, оказалось, что без кэша сайт не способен выдержать такой нагрузки и скопытился.
А потом мы поставили заглушку, для того чтоб восстановиться — и люди начали качать мобильное приложение. И случилось две вещи: наше приложение начало лезть вверх в рейтингах апп стора/гугл плея, и мы узнали о том, что API для мобильных совершенно не оптимизирован. :) Ни на одну граммулечку. Ну очень, очень грустный грустный он был.
И если в 4 часа вечера мы выдерживали суммарно 18–19 тысяч пользователей онлайн, из которых 2 — мобильные приложения, то к 9 вечера было 4 тысячи человек с мобильных, и при достижении 12–13 тысяч человек онлайн умирала и база, и сервера с приложением. Кто первый, кто последний — как повезет. :)
Теперь
А в этом году Black Friday растянули на целую неделю — в результате рост (относительно прошлого года) людей онлайн в пятницу в 8 вечера не такой резкий, как мог бы быть, всего лишь 22,5 тысячи человек.
Всего. :)
В прошлом году каждый пик стоил очень дорого базе — она начинала тормозить, случались дедлоки, на которых она переставала отвечать на несколько секунд (пока таймаут не произойдет). А в этом году в самое жаркое время в постгрес прилетало 4 тысячи запросов в секунду, которые нагружали сервер процентов на 30. База не просто себя прекрасно чувствовала, она даже не почесалась.
Вот что вручную написанные запросы делают, а то ORM, ORM… В SQLAlchemy, наверное, еще можно было бы как-то предпринять оптимизацию запросов — и то её часто используют с моделями, а там ты хочешь не хочешь, вытаскивается сильно больше данных, чем нужно. А уж Django ORM
, который у нас был — это боль из болей, он даже при серьезных усилиях со стороны разработчиков не хочет нормальные запросы генерировать.
Еще один очень радующий меня факт — в прошлом сентябре мы обновили сервера БД (основной и реплику), потому что в наши дни держать базу данных на HDD это грусть. И с тех пор мы не только не покупали нового железа, более того — 18 серверов с Python, которые у нас были в прошлом году, мы заменили на 8 с Clojure. Неплохая экономия железа, а? Справедливости ради надо сказать, что есть еще несколько серверов с джангой, которые поддерживают старый API и те несколько страниц, что мы еще не перевели.
Как так
Ну, во-первых, написанные руками (ну окей, HoneySQL) запросы — это супер-верное решение. Берешь EXPLAIN
и он тебе сразу рассказывает, где ты неправ, где ты забыл индекс, и т.п. И эти знания ты идешь и сразу применяешь. Короче, философия Clojure быть поближе к данным работает и тут. :)
Конечно, не надо забывать про архитектуру. То, что приложение — одностраничное, делает переходы между страницами куда дешевле: фактически 1–2 вызова API, которые куда меньше действий делают на сервере, чем рендеринг целой странички — один только хедер требует кучи данных.
JVM еще чуточку помогает. Виртуальной машине пайтона далеко-далеко по скорости, конечно.
Clojure заставляет код писать иначе — помогает философски чуть, неизменяемые данные заставляют подумать о каком-то пайплайне обработки, а функциональность о каком-то сборе операций в одном месте, вместо стандартного “а добавлю-ка я еще запрос в базу и здесь”. И не философски — нельзя просто взять и скопировать логику, приходиться задуматься.
MiniProfiler
, кстати, я бы тоже со счетов не сбрасывал. Нельзя сказать, чтоб он сделал всю погоду, но на пару вещей обратить внимание заставил: показывает время всех запросов к серверу и информацию по запросам в БД во время этих запросов.
Riemann + InfluxDB + Grafana, или, другими словами, мониторинг/аналитика — очень помогает глянуть внимательно на происходящее и предпринять меры. Тяжело, правда, идёт выдумывание, на какие же параметры смотреть. Т.е., RPS и время запросов, разбитое по отдельным урлам приходят в голову сразу, но это регулярно показывает только симптомы. Впрочем, понемногу какие-то разумные графики и дэшборды вырисовываются. То, что у нас 4 тысячи запросов в секунду в базу в пике было, я узнал из графика, который появился за день до черной пятницы. :)
Итого
Stay tuned, мы собираемся сделать серию постов про нашу архитектуру и про всякие моменты, с которыми приходится сталкиваться. Подписывайтесь на этот блог в медиуме или на мой твиттер, я там буду обязательно писать о каждом новом посте.