Регрессия и нагрузочное тестирование: как проверить надежность до продакшена?¶
Когда говорят о надежности, неинженерная аудитория часто представляет себе реакцию: мониторы, дежурных, экстренные вызовы посреди ночи, героическое тушение пожаров. Это красивая картинка, но она в корне неверна. Настоящая надежность начинается не в момент падения системы, а задолго до него. Она закладывается тогда, когда код еще даже не попал в продакшен, на этапе разработки и тестирования. Это проактивная, а не реактивная работа.
Представьте, что вы ставите спектакль. Вы написали пьесу, выучили роли, сделали декорации. И вот наступает премьера. Зал полон. Свет гаснет, занавес открывается... и вы понимаете, что у актеров не хватает голоса, чтобы перекричать оркестр, или что декорации поставили так, что они загораживают актеров, или что монолог, который так хорошо звучал на репетиции в пустом зале, совершенно не слышен на последних рядах.
Что пошло не так? Да все, и из-за того, что вы не репетировали в условиях, приближенных к реальным.
В разработке программного обеспечения происходит то же самое. Код может быть идеальным с точки зрения функциональности. Он может проходить все тесты, быть красивым, читаемым, с комментариями. Но когда на него обрушивается настоящий, реальный пользовательский трафик, то тут начинаются сюрпризы. База данных не справляется с количеством запросов; таймауты срабатывают раньше, чем сервис успевает ответить; память заканчивается через час после релиза.
Поэтому прежде чем выпускать систему в настоящий полет, нужно устроить ей генеральную репетицию. И здесь у SRE есть два главных инструмента: нагрузочное тестирование и chaos engineering.
Нагрузочное тестирование это репетиция при полном зале. Вы генерируете искусственную нагрузку, максимально приближенную к реальной, и смотрите, как система себя ведет. Сколько запросов в секунду она может обработать, прежде чем начнет задыхаться? Как растет время ответа с увеличением нагрузки? В какой момент начнут падать первые запросы? Где узкое горлышко, которое задушит всю систему?
Хорошее нагрузочное тестирование отвечает не на вопрос «работает или не работает», оно отвечает на вопрос: «как долго это будет работать при таком-то количестве пользователей?». Это принципиально другой уровень понимания.
Иногда результаты бывают обескураживающими. Система, которая блестяще справлялась с одним пользователем на тестовом стенде, падает на десяти. Или время ответа линейно растет с нагрузкой, и вы понимаете, что через месяц, когда придет миллион пользователей, всё встанет. Лучше узнать об этом сейчас, в лабораторных условиях, чем в день запуска рекламной кампании.
Нагрузочное тестирование бывает разным. Нагрузочное в узком смысле — когда вы постепенно увеличиваете нагрузку и смотрите, до какого предела система тянет. Стресс-тестирование — когда вы сразу даете нагрузку значительно выше ожидаемой, чтобы увидеть, как система умирает и умирает ли она gracefully или падает с дампом памяти. Тестирование стабильности — когда вы держите высокую нагрузку длительное время и смотрите, не течет ли память, не перегреваются ли серверы, не накапливаются ли ошибки.
У каждого типа тестирования своя цель, но объединяет их одно: они переносят обнаружение проблем из боевых условий в контролируемую среду, когда есть шанс эти проблемы исправить заранее. Цена ошибки в лаборатории на порядки ниже, чем на проде.
Но нагрузочное тестирование проверяет только то, что вы предусмотрели. Вы создаете сценарии, которые, как вы думаете, будут в реальности. Вы моделируете типичное поведение пользователей. А реальность, как известно, богаче любых сценариев. Пользователи делают неожиданные вещи: кликают туда, куда не надо, отправляют формы по сто раз, приходят волнами, которые невозможно предсказать. А еще бывают сбои, которые накладываются на пиковую нагрузку.
Как проверить, что система выживет в таком аду? Для этого существует chaos engineering — ему посвящена отдельная глава «Chaos Engineering: разрушаем, чтобы построить». Нагрузочное тестирование и chaos engineering работают в паре: первое проверяет поведение под давлением, второе — поведение в условиях отказа. Вместе они дают полную картину.
Но сравните это с ценой реального сбоя. Один час простоя ключевого сервиса/продукта может стоить миллионы. Один испорченный релиз может убить доверие пользователей на годы. Инвестиции в проактивное тестирование окупаются многократно.
Поэтому ответ на вопрос "как проверить надежность до продакшена" звучит так: вы должны сделать продакшен максимально скучным событием. К моменту, когда код попадает к реальным пользователям, вы уже должны знать о нем всё: как он ведет себя под нагрузкой, где его пределы, при каких условиях и как он умирает, как восстанавливается, что происходит, когда отключаются зависимости.
Идеальный релиз это не тот, после которого ничего не сломалось. Идеальный релиз это тот, после которого не случилось ничего неожиданного. Потому что все возможные сценарии вы уже отрепетировали заранее. При полном зале. И с выключенным светом.