Как за ограниченное время из готовых компонентов создать и запустить по-настоящему нагруженный проект? Рассмотрим пример метрик, архитектуры, технических ограничений и подходов к проектированию систем на примере проекта «Экологический диктант».

Помогут нам в этом, два главных человека из компании Старботс.рф - Станислав Жуковский, руководитель проекта, и Василий Шалимов, архитектор и разработчик фич в части бэкенда. Они расскажут, как собрали сервис онлайн-тестирования за 2 месяца, вместо 8 плановых, а также про человеческий фактор, с которым они столкнулись во время работы.

Что такое Экодиктант?

Многие сейчас говорят про бережное отношение к экологии, электронный движ и прочее. Международный проект Экодиктант нацелен на то, чтобы проверить знания об экологии и природопользовании не только у школьников и студентов, но также у взрослого населения. Вот немного цифр Экодиктанта 2021:

  • Срок запуска 2 месяца

  • 3 миллиона авторизованных пользователей из 35 стран

  • 1 миллион пройденных тестов за 5 дней

  • 1000 корпоративных клиентов, среди которых Газпром, Норникель, Росатом с подразделениями и МЧС и сотрудники других компаний.

Но это только то, что касается онлайн пользователей. Был ещё большой блок, связанный с офлайн проведением мероприятия: распечатки анкет, организация волонтеров для помощи в подсчете результатов и прочие орг.моменты. ТЗ проекта составлялось более полугода и содержало более 120 страниц. Схема включала более 100 микросервисов со слабой связанностью, s3 хранилища, шардирование базы на основе регионального принципа, и ещё много чего.

В итоге на выполнение проекта было оставлено всего 2 месяца. Команда Старботс.РФ высказала опасения заказчику, что за такое время не успеют сделать проект на основе микросервисов и обеспечить стабильную работу при таком масштабе пользователей. К тому же нужно было ещё сделать публичную часть сайта со страницей в Википедии, хотя на тот момент не был утверждён даже дизайн.

По итогу разработчики предложили исполнительной дирекции «Экодиктанта» идти по пути MVP (минимально жизнеспособного продукта), который можно сделать на чём угодно. Станислав и Василий выбрали Django, потому что это был самый оптимальный выбор в сложившихся условиях, в том числе и для highload проект, к сожалению, Laravel использовать было нельзя, потому что у заказчика с ним были проблемы ранее. При этом главная фича проекта — прохождение самого диктанта, была реализована на React. Всё остальное: регистрация, аутентификация и Wiki — осталось на Django, чтобы снизить нагрузку.

Рассмотрим, как они разрабатывали этот проект по неделям.

До диктанта 11 недель

Всего было 12 недель, но одна из них ушла на согласование и прочее, поэтому на старте осталось лишь 11.

https://lh3.googleusercontent.com/F12ZfLcuUFym8_hwek9l_ZoEHjzEkS8jZOQshGeKxYSuwyzqWB-BzuskU7DaPZCPrgMXVhDxwCJw3jVUGN0_2RJeMB-dw6ZAl2YoRxwjrMYfCk435UrRMHcxpn8JLySBzrzrD8jeqx9MTBtUTRkuaw

Нужно было провести нагрузочное тестирование, чтобы показать заказчику, что Django и React подходят по метрикам. Чтобы приступить к тестированию требовалось собрать более или менее согласованный дизайн, статику и прототип React приложения.

Для оптимизации микросервисов проекту разработчикам требовалось много «железа». Этот вопрос был решен с помощью технического оснащения от Мегафон.

10 недель

https://lh3.googleusercontent.com/rjLWxi0ZGAYbGZH4_AhW8GurUjb8CzSx7hlZ-UlAFHX_d2iDpa6Vbx5iSKMQAhlbpstqCapUc4uqKXVgI4sL1Y0ZqxUSzPeYRbsE4vrPYlibfXPBxyqW_pCxhVhREhjyBSBumvm0HGzxnviBi6_dNw

Было два щекотливых момента, которые настораживали заказчика:

  1. Выбор сервера web-приложения Django: uWSGI.
    Оказалось, что заказчик был очень начитанный, проштудировал все статьи Хабра за неделю. Он просил Bjoern на этот проект из-за его асинхронности и наличия большого количества RPC. Но Василий со Станиславом смогли убедить заказчика оставить uWSGI, потому что по количеству ошибок он стоит до последнего, пока не закончится память.

https://lh4.googleusercontent.com/psCUcdazOMmR8tJQGYhJkwp7G0hweS0AWN7RCjtDHELKm4-P_rjyrCJy0XrqUgnlT5OHMDwcotOZwTWlWe1Q6V7CUSrDI7C9MbvG1E3W9q7jLWMt7hCCYi20Lenp53FpcBrPGuQGxf5NiFRd12pfNg
  1. Выбор балансировщика: HAProxy.
    Заказчик спрашивал, чем не подошли Nginx, Envoy и требовал тесты.  Тесты были успешно выполнены, что позволило оставить HAProxy.

8 недель

https://lh6.googleusercontent.com/mwVDPZUJrNa4tjAbjQttlx9LRgEWhzS5LijZV-adzrLzpNtLVljjMWApnBq2TibsBisNsbp8GKLdXNn9qrxElXETxUYxKNbGkJC88yC0UF0NPwQwoB1iwZdSOGHlUYrQ9TeE8FVMwBf3Das6jKqytA

Настал день нагрузочного тестирования. Поскольку проект жил в облаке Мегафона, логично было вынести его за пределы их инфраструктуры, чтобы получить валидные результаты. Поэтому техническая команда проекта приняла решение поднять под образы Мегафона машины с Яндекс.Танком в Яндекс.Облаке. Поскольку у них уже была собрана статика, то получился не гипотетический конь в вакууме, а конкретное React-приложение с медийными материалами, которые планировалось показать через 8 недель. Кроме этого уже имелись размеры главной страницы всех типов файлов.

RPC заказчика устроило при нормах потребления по контейнерам. Поэтому инфраструктура была утверждена и можно было начинать полноценную разработку.

7 недель

https://lh6.googleusercontent.com/d_qKqi0RV-fcE7pcLMZ_cv442d5doNut4TrsgqF3UJBHgkpK-ZhRHP9keRlt6wx3V6_-vjlS5DZ9dOaZaF6fnjwIuoTFIHKp2CAJ-FJZf4oT8cgTxw7tRHYk5CUOHP2ZUsfBbJBPHjiAs19BINLeFA

Django отвечал за публичную часть: аутентификацию, React — за само прохождение диктанта, он гонял пользовательские сессии через JWT.

Не все из 5 ведущих библиотек одинаково быстро выпускают токены, поэтому их всегда нужно тестировать на своём проекте. А после нагрузочного тестирования просто поменять фичи или либы, и выбрать ту связку, в которой токены выпускаются вовремя.

6 недель

https://lh4.googleusercontent.com/xZC1TRSQKjRMojbcqTpR4Wkj8h3Su-FwCVuT1C3I3lpufl9NIOzU9lfyH5AcCl0KGfo_ZDQiHP7jB195_8xyx3iIt9FgKk5ea9klbaWbz0ZIknIZnkc3xd5Hubpc4jPNgu2wJ2hyQxvCtMC0bW7swA

На 6 неделе заказчик вспомнил, что в старом проекте  на Laravel осталось 300 тысяч учётных записей, которые надо бы перенести. При этом оповестить пользователей о том, что нужно сменить пароль, они не успевали. Поэтому пришлось давить нагрузкой: поднимать микросервисы под Laravel. Но возникла проблема: в Laravel использован bcrypt 128 bit, а в Django — 256 bit. Пришлось под 300 тысяч учёток в бэке отдельно писать ветку, чтобы пользователи, не меняя пароль, могли получить токены Django и пройти дальше.

5 недель

https://lh5.googleusercontent.com/G1Zour3ZrhtIWNZk6w861aO1O4-Skwbo7xxznQmbEdu4ARlYBirT93eE-IArFuxlYJsb-p4KQwxYKqZ0mNkrlTop3nZgIoNnVuO1GeDGEV3OBA3s-9EMlDDf80oKW3XpmfIX_2GpztI8BgUvlxMEbA

Стоит отметить, что глобально web проект на проде уже существовал с первой недели. Потому что его большая часть — это медиатека с довольно большим количеством контента, который нужен участникам для того, чтобы с ним ознакомиться, подучится для онлайн-тестирования. Поэтому к моменту, когда нужно было прикручивать авторизацию и уведомлять пользователей о регистрации, портал, как источник медиафайлов, уже существовал.

Во второй части оставалась ещё задача про рассылку почтовых уведомлений. С учётом опыта прошлого года и уверенного предположения заказчика о том, что Госуслуги сделают рассылку по всей стране, было выставлено требование: сервис должен отправлять минимум 50, а лучше 60-70 писем в секунду.

Обычно, когда мы говорим про сервис почтовых рассылок, вспоминаются MailChimp или UniSender. Но когда разработчики посмотрели на требуемые цифры, то поняли, что эти параметры есть только у Amazon. Однако, Amazon ничего просто так давать не собирался. Он в свою очередь потребовал 15 тысяч долларов и 10% от квот в течении 3-х месяцев.

3-х месяцев в запасе не было, чтобы кому-то что-то доказывать, поэтому в век, когда все пользуются СМС-верификациями или звонками, пришлось самим собирать почтовик —- сделали на Postfix, потом размножили. В общей сложности удалось довести показатели рассылки до 70 писем в секунду. У команды разработчиков было 2 домена, которые в прошлом году участвовали в демонстрации web-портала, поэтому их можно было считать условно прогретыми. В итоге Василий со Станиславом выпустили всё, что было нужно, вплоть до правильных DKIM подписей и по-человечески настроенных портов.

Если вы когда-нибудь будете настраивать свой почтовик с такими объёмами отправки, лучше сразу приобретите на это дело доменов 5. В случае с Экодиктантом, 1 домен «упал» и попал в black-list примерно на 2-3 суток. Поэтому было принято решение переключиться на второй резервный, но попутно делать всё возможное, чтобы скорее вывести из black-list’а упавший домен. Когда его разбанили, то перевели все на основной домен. В общей сложности такое мероприятие отняло около недели. За это время только менее 1% участников людей не удалось получить письмо с подтверждением регистрации с первого раза.

Самое интересное, что потребность в рассылке была необходима, поскольку по итогам прохождения тестирования участники получали диплом, который можно было распечатать в нормальном формате и повесить себе на стенку. Он отправлялся на электронную почту, поэтому организатор по опыту прошлого года уже понимал, что была куча участников, которые регистрировались на непонятную почту, проходили тестирование, а после спрашивали, где их диплом. Учитывая опыт прошлых лет пользователей попросили регистрироваться только валидные почты.

4 недели

https://lh3.googleusercontent.com/BX0iY9eI-rc-eE6sRig5rm4wRV-atNZ6fb6ch2z_7VyMbjDPqvK-5LPhY5wsqsEGs6tl47PxkAlUjnbQgqN9Vr9lNsUFnsKwhjbjV10NXSW_9PTrLJwGunzuwAGH6gn9__rCi5lEbbRlVP9iueNSgw

На начало второго месяца была готова публичная часть (медиатека, регистрации), почта, оповещения в госслужбы, реферальные ссылки компаниям-участникам, чтобы все работники РЖД, Газпрома, Норникеля, которые связаны с экологией, их увидели. Во многих организациях, где работает большое количество сотрудников - это целое мероприятие.

Если у вас совсем времени в обрез, некоторые вещи, связанные с мощностями, можно отдать техническому спонсору. В случае Экодиктанта это был Мегафон. Они настроили аппаратную защиту от DDoS, поэтому команде Станислава с Василием ничего на своей стороне делать не пришлось в этом вопросе.

3 недели

https://lh3.googleusercontent.com/nucdSZLxulA34XLZQTpEwCYCsbmiqzPDtERmT-Xu_QFC_OqDOOgfx3k3faZISBt0Eusw5ZiuXNC6b8FkD-dEPjQ6aZk-NJuO3djTV9mDujMgWsgwO70BEiW3a1E8w75kC1ElO2QoH5CGRjdaDqVOAA

Вовсю шла выкладка контента по 4 категориям: до 18, 18+, экологи, не экологи. Под каждую из категорий заказчик предоставил контент: видео, картинки, текстовые PDF-файлы, звуковые записи и прочее.

Для ускоренной прогрузки медиа файлов, по просьбе заказчика были выключены фильтры конвертации и оптимизации загружаемых файлов. Что привело к ошибочной загрузке на главную страницу больших файлов в не сжатом виде, что в свою очередь привело к превышению квоты пропускной способности канала.

2 недели

https://lh5.googleusercontent.com/kLzgNqBepyEhO0ujXqhZA9g3Y9INpSA09RyYFdecfeWxV4ZnH_ScDs9SdowaVI7KCyPaTSEIALJ7MXzFDzLSSVaTgcFHCg9aAHa9-vRUXXalrXjz9SJmLsHAe5X0JSMAzVatIt2sRMu1nf3BKaEmkg

Поскольку всё находилось в Kubernetes, по автомасштабированию был вопрос. Мегафон сказал, что даст железа столько, сколько нужно, но только тогда, когда будет нагрузка. Он попросил сначала всё оптимизировать, а потом уже забирать аллоцированные ядра.

Поскольку ограничений со стороны железа не было, то команде не подошли методики горизонтального, вертикального и автомасштабирования в Kubernetes. Ключевой метрикой для было не потребление, а скорость ответа, чтобы контейнер всегда оставался жив.

https://lh5.googleusercontent.com/lwQucmqNTLS0cjIOL4H2_8Htnk3b95SQoZVpqwraRimCucTmwGyjjqMmlNbja9yVwSOQHb71TOTrX66GaDv-e_j_6OU6JxOzXdDKtQgQd73F0KqZrC7BHoPFb8aKeSaJxPIOPPdunetfEGJD4IJGpg

Таким образом, основной метрикой было то, с какой скоростью Django машина отдаёт публичную часть, с какой скоростью React-приложение пропускает через себя вопросы-ответы и с какой скоростью отвечает Rest. Под эту историю в соответствии с документацией Kubernetes девопсы подняли сервер метрик и Prometheus. А дальше, чтобы убрать выбросы, на основе опроса поднятых подов в Django и времени ответа через сглаживание, происходило расширение нужного количества подов Django машин.

https://lh5.googleusercontent.com/BzOPVupDm_VwiM3LdyJXlXAvXLADHsgIq2OGcS_-G96d20DqkLbwYUtGHJeqECmjWteUtk10Bw7F9DwVWIvkjOknWMepQT8FD94Zt4t88GRAm_ngDbOWCWlJwz1OeeVc8OAldQdcpvuuVOA9oQn9BA

React в этом проекте вёл себя очень скромно. В то время как Django прямо ел и ел ресурсы пропорционально росту количества регистраций и прохождений тестов.

1 неделя

https://lh3.googleusercontent.com/aV4Xh0FAJmlI_VpB89Q7LEYbXffEFspfu-Q5HiyZu8hwi9D86W5WNmj-Iua2YIQAdHdiIVCgvXZoNT1l1RYTiK5Eg2VYn7skWSzhJ-HY06104l_PB4ZipQy97yeza1vzggqPMF_30o5Yo8sM63kUNA
https://lh3.googleusercontent.com/aV4Xh0FAJmlI_VpB89Q7LEYbXffEFspfu-Q5HiyZu8hwi9D86W5WNmj-Iua2YIQAdHdiIVCgvXZoNT1l1RYTiK5Eg2VYn7skWSzhJ-HY06104l_PB4ZipQy97yeza1vzggqPMF_30o5Yo8sM63kUNA

В 0 часов разработчики узнали, что у проекта деградация на 5 секунд в публичной части. Они не успевали разворачиваться под контейнера. Пришлось разбираться, в чём дело, оказалось, что это Госуслуги начали рассылку.

Дело в том, что Владивосток проснулся в 8 утра, а это 0 часов по Московскому времени. Тогда сразу пошла нагрузка по Кубер-кластеру. Но Кубер не в момент рождает поды, есть задержка. Её хватило, чтобы получить деградацию. Конечно, команда быстро перестроила настройки, предразвернули поды и погасили деградацию. Однако, если бы была информация о рассылке по Госуслугам заранее, то к этому вопросу отнеслись бы пристальней.

Диктант

https://lh3.googleusercontent.com/5AdRX2rgbBDEeqTHu7KcNDxxhgLGgDbUdyU865qvuVo_QnYClIXJFWwXQ4zq59D4QVn02jcAhuOo9lw4A3BX2o86AY26nVdbTuuuOVRTPXHGXZV1Hwp8Id9jDHWPr8a0ViWRmhB2uiPHiOEIwOqXYA

Возможно, вам знакома ситуация, когда люди не могут подключиться к Госуслугам, электронному дневнику и другим сервисам, связанным с обучением. Опасения были и у команды Старботс.рф. Но опасения были напрасны.

Василий отодвинул всё, что не касалось главной фичи, а Станислав ограждал его и остальную команду от яростных атак заказчика по поводу цвета иконок и прочего. Главное, что диктант выдержал и прошёл. В офлайн и в онлайн режимах не было нареканий. Мы это знаем, потому что в конце диктанта было окошко: «Оставьте свой отзыв о том, как всё прошло». Среди более 2 тысяч отзывов были отрицательные, но они не связаны с технической стороной проекта. Это прямо погрело сердце разработчикам, хотя во время подготовки их стороны были и фейлы.

Ошибки и проблемы

  • 2 падения;

Уже во время прохождения диктанта заказчик сообщил, что: «Мария Ивановна и Светлана написали в социальных сетях, что не могут зайти!». Станислав с Василием начали разбираться и включили поиск LIKE в Django.

В это время Postgres сожрал всю память и CPU! Но так как технические возможности были, то просто умножили на 2 и подняли. Но потом он опять упал. В такой критической ситуации, Станислав с Василием подняли директиву и откатили назад на предыдущую версию. Это и спасло. Мария Ивановна, конечно, расстроилась, что не смогла зайти, но зато все остальные смогли.

  • Лёг кластер Кубер;

Если есть отказоустойчивый сервер, разделяйте его на разные дата-центры. Команда этого сначала не сделала и, когда у Мегафона возникли проблемы на VMWARE, у них упал Кубер на час.

  • 2 DDoS-атаки: успешно отбиты аппаратно.

Выводы

→ Говорите «нет» срокам!

Чудес не бывает. Если нужно всё оптимизировать, то времени нужно много. Если делать всё быстро, то требуется много ресурсов, поэтому смело просите больше «железа» и используйте подходы, инструменты MVP.

→ Прогнозируйте всплеск трафика.

Какие бы у вас не были крутые девопсы и подсчёты, перестрахуйтесь и запланируйте все всплески: разверните поды в Кубере заранее и умножьте их количество на два.

→ Кластеры Кубер тоже смертны!

Шардируя Кубер на разные дата-центры, учитывайте, что они могут ломаться.

Комментарии (2)


  1. AntonOcean
    13.07.2023 11:05
    +4

    А вывод не использовать Django? :peka:


    1. dph
      13.07.2023 11:05
      +2

      Вот да. Вроде бы вполне скромные НФТ, интересна только рассылка писем, все остальное совсем небольшое.