System Design Space

    Глава 37

    Обновлено: 9 февраля 2026 г. в 20:31

    Система бронирования отелей

    Прогресс части0/21

    Публичное интервью на ArchDays 2022: overbooking, inventory-модель, конкурентность и масштабирование.

    На конференции ArchDays 2022 мы провели публичное System Design интервью в формате, максимально приближённом к реальному собеседованию в Big Tech компаниях. Задача — спроектировать систему бронирования отелей. Этот разбор покажет весь процесс от формализации требований до обсуждения масштабирования.

    Связанный кейс

    Проектирование Airbnb

    Похожая задача с geo-search, dynamic pricing и двусторонним маркетплейсом.

    Читать обзор

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

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

    Смотреть на YouTube

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

    Hotel Booking System

    Спроектировать систему бронирования отелей для российского рынка.

    20 000 отелей

    Общее количество отелей в системе

    1 000 000 номеров

    Суммарное количество номеров

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

    Просмотр информации

    Детальная информация об отелях и номерах

    Онлайн бронирование

    Выбор дат и типа номера с оплатой

    Оплата

    Интеграция с платёжной системой

    Отмена брони

    Возможность отменить бронирование

    Важное бизнес-требование: Overbooking до 10%

    Система должна поддерживать овербукинг — возможность продать больше номеров, чем есть в наличии. Это стандартная практика в гостиничном бизнесе, так как часть броней отменяется или гости не приезжают (no-show).

    Что вынесли за scope

    Авторизация/аутентификацияАдмин-панельПоиск отелейОтзывы и рейтинги

    Оценка нагрузки (Back of the Envelope)

    Средняя длина брони5 ночей
    Средняя заполняемость70%
    Номеров занято ежедневно700 000
    Новых бронирований в день~200 000
    Средняя нагрузка~2.3 TPS

    Важно: Средняя нагрузка невелика, но будут значительные пики — сезонные распродажи, праздники, flash-sales. Система должна выдерживать нагрузку в 10-100 раз выше средней.

    Public API

    GET/v1/hotels/{hotel_id}

    Получение информации об отеле

    GET/v1/hotels/{hotel_id}/rooms/{room_type_id}

    Получение информации о типе номера

    POST/v1/reservations

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

    {
      "hotel_id": "123",
      "room_type_id": "456",
      "start_date": "2024-03-15",
      "end_date": "2024-03-20",
      "guest_info": { ... }
    }
    DELETE/v1/reservations/{reservation_id}

    Отмена бронирования

    Эволюция модели данных

    Одна из ключевых тем интервью — как правильно спроектировать модель данных для поддержки overbooking и высокой конкурентности.

    Наивный подход: Таблица Reservations

    Reservation
    ├── id
    ├── hotel_id
    ├── room_type_id
    ├── room_id (конкретный номер)
    ├── start_date
    ├── end_date
    ├── status
    └── guest_id

    Проблема 1: Для проверки доступности нужно делать COUNT по всем броням на дату

    Проблема 2: Сложно реализовать overbooking — нужно знать точное количество доступных номеров

    Проблема 3: Race condition при одновременном бронировании

    Улучшенный подход: Inventory-based модель

    RoomTypeInventory
    ├── hotel_id
    ├── room_type_id
    ├── date
    ├── total_rooms (всего номеров этого типа)
    ├── total_reserved (забронировано)
    └── overbooking_limit (лимит овербукинга)
    
    Constraint: total_reserved <= total_rooms * (1 + overbooking_limit)

    Преимущество 1: Мгновенная проверка доступности — один SELECT

    Преимущество 2: Overbooking встроен в модель через overbooking_limit

    Преимущество 3: Атомарное обновление через UPDATE с условием

    Обработка конкурентности

    Критически важная тема — как избежать race condition, когда два пользователя пытаются забронировать последний номер одновременно.

    Pessimistic Locking (SELECT FOR UPDATE)

    BEGIN;
    SELECT * FROM room_inventory 
    WHERE hotel_id = ? AND room_type_id = ? AND date = ?
    FOR UPDATE;
    
    -- Проверка и обновление
    UPDATE room_inventory SET total_reserved = total_reserved + 1 ...
    
    COMMIT;

    Плюсы

    Гарантированная консистентность, простая логика

    Минусы

    Блокировка строки, снижение throughput, deadlock риск

    Optimistic Locking (Repeatable Read)

    -- Isolation Level: REPEATABLE READ
    BEGIN;
    
    UPDATE room_inventory 
    SET total_reserved = total_reserved + 1
    WHERE hotel_id = ? 
      AND room_type_id = ? 
      AND date = ?
      AND total_reserved < total_rooms * (1 + overbooking_limit);
    
    -- Если affected_rows = 0, номеров нет
    COMMIT;

    Плюсы

    Высокий throughput, нет блокировок, атомарность

    Минусы

    Нужен retry при конфликтах

    Database Constraints

    ALTER TABLE room_inventory 
    ADD CONSTRAINT check_overbooking 
    CHECK (total_reserved <= total_rooms * (1 + overbooking_limit));

    Дополнительная защита на уровне БД — даже при багах в коде система не нарушит лимиты.

    Выбор для нашего масштаба

    При нагрузке ~2.3 TPS с пиками до 100 TPS Optimistic Locking — оптимальный выбор. Он обеспечивает высокую производительность без сложности распределённых блокировок. Pessimistic Locking имеет смысл при очень высокой конкуренции за конкретные ресурсы.

    Стратегии масштабирования

    Партиционирование по времени

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

    • Старые данные можно архивировать
    • Запросы работают с меньшим объёмом данных
    • Упрощает maintenance операции

    Шардирование по hotel_id

    Распределение данных по разным шардам на основе ID отеля.

    • Горизонтальное масштабирование записи
    • Изоляция нагрузки между отелями
    • Consistent hashing для распределения

    Ключевые выводы из интервью

    1

    Начинайте с уточняющих вопросов

    Overbooking — критическое требование, которое кардинально меняет архитектуру. Без этого вопроса можно уйти не в ту сторону.

    2

    Итеративно улучшайте дизайн

    Показали эволюцию от наивной модели Reservation к Inventory-based подходу. Интервьюер оценивает не финальный ответ, а ход мыслей.

    3

    Обосновывайте выбор стратегии конкурентности

    Pessimistic vs Optimistic locking — классический trade-off. Важно объяснить, почему выбрали конкретный подход для данной нагрузки.

    4

    Думайте о масштабировании заранее

    Даже если текущая нагрузка невелика, покажите понимание того, как система будет расти и какие стратегии применить.