Все счастливые семьи похожи друг на друга, каждая несчастливая семья несчастлива по-своему.
«Анна Каренина» Л.Толстой.
Проведя сотни аудитов проектов в IT и расследуя десятки инцидентов, перефразируя классика, можно сказать: «Все проекты счастливы по-своему, а несчастны одинаково». Успех проекта — это уникальное сочетание параметров и людей. А несчастья приносят одни и те же проблемы или совокупность проблем, небольших упущений, которые в итоге приводят к пике. Об одном таком случае сегодня расскажу вам я — эксперт Службы качества SimbirSoft Юлия.
Обычно мало кто реагирует на небольшие отступления от стандартов ведения проектов, соблюдения процессов: «Ничего же страшного не произойдет». Это чревато большими проблемами, когда специалисты не понимают риски, не осознают, зачем то или иное правило, договоренность, и что может произойти в итоге, если этого не делать. Потому что по сути процессы и правила гибкие (в лучших традициях agile :)) Но мелочи и, казалось бы, незначительные вещи на самом деле могут оказать серьезное влияние на весь проект. И привести к катастрофе…
У нас в SimbirSoft есть процесс фиксации и анализа инцидентов. Сначала, конечно, нужно как можно скорее устранить последствия. Но основная цель — понять, почему инцидент произошел и что нужно сделать, чтобы он не повторился в будущем. Как в авиации проводят расследование авиакатастроф, так и у нас в IT — расследование инцидентов, которым занимается, в том числе, служба качества компании (иногда мы в шутку называем себя «следственный комитет»). Но вы не подумайте, допросов с пытками не устраиваем :) Мы в компании развиваем культуру качества, когда можно открыто говорить об ошибках, делать выводы и учиться на них.
Но вернемся к истории об одном инциденте на мобильном проекте, который произошел в конце декабря 2019 года, а после разберем, какие ошибки мы совершили и как их можно было избежать.
26.12.2019
Последняя в году рабочая неделя. Николай, backend-разработчик одного из проектов, давно планировал новогоднюю поездку в Петербург. Остался последний рывок — релиз новых фич.
QA-специалист Гуля написала в чат, что регресс завершен, мелкие баги, которые были, уже поправлены, и пора выкладывать приложение в AppStore и Google Play.
Мобильное приложение для online-тренировок очень нравилось команде: и тренировки, и подход его владельца. Наша компания разрабатывала приложение «под ключ»: от ТЗ, дизайна, архитектуры до иконки в телефоне тех, кто мечтает сделать фигуру мечты. По классике оно состояло из двух частей — серверной и мобильной клиентской (Android и iOS). В команде разработки были аналитик, дизайнер, backend, Android- и iOS-разработчики, QA-специалист и PM. Дрим-тим увлеченных работой и продуктом людей. Приложение уже было в сторах. Первый релиз состоялся 20 октября. И только за первый месяц работы уже было более 50 000 скачиваний, более 4100 оценок и отзывов.
К новому году команда запланировала релиз новых фич и публикацию нового курса тренировок, рекламная кампания которого уже была в самом разгаре. Первые скачавшие получали доступ к тренировкам по сниженной цене и дополнительные видео по мотивации и питанию. Выход продукта ожидала большая аудитория пользователей.
У нас все было готово. Ждали только окончания проверок от AppStore и Google Play.
30.12.2019
PM проекта Анна сообщила заказчику, что приложение успешно прошло проверки и можно проводить релиз.
Клиент решил провести его 31 декабря. Новый год — новая жизнь! А мы были молоды и отчаянны :)
31.12.2019
Новая версия стала доступна для пользователей. Пошли скачивания и обновления, все было в штатном режиме. Команда уже делилась планами на новогодние праздники, приводила в порядок таск-трекер и документацию проекта, причесывала бэклог. И спокойно ушла готовить салатики.
19:54 (+3 GMT) Первый алерт о высокой нагрузке на базу данных (БД). Потом еще и еще.
20:35 (+3 GMT) DevOps Максим написал в чат команде о том, что сервер «себя плохо чувствует», и он уже смотрит логи, пытаясь разобраться в произошедшем.
Прочитав сообщения, QA-специалист проекта Гуля сразу зашла в приложение и увидела, что некоторые тренировки не открывались или информация прогружалась длительное время.
PM Анна сидела за новогодним столом, а телефон вибрировал сообщениями: помимо поздравлений там были плохие новости от команды, что приложение не работает, а клиент написал, что возникает ошибка при попытке опубликовать новый курс тренировок.
«Вечер перестает быть томным» :) Новогодний вечер! У клиента 11:00 31 декабря. Разница с командой 8 часов. И срыв выхода нового курса тренировок.
По существующим процессам аккаунт-менеджер Наталья оповестила руководителей компании об инциденте. Несмотря на позднее время и праздник, необходимо срочно спасать релиз.
Backend-разработчик Николай в это время гулял по Санкт-Петербургу — на 30 и 31 декабря он оформил отгул. Но читать рабочие чаты в любое время дня и ночи и даже в отпуске — это зависимость большинства айтишников. Связался с Максом (Devops), и по его описанию возникли подозрения сразу на несколько проблем. Николай написал PM и своему руководителю, указал, что необходимо донастроить кэширование на стороне СУБД.
В команде приняли решение срочно подключить другого backend-разработчика Сергея (представляете его лицо? :)), поскольку Николай не может внести правки. Также решили увеличить производительность сервера.
21:53 (+3 GMT) На экране приложения появилось сообщение «Ошибка приложения». Бэк полностью «умер».
22:46 (+3 GMT) Кэширование уже на проде, «железные» мощности тоже уже добавили. Приложение «завелось». Но стало понятно, что это временная передышка и лишь возможность выиграть время на поиск и исправление проблемы. Кэширование и увеличение производительности сглаживали ситуацию, но не решали ее.
00:00 (+3 GMT) С Новым годом!
Да-да, каждый член команды праздновал у компа или телефона, чтобы в любой момент подключиться при необходимости!
1.01.2020
Сергей нашел основную проблему приложения и уже вносил правки, попутно консультируясь с Николаем.
Исправленный код на тесте. QA-специалист оперативно подключилась и проверила, нашла пару замечаний. Снова правки и снова тест. Потом мини-регресс (да-да, именно мини, пошире смоука, но времени на полноценный нет).
02.01.2020
Все исправления на проде. Можно было выдохнуть, но все же нужно было еще понаблюдать за нагрузкой на СУБД.
03.01.2020
Проблемы с кэшем Redis. Приложение было недоступно в ночное время у клиента, проблему удалось решить сбросом кэша.
04.01.2020
18:40 (+3 GMT) Приложение упало на 3 минуты, произошел сброс кэша пользователей, сделали новый вариант сброса и работы кэша.
05.01.2020
Мониторинг без аномалий. Полет нормальный. Выдохнули. Поставлена задача реализовать API 2.0.
9.01.2020
В первый рабочий день после новогодних праздников PM Анна сделала новую запись в трекере инцидентов о проблемах в работе приложения после выпуска в продакшен.
Служба качества собрала рабочую группу по расследованию инцидента: необходимо было провести технический анализ допущенных ошибок, установить причины их появления, выработать алгоритм действий для недопущения подобной ситуации в будущем.
25.02.2020
Релиз обновленного приложения. Были доработаны и бэк, и мобильное приложение (Android, iOS). Единый запрос на всю структуру тренировок был разбит на несколько, в соответствии с уровнями вложенности. Прогресс по тренировкам тоже «ушел» в отдельные роуты.
Команда провела нагрузочное тестирование с использованием примеров новых, более сложных по структуре данных тренировок.
Последующие новые фичи — бесплатные тренировки, анонсы, мультиязычность — уже проходили гладко, без эксцессов и сложностей.
Допущенные ошибки, и как их можно было избежать
1. Неправильное построение запросов
PM предположила, что заниматься спортом по тренировкам из приложения пользователи могут в местах, где не очень хорошая связь (привет тренажеркам в подвалах от детей 90-х :)). Backend-разработчик согласился на предложение PM сделать один большой запрос на загрузку всей информации о всех тренировках, не предполагая, насколько после возрастут объемы загружаемой информации. Это упростило работу мобильным разработчикам, но нарушило принцип REST — вместо множества GET-запросов для получения разных уровней вложенности тренировок, был один запрос, загружающий сразу все уровни.
Кроме структуры курсов, ответ от этого запроса содержал и прогресс пользователя по тренировкам, то есть ещё дополнительные запросы к базе. К тому же само получение структуры тренировок добавило проблему N+1 из-за использования ленивых ассоциаций.
Этого не было видно на тестовых данных. Однако на проде проблема расцвела во всей красе.
Как надо было сделать:
При наличии иерархических моделей данных в ответе на запрос получения данных любой модели не должна содержаться информация о дочерних ресурсах. Каждой модели данных должен соответствовать свой путь. Backend-разработчик должен был отстоять свое мнение, привести аргументы. А еще лучше — совместно с командой сформировать плюсы и минусы двух решений, возможные риски. И уже на основе этой информации принимать решение.
2. Тестовые данные не соответствовали реальным
Вложенная структура данных реальных тренировок оказалась в несколько раз сложнее, чем мы представляли. Один большой запрос с такой сложной многоуровневой структурой оказался фатальным для производительности приложения.
Примеры тренировок от заказчика для тестирования данных оказались намного проще, чем реальные тренировки, которые были потом введены в приложении.
Как надо было сделать:
Всегда запрашивать примеры тестовых данных. Чем больше, тем лучше. Но не единоразово. Если есть планы по новым фичам, то важно запрашивать их повторно. В нашем случае необходимо было запросить пример нового курса тренировок.
Определить ограничения по типу, объему, структуре данных. Согласовать с командой и клиентом.
По возможности провести тестирование как на простых, так и на усложненных примерах. Понимаю, что чаще всего время на тестирование ограничено, поэтому здесь действуем без фанатизма.
Задавать наводящие вопросы: «А какие еще в перспективе могут быть изменения в приложении?», «Планы по развитию?», «Как это отразится на данных?».
3. Не было реализовано закрытие соединения к Redis
В явном виде не было закрытия соединения, само закрывалось, но долго висело. Реализация функциональностей базировалась на документации Symphony и по сути реализовывалась «в лоб», без углубления в особенности работы фреймворка и доктрины.
В первой итерации исправления проблем приложения увеличили производительность сервера и расширили кэширование — вся структура тренировок заносилась в кэш. Это помогало, но не в полной мере. Так как при любых изменениях структуры тренировок в админке весь кэш группы тренировок сбрасывался, пока он формировался заново, часть пользователей могли получать ошибки. Поэтому мы добавили прогрев кэша. После этого приложение стало работать стабильнее, а мы продолжили последовательную работу по исправлению.
Как надо было сделать:
Этот пункт возник из-за первых двух и экстренных правок. Правильно выстроить работу с кэшем и подсветить первые две проблемы позволило бы своевременное проведение нагрузочных тестов.
Что в итоге мы изменили у себя в процессах
Ввели архитектурный надзор в каждом производственном направлении разработки. Проводим ревью разрабатываемой архитектуры на контрольных точках проекта, которые определяют PM.
При тестировании фокусируемся на релевантных тестовых данных. Актуализируем примеры при разработке новых фич.
На каждом проекте обязательно анализируем необходимость проведения нагрузочных испытаний. Разработали чек-лист для выявления требований по производительности, шаблон требований к производительности и нагрузке.
Для обеспечения требуемых параметров производительности продукта проводим минимальные нагрузочные испытания, даже если клиент считает, что в них нет необходимости.
Ввели мораторий на релизы в предпраздничные дни и по пятницам.
Что могу сказать в заключении. Когда я села писать историю об этом кейсе, у меня даже мысль возникла: «А как мы это упустили? У нас же есть контроль на уровне архитектуры и сбора требований». А потом поняла — да это же как раз после этого инцидента ввели :)))
Разработка без ошибок — это в идеальном мире. Самое главное — делать выводы, учиться на ошибках и непрерывно улучшать процессы создания программных продуктов. Всем добра!
Спасибо за внимание!
Больше полезных материалов для разработчиков и управленцев в IT мы также публикуем в наших соцсетях – ВК и Telegram.