Системы оплаты проезда и билетов: как мы проектируем решения под нагрузку и рост

Почему транспортные платежи — отдельный класс задач
Когда заказчик говорит «нам нужна онлайн-оплата проезда», за этой фразой скрывается не интернет-магазин с корзиной, а инфраструктура реального времени. Пассажир валидирует карту на турникете или у кондуктора, и решение «пускать или нет» система обязана принять за доли секунды — независимо от того, есть ли в этот момент связь с банком, перегружен ли сервер и сколько таких же пассажиров прикладывают карту в эту же секунду в других точках города.
Это меняет всё. Обычный e-commerce может позволить себе показать спиннер на две секунды и баннер «попробуйте позже». В транспорте «попробуйте позже» означает очередь на входе в метро, заблокированный турникет и недовольство тысяч людей одновременно. Поэтому транспортные платёжные системы проектируются вокруг трёх свойств: предсказуемая задержка, устойчивость к пиковым нагрузкам и корректность учёта денег даже при сбоях.
Мы в OneDev подходим к таким проектам как к финтех-инфраструктуре с жёсткими SLA, а не как к веб-приложению с платёжной формой. Ниже — как мы рассуждаем об архитектуре, какие решения принимаем и какие ошибки чаще всего видим у систем, доставшихся в наследство.
Нагрузка в транспорте неравномерна — и это главное
Главная особенность транспортных платежей — резкая неравномерность трафика. Утренний и вечерний час пик дают всплеск в десятки раз выше среднесуточного уровня. На крупной станции метро в течение нескольких минут проходят тысячи валидаций, и каждая из них — отдельная транзакция, которую нужно проверить, списать и записать.
Проектировать систему под средний показатель — классическая и дорогая ошибка. Считать нужно пиковую секундную нагрузку (TPS, транзакций в секунду) на самой загруженной точке в самый загруженный момент, а затем закладывать запас сверху. Если средний поток — 50 транзакций в секунду, а пик на крупном узле даёт 1500, проектировать надо под 2000–2500, иначе система ляжет именно тогда, когда она нужнее всего.
- Пиковый TPS на узел, а не усреднённый по сети за сутки.
- Сезонность и события: праздники, спортивные матчи, погодные аномалии меняют поведение пассажиров.
- Холодный старт утром: одновременное «пробуждение» тысяч валидаторов и их синхронизация с центром.
- Деградация связи: 3G/4G в тоннелях и на удалённых маршрутах нестабильны, а оплата должна работать.
Офлайн-режим: то, что отличает транспорт от любого магазина
Связь в транспорте пропадает регулярно: метро под землёй, пригородные автобусы на трассе, паромы. Система, которая отказывает в проезде при потере интернета, нежизнеспособна. Поэтому критичный архитектурный принцип — валидатор должен уметь принять решение локально.
На практике это означает, что валидатор хранит локальные списки (белые и чёрные), правила тарификации и буфер транзакций. Если связи нет, устройство принимает решение по локальным данным, записывает транзакцию в очередь и синхронизирует её с центром, как только канал восстановится. Центральная система при этом обязана корректно обработать «задержанные» транзакции, пришедшие пачкой через минуты или часы.
Деньги нельзя терять и нельзя списывать дважды
Финансовая корректность — то, что прощают меньше всего. Пассажир не должен быть списан дважды за одну поездку, а перевозчик не должен недосчитаться выручки из-за «потерянной» транзакции. При распределённой системе с офлайн-буферами и повторными отправками это нетривиально.
Базовый инструмент здесь — идемпотентность. Каждая транзакция получает уникальный идентификатор на устройстве в момент создания, и сервер при повторном получении того же идентификатора не проводит операцию заново, а возвращает прежний результат. Это защищает от двойных списаний при ретраях после обрыва связи.
Поверх этого обязательна регулярная автоматическая сверка (reconciliation): данные валидаторов, центральной системы и банка/процессинга должны сходиться. Любое расхождение — это инцидент, который нужно ловить автоматически, а не обнаруживать в конце месяца при сведении отчётности.
Архитектура, которая выдерживает рост
Систему оплаты проезда нельзя строить как монолит, который при росте сети просто «ставят на сервер помощнее». Вертикальное масштабирование упирается в потолок, и именно в час пик. Мы проектируем такие решения вокруг нескольких принципов.
- Горизонтальное масштабирование без состояния: сервисы приёма транзакций не хранят сессионное состояние в памяти, что позволяет добавлять инстансы под нагрузку.
- Очереди и буферизация: входящие транзакции принимаются быстро и складываются в очередь (например, брокер сообщений), а тяжёлая обработка идёт асинхронно. Это отделяет пиковый приём от скорости обработки.
- Разделение горячего и холодного пути: валидация и решение «пускать» — отдельный быстрый контур; аналитика, отчётность и биллинг — отдельный, не мешающий первому.
- Кэширование правил тарификации: тарифы и лимиты меняются редко, поэтому они кэшируются и не дёргают базу на каждую транзакцию.
- Изоляция отказов: падение модуля отчётности не должно ронять приём оплаты.
Безопасность и соответствие требованиям
Платёжные данные — зона повышенной ответственности. Если система работает с банковскими картами напрямую, в игру вступают требования PCI DSS, и грамотный путь — не хранить данные карт у себя, а использовать токенизацию и процессинг на стороне сертифицированного провайдера. В контексте Узбекистана это также интеграция с локальными платёжными системами и банковской инфраструктурой, локализация хранения данных и работа с местными процессингами.
Отдельный пласт — защита самих валидаторов от подделки баланса и клонирования карт, шифрование каналов между устройствами и центром, аудит всех операций. Транспортная карта — это, по сути, носитель денег, и относиться к ней нужно соответственно.
Типичные ошибки унаследованных систем
Когда нас зовут переделать существующую систему, мы чаще всего встречаем один и тот же набор проблем. Понимание этих граблей помогает не наступить на них в новом проекте.
- Нет офлайн-режима — система парализуется при потере связи именно там, где связь нестабильна.
- Синхронная обработка «в лоб» — каждая транзакция ждёт банк, и в пик всё встаёт в очередь.
- Отсутствие идемпотентности и сверки — учёт «плывёт», расхождения копятся незаметно.
- Жёстко зашитые тарифы — изменение цены проезда требует релиза и простоя вместо смены конфигурации.
- Нет наблюдаемости — нет метрик TPS, задержек и доли ошибок, поэтому деградацию замечают по жалобам пассажиров, а не по дашбордам.
Последний пункт мы считаем обязательным с первого дня: мониторинг задержек, очередей, доли отклонённых операций и расхождений сверки — это не «улучшение на потом», а часть несущей конструкции. Без него вы управляете системой вслепую.
Вывод
Системы оплаты проезда — это финтех-инфраструктура реального времени, где цена архитектурной ошибки измеряется не багами, а очередями, потерянными деньгами и репутацией. Надёжное решение строится вокруг пиковых нагрузок, офлайн-устойчивости валидаторов, идемпотентного учёта с автоматической сверкой и архитектуры, которая масштабируется по частям вместе с ростом сети. Если вы планируете запуск или модернизацию транспортной платёжной системы в Узбекистане — расскажите нам о маршрутах, ожидаемом пассажиропотоке и текущей инфраструктуре, и команда OneDev поможет спроектировать решение, которое выдержит и сегодняшнюю нагрузку, и завтрашний рост.