Анализ постмортема сбоя Ticketon 11 апреля 2025 года
Как и обещали, Ticketon опубликовали постмортем по итогам сбоя 11 апреля. Вот мой анализ этого документа.
Стала понятна главная причина дублирования билетов. При массовом наплыве пользователей сервера Ticketon перестали справляться с нагрузкой и сайт периодически становился недоступным. Чтобы решить эту проблему, команда экстренно решила использовать Cloudflare Waiting Room. В постмортеме напрямую не называется Cloudflare, но этот сервис упоминается в прошлом сообщении Алексея Ли.
Когда используется Cloudflare Waiting Room, пользователи перенаправляются на специальную страницу ожидания вместо того, чтобы случайным образом получать ошибки загрузки сайта. И система следит за тем, чтобы те пользователи, кто пришёл раньше, получили доступ к сайту раньше. Виртуальная очередь как снижает нагрузку на сайт, так и явно информирует пользователей, когда они смогут воспользоваться сервисом. Рекомендую прочитать статью о том, как использовать Waiting Room. А для тех, кто хочет узнать больше, есть хорошая статья о технических деталях работы сервиса.
Проблемы начались сразу же после включения электронной очереди. Чтобы понять причину, необходимо знать, как работает оплата на веб-сайтах. Для этого рекомендую посмотреть видео, где я рассказываю про работу платёжных провайдеров на примере Stripe. Другие платёжные провайдеры работают аналогично.
Когда пользователь заходит на сайт Ticketon, выбирает билет и нажимает "Оплатить", то оплату принимает не Ticketon, а отдельный сервис - платёжный провайдер. После того, как пользователь оплатил билет и платёжный провайдер снял деньги с карты, необходимо уведомить об этом Ticketon, чтобы он у себя отметил, что этот билет продан, и затем выслал ваучер покупателю. Для этого у Ticketon есть HTTP API эндпоинт, на который платёжный провайдер шлёт HTTP запросы с подтверждениями покупок билетов.
Проблема возникла именно с этим эндпоинтом.
Для повышения безопасности и надёжности системы Ticketon позволял слать запросы на эндпоинт только с ограниченного списка IP адресов - адресов платёжного провайдера. Это грамотное решение. Нельзя давать возможность кому угодно слать запросы на такой важный эндпоинт.
Так что же произошло после того, как команда подключила Cloudflare Waiting Room? В постмортеме это явно не указано, но я вижу только один возможный сценарий. Для того, чтобы Waiting Room заработал, нужно начать проксировать трафик через Cloudflare. То есть запросы от пользователей сначала отправляются на сервера Cloudflare и потом Cloudflare переотправляет запросы на сервера Ticketon. Это позволяет решить, перегружен ли сайт, и, если да, то вместо запроса на сайт Ticketon вернуть HTML-страницу электронной очереди.
Думаю, внимательные читатели уже поняли, что пошло не так.
После включения проксирования через Cloudflare запросы от платёжного провайдера стали также проходить через Cloudflare. И запросы на эндпоинт подтверждения покупок в Ticketon стали приходить с IP адресов Cloudflare, а не с IP адресов платёжного провайдера. Поэтому эти запросы блокировались. Покупки перестали подтверждаться.
Вот как это выглядело с точки зрения покупателя. Он заходил на сайт, выбирал место, нажимал "Оплатить" и вводил платёжные данные. После этого платёжный провайдер списывал деньги и говорил покупателю, что платёж успешно завершён. Покупатель думал, что всё хорошо, и билет теперь его.
Но подтверждение оплаты покупателем не доходило от платёжного провайдера до Ticketon. И Ticketon думал, что покупатель выбрал билет, перешёл на его оплату, но оплату не произвёл. Из-за этого через некоторое время бронь с билета снималась, и его мог купить уже другой человек. В итоге, было совершено более 10 тысяч таких повторных продаж.
К сожалению, в постмортеме не указано, как можно было предотвратить эту проблему. Поэтому я напишу 2 технических решения, которые позволили бы избежать сбоя:
- Можно было начать проксировать через Cloudflare не все запросы на Ticketon, а только запросы от пользователей. Но для этого эндпоинт подтверждения платежей должен был изначально быть на другом (под)домене. Cloudflare позволяет включать проксировать только для конкретных доменов. Если бы эндпоинт был, к примеру, по адресу https://payments.ticketon.kz/webhook, то можно было не включать проксирование для payments.ticketon.kz, и проблема бы не возникла
- Использование прокси по пути запроса от клиента к целевому серверу это частая практика. И поэтому нельзя смотреть только на IP адрес пришедшего запроса, чтобы понять, кто его изначальный отправитель. Для сохранения информации об IP адресе исходного отправителя прокси в переотправляемые запросы добавляют HTTP-заголовок X-Forwarded-For. Cloudflare тоже так делает. Поэтому сервера Ticketon должны были проверять наличие этого заголовка и брать IP адрес отправителя оттуда. Там бы они нашли адрес платёжного провайдера и проблема бы не возникла.
Указанные выше меры позволили бы избежать сбоя в этом конкретном случае. Но могут возникнуть и другие проблемы. Поэтому у команды должен был быть план на случай, когда такая важная часть общего процесса покупки перестала работать. К примеру, должна быть метрика отношения количества бронирований к количеству покупок. И в случае аномального изменения этой метрики, команде должен сразу прилетать алёрт. И затем у команды должны были быть средства быстро предотвращения проблемы. Например, автоматическое продление бронирования для всех неоплаченных билетов. Чтобы их нельзя было купить, пока команда не решит проблему.
На этом я завершаю анализ технических деталей и хочу поделиться своим мнением о постмортеме в целом.
Упор в документе сделан на организационных проблемах и на том, как их предотвращать в будущем. Я бы хотел, чтобы технические проблемы были проанализированы так же глубоко. Чтобы в посмортеме было больше технических деталей, таких как графики потребления ресурсов и времени обработки запросов, и описание того, что в сайте отказало под нагрузкой.
Но нужно отдать должное команде Ticketon и Freedom Holding в целом. Казахстанские компании всё ещё очень редко публикуют постмортемы, и шаг Ticketon заслуживает большого уважения. Это повышает прозрачность и помогает всему сообществу казахстанских ИТ-специалистов учиться на реальных ситуациях. Надеюсь, другие компании последуют примеру Ticketon и тоже будут публиковать разбор сбоев своих ИТ-систем. Это сделает рынок более зрелым, а продукты надёжнее.
P.S. Подписывайтесь на мой канал, чтобы получать подобные глубокие технические разборы и быть в курсе событий ИТ-индустрии https://t.me/drim_channel
ДОПОЛНЕНИЕ от 13 мая 2025 года:
В комментарии ниже написали, что причина сбоя была несколько другой. И заключалась в том, что запросы от платёжного провайдера просто не доходили до эндпоинта, потому что они вставали в очередь наравне с запросами от пользователей. Для корректной работы нужно было в конфигурации Cloudflare Waiting Room настроить Bypass Rules, чтобы запросы с IP адресов платёжных провайдеров не попадали в очередь ожидания. Либо настроить правило, чтобы в очередь не попадали запросы на конкретный URL эндпоинта Ticketon. Спасибо комментатору Владимиру за уточнение, это ценно.