В августе-сентябре и во время черной пятницы произошло несколько десятков отказов и периодов снижения производительности Mindbox из-за кратного роста нагрузки. Просим прощения за это у клиентов.
5 декабря 2019
Отчет по инцидентам. Как мы не справились с ростом
В августе–сентябре и во время черной пятницы произошло несколько десятков отказов и периодов снижения производительности Mindbox из-за кратного роста нагрузки.
Пожалуйста, обратитесь к вашему менеджеру за компенсацией по SLA, таким образом ваша обратная связь напрямую дойдет до ответственных. Компенсации специально сделаны существенными для нас, а бонусы ответственных привязаны к прибыли.
Такой частоты отказов никогда не было, и, из-за одновременного повышения прозрачности через status.mindbox.group, могло возникнуть ощущение резкого снижения надежности.
В реальности всё не так плохо: есть объективные сложности, мы понимаем причины, часть уже исправили, часть исправляем, в 2020 такие отказы станут невозможными.
Есть и повод для радости: с такой нагрузкой в России сталкиваются единицы компаний, мы приобретаем уникальный опыт, а рост открывает возможности. Вы можете рассчитывать на наши долгосрочные растущие инвестиции в надежность и развитие инфраструктуры для вашего бизнеса.
Ниже открытый отчет о происходящем:
- Что произошло: кратковременные отказы части функций у части клиентов
- Причины: не справились с ростом
- Что сделали: выделили ресурсы, снизили частоту и критичность отказов
- Сделаем дальше: принципиально поменяем архитектуру и подход к надежности
- Чего ждать в будущем: ещё несколько отказов и резкое увеличение надежности
- Технические подробности
Что произошло
Первая серия отказов, несколько десятков, случилась в августе и сентябре. Отказывал единый шлюз протокола api.mindbox.ru, т. е. почти весь функционал у большинства клиентов. Суммарно перебои в работе длились около четырех часов. Пострадавшим клиентам выплатили более миллиона рублей в виде компенсаций по SLA.
Отказывали случайные части сервиса, и нам потребовалось около месяца на идентификацию причин и запуск улучшений.
В неделю черной пятницы по схожим корневым причинам произошло еще 4 краткосрочных отказа в других местах, и ещё три — из-за сопутствующих изменений. Отказы были меньшего масштаба и эффекта. Суммарная длительность — около часа, каждый раз для разных групп клиентов (от 5% до 15%) и разного функционала.
Причины
Основная причина приятная: мы растем быстрее самых смелых прогнозов.
С августа по ноябрь среднесуточная нагрузка по вызовам наших API выросла в два раза, с 60 до 120 тысяч запросов в минуту. Всего в ноябре мы отправили 1,1 миллиарда писем. А вот сколько писем мы отправляем в неделю черной пятницы ежегодно:
Количество писем за неделю черной пятницы
К сожалению, мы не успели привести архитектуру в соответствие с возросшим уровнем нагрузки, хотя уже два года готовим нужные изменения. Требуется поменять балансировщик нагрузки и способ распределения клиентских приложений по серверам. Для этого нужно перенести все 2 миллиона строк кода на более новую версию библиотек без обратной совместимости (.net core) и отладить под другой операционной системой, параллельно переписав почти весь код мониторинга и выкладки обновлений. Всё это в режиме 24/7 работы под нагрузкой и с быстрым выпуском новых функций.
Одновременно с корневой причиной несколько раз возникало недокументированное поведение различных компонентов при достижении их предельных возможностей. К этому мы привыкли, но в комбинации с другими факторами это вызвало дополнительные сложности.
Еще несколько отказов произошло из-за желания ускорить изменения, чтобы не подводить клиентов. Если бы не общая частота перебоев, они бы уложились в рамки нормального уровня.
Что сделали
- Выделили больше ресурсов шлюзу (с четырехкратным запасом)
- Перенесли шлюз на отдельный балансировщик нагрузки и сервера
- Лучше изолировали компоненты приложения
- Улучшили систему диагностики и оповещения
- Повысили отказоустойчивость кода и выкладку приложения
В результате с начала октября надежность шлюза вернулась к нормальной.
Среднее времени ответа и срабатывания мониторинга шлюза
Мы ошибочно посчитали, что этого достаточно, чтобы дождаться плановых архитектурных изменений в первом полугодии 2020 года, но в неделю черной пятницы произошли новые отказы на веб-серверах с клиентскими приложениями, несмотря на сниженную нагрузку из-за изоляции шлюза. Что приятно — шлюз больше не отказывал.
Дальнейшие планы
В декабре:
- Внепланово сменим архитектуру балансировки нагрузки
- Уменьшим количество приложений на одном сервере
- Усилим изоляцию клиентов друг от друга в рамках одного сервера
Это уменьшит вероятность новых отказов в ближайшие пики нагрузки.
В первом квартале 2020 года:
- Перенесем отслеживание рассылок в облако
- Отладим новую архитектуру балансировки нагрузки
Во втором квартале:
- Перенесем шлюз и клиентские приложения в облако
- Клиентские приложения будут выполняться в изолированных контейнерах
- Клиентские приложения будут автоматически балансироваться между серверами
Важно: клиентские данные продолжат храниться на наших собственных серверах в России, облако также будет российским.
В третьем и четвертом квартале:
- Выделим и изолируем микросервис процессинга и лояльности
- Сменим сервис очередей на более надежный и производительный
Над изменениями архитектуры работает выделенная команда с самыми опытными специалистами. Начиная со второго квартала 2020 года подключится вторая команда.
По итогам мы ожидаем повышение скорости работы и долгосрочное уменьшение количества инцидентов из-за лучшей изоляции, автобалансировки приложений в кластере kubernetes и уменьшения ошибок администрирования собственной инфраструктуры.
К сожалению, при таких масштабных изменениях неизбежно будут совершаться ошибки, которые вызовут ещё некоторое количество разовых отказов. Мы постараемся их избежать, но просим отнестись к ним с пониманием и запастись терпением.
Технические подробности
Причины
Основная причина: устаревшая архитектура веб-сервисов
С самого начала существования Mindbox мы проектируем веб-сервисы так, чтобы максимально изолировать клиентские данные друг от друга. Бóльшая часть работы с ними происходит в отдельном веб-приложении (в IIS) для каждого клиента. Часть сервисов, включая api.mindbox.ru, обслуживает всех клиентов. Это позволяет управлять безопасностью из единой точки, работать с асинхронными интеграциями, изменять инфраструктуру незаметно для клиентов.
Масштабирование веб-приложений под возрастающую нагрузку происходит через добавление веб-серверов в кластер. Балансировку между серверами осуществляет Microsoft NLB, поэтому все веб-приложения расположены на всех серверах.
Со временем число клиентов достигло предела, когда один сервер с трудом выдерживает такое количество приложений из-за количества потоков, процессов, сокетов.
Ещё одна неудачная для нас особенность NLB — принципы его работы с трафиком. NLB всегда распределяет весь входящий трафик по всем серверам, а отвечает на конкретный запрос только один из них. Какой именно — рассчитывает механизм балансировки NLB. Таким образом, с ростом количества клиентов росло и количество входящего трафика, и все сервера нагружались поровну. Это также вызывало сложно диагностируемые проблемы на сетевом уровне.
Приложение api.mindbox.ru располагалось на тех же веб-серверах. С ростом количества приложений и объемов трафика вероятность его отказа повышалась, пока не стала критической.
Дополнительная причина: метрики и мониторинг
Недостаток метрик затруднил диагностику. На момент первых инцидентов мы не могли смотреть:
- Метрики в разрезе по клиентам, чтобы исключить некорректные интеграции. В результате наш мониторинг генерировал ложные срабатывания, на разборы которых тратилось время.
- Долю каждого узла инфраструктуры в общем времени ответа сервиса. Без этой метрики сложно определить точку отказа в случае инцидента.
Дополнительная причина: пределы возможностей инфраструктуры
Для механизма очередей мы используем RabbitMQ. Мы достигли недокументированных пределов его производительности, а из-за недостатка метрик не были уверены, где именно возникает замедление.
Аналогичные сложности возникли с клиентом Redis, который мы используем. Оказалось, что в некоторых ситуациях при большой нагрузке в нем копится очередь блокировок, что приводит к отказу. И снова мы смогли диагностировать проблему, только улучшив метрики.
Дополнительная причина: интернет-канал
С ростом количества клиентов мы стали отправлять 50 терабайт писем в месяц. В результате в августе и сентябре несколько раз полностью использовали наш исходящий канал — 2Гбит/сек. Это незначительно влияло на доступность api.mindbox.ru, однако из-за множества параллельных инцидентов мешало диагностике.
Оперативное расширение канала было невозможно из-за устаревшего способа коммутации с ISP: переключение на 10Гбит-ную оптику заняло несколько недель.
Шаги и планы
Крупные выполненные шаги
- Создали основу для микросервисной архитектуры: отказы приложений CDP уже не влияют на работоспособность рекомендаций, персонализации и ещё нескольких компонентов
- Поменяли процесс надежности и восстановления, лучше определили ответственность и выделили дополнительных дежурных для ускорения реакции
- Выделили инфраструктурную команду из разработчиков, архитекторов и devops / sre специалистов
- Перевели основную массу кода на .NET Core (в рамках подготовки к переходу на linux стек)
- Начали миграцию вычислительных мощностей в облако, linux и кластер kubernetes: выбрали провайдера, установили выделенный канал, завершили прототип новой архитектуры и процессов разработки на небольшом приложении
Малые выполненные шаги
- Изолировали все компоненты api.mindbox.ru от других приложений
- Разместили api.mindbox.ru на серверах с большим запасом по производительности (пиковая нагрузка на CPU веб-серверов — 13%)
- Переписали приложение, сделав его менее чувствительным к кратковременным отказам БД и Redis
- Доработали мониторинг и диагностику: отслеживаем распределение времени ответа по частям кода и инфраструктуры, по типу запроса, по клиенту, а также размеры асинхронных очередей, системные метрики RabbitMQ, Redis и другие
- Обновили политики алертов: в случае деградации производительности сервиса SMS дежурному теперь приходит в течение двух минут, при этом нет лишних SMS.
- Улучшили конвейер доставки api.mindbox.ru: дежурный может одной командой сделать откат и в течение нескольких минут вернуть предыдущую версию кода в случае недоступности
- Распределили нагрузку на RabbitMQ между пятью экземплярами приложения
- Балансировщик NLB внепланово меняем на HaProxy для уменьшения количества приложений на текущих веб-серверах
Планируем
- Плавное перемещение в облако частей приложения: трекинг писем, шлюз, клиентские приложения
- Миграцию на другую систему очередей (Kafka)
- Выделение микросервиса лояльности
- Дальнейшие улучшения процесса надежности, метрики и организационные меры: расширение штата, регулярные тренировки по отказоустойчивости