Граф знанийНастройки

Обновлено: 11 апреля 2026 г. в 23:51

Система умной парковки

средний

Публичное интервью на C++ Russia 2023: конкурентное бронирование парковочных мест, строгая консистентность и автоматическое освобождение по тайм-ауту.

Система умной парковки ломается не на карте и не на поиске, а в тот момент, когда несколько водителей одновременно пытаются занять одно физическое место.

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

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

Временная бронь

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

Счётчик мест

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

Контур тайм-аута

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

Контроль въезда

Проверка номера машины и команда шлагбауму живут в другом операционном мире, поэтому этот путь стоит отделять от логики бронирования уже на ранней архитектуре.

Публичное интервью на C++ Russia 2023 предлагает спроектировать систему умной парковки: пользователь заранее резервирует место, въезжает по номеру машины, а система должна выдерживать конкуренцию и защищаться от .

Источник

Оригинальный разбор

Разбор основан на публикации в Telegram-канале «Книжный куб» и записи публичного интервью.

Перейти на сайт

Видеозапись интервью

Полная запись публичного интервью длится около 30 минут и доступна на YouTube.

Смотреть на YouTube

Постановка задачи

Система умной парковки

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

Функциональные требования

Поиск парковки

Поиск по геолокации с показом доступных парковок и числа свободных мест.

Создание брони

Атомарное резервирование одного свободного места без перепродажи того же слота.

Отмена по тайм-ауту

Автоматическое снятие брони, если водитель не приехал вовремя.

Въезд и выезд

Автоматическое распознавание номера и открытие шлагбаума для валидной брони.

Нефункциональные требования

Высокая конкуренция

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

Без двойного бронирования

Ошибка в этой системе очень заметна пользователю: нельзя отдать одно физическое место двум машинам одновременно.

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

Связанная глава

Геопоиск и горячие зоны

Полезна для разговора о локальных пиках нагрузки и географическом разбиении парковок.

Читать обзор

Высокоуровневая архитектура

Система умной парковки: архитектурная карта

временная бронь, контроль въезда и снятие просроченной брони

Контур бронирования

Приложение водителя
поиск и бронь
API-шлюз
авторизация и маршрутизация
Сервис бронирования
создание и отмена
Контур блокировки мест
Redis-семафор
База бронирований
состояние и история

Контур доступа и фоновой обработки

ANPR/LPR -> Сервис въезда -> Контроллер шлагбаума
проверка номера и команда на шлагбаум
Шина событий -> Очередь тайм-аутов -> Воркер отмены
контур истечения времени брони
Уведомления
push и email

Сквозной сценарий умной парковки: бронирование места, проверка въезда и автоматическое освобождение просроченной брони.

Архитектура сознательно разделяет три контура: оформление брони, физический контроль въезда и фоновое снятие просроченных броней. Так API, контур ANPR/LPR и фоновые воркеры можно масштабировать независимо и деградировать по-разному.

Основные сущности

Parking

{
  id: UUID,
  gps_coordinates: {lat, lon},
  total_capacity: int,
  free_spots_counter: int,  // семафор!
  address: string
}

Booking

{
  id: UUID,
  user_id: UUID,
  parking_id: UUID,
  car_plate: string,
  created_at: timestamp,
  expires_at: timestamp,
  status: enum (pending, confirmed, cancelled, expired)
}

Счётчик свободных мест

Центральная техническая сложность здесь — атомарно уменьшить счётчик свободных мест так, чтобы он никогда не уходил ниже нуля. Именно на этой операции и появляется гонка между параллельными запросами на одно и то же место.

Redis: Lua-скрипт

Рекомендуется
-- parking_book.lua
local counter = redis.call('GET', KEYS[1])
if tonumber(counter) > 0 then
  return redis.call('DECR', KEYS[1])
else
  return -1  -- Нет свободных мест
end

Плюсы

Атомарность на одном ключе, простая логика и высокая скорость.

Минусы

Нужно отдельно продумать отказоустойчивость и синхронизацию с основной БД.

PostgreSQL: условный UPDATE

UPDATE parkings 
SET free_spots = free_spots - 1
WHERE id = $1 AND free_spots > 0;

-- affected_rows = 0 → мест нет

Плюсы

Строгие транзакционные гарантии и единый источник истины для состояния.

Минусы

Под высокой конкуренцией быстро упирается в блокировки строк и нагрузку на БД.

Рекомендуемый подход

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

Автоматическое освобождение по тайм-ауту

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

AWS SQS: задержанная доставка

# При бронировании
sqs.send_message(
    QueueUrl=timeout_queue,
    MessageBody={"booking_id": "...", "parking_id": "..."},
    DelaySeconds=900  # 15 минут
)

# Через 15 минут воркер проверяет:
# - Если машина не приехала → INCR счётчик, отменить бронь
# - Если приехала → ничего не делать

Альтернатива — RabbitMQ Delayed Message Plugin, если очередь нужно держать внутри собственного контура.

Воркер отмены и сервис въезда должны быть : повторное сообщение не должно вернуть место в пул дважды и не должно повторно отменить уже завершённую бронь.

Географическое разбиение

Для этой системы естественно использовать по регионам, а ещё точнее — . Большинство запросов локальны: водитель ищет парковку рядом, а не по всей стране.

Стратегия

  • Ключ разбиения можно строить из региона или geohash-ячейки парковки.
  • Запросы «покажи ближайшие парковки» обычно обслуживаются внутри одного региона.
  • Пересечение между регионами остаётся редким исключением, а не нормальным режимом.

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

Ключевые выводы

Семафор на счётчике мест

Критичный инвариант живёт в одном месте: место либо занято, либо свободно. Любая гонка вокруг декремента ломает весь сценарий.

История бронирований обязательна

Отдельная сущность брони нужна не только продукту, но и аудиту, поддержке, аналитике и восстановлению состояния после сбоев.

Тайм-аут — отдельный контур

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

География помогает с масштабированием

Парковки естественно разбиваются по регионам, поэтому локальность трафика можно использовать уже на ранней архитектуре.

Что важно проговорить на интервью

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

Оценка интервьюера

✓ Сильные стороны

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

⚠ Области для улучшения

  • Отдельную сущность брони нужно было назвать и обсудить раньше.
  • Не хватает численной оценки нагрузки и явного sizing по пикам.
  • Выбор между Redis и PostgreSQL стоит доводить до более явного решения.
  • Не до конца раскрыт операционный контур вокруг ANPR/LPR и обработки сбоев на въезде.

Связанные главы

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