На конференции ArchDays 2022 мы провели публичное System Design интервью в формате, максимально приближённом к реальному собеседованию в Big Tech компаниях. Задача — спроектировать систему бронирования отелей. Этот разбор покажет весь процесс от формализации требований до обсуждения масштабирования.
Связанный кейс
Проектирование Airbnb
Похожая задача с geo-search, dynamic pricing и двусторонним маркетплейсом.
Видеозапись интервью
Полная запись публичного интервью доступна на YouTube. Рекомендую посмотреть перед чтением разбора, чтобы увидеть динамику процесса.
Смотреть на YouTubeПостановка задачи
Hotel Booking System
Спроектировать систему бронирования отелей для российского рынка.
Общее количество отелей в системе
Суммарное количество номеров
Функциональные требования
Просмотр информации
Детальная информация об отелях и номерах
Онлайн бронирование
Выбор дат и типа номера с оплатой
Оплата
Интеграция с платёжной системой
Отмена брони
Возможность отменить бронирование
Важное бизнес-требование: Overbooking до 10%
Система должна поддерживать овербукинг — возможность продать больше номеров, чем есть в наличии. Это стандартная практика в гостиничном бизнесе, так как часть броней отменяется или гости не приезжают (no-show).
Что вынесли за scope
Оценка нагрузки (Back of the Envelope)
Важно: Средняя нагрузка невелика, но будут значительные пики — сезонные распродажи, праздники, flash-sales. Система должна выдерживать нагрузку в 10-100 раз выше средней.
Public API
/v1/hotels/{hotel_id}Получение информации об отеле
/v1/hotels/{hotel_id}/rooms/{room_type_id}Получение информации о типе номера
/v1/reservationsСоздание бронирования
{
"hotel_id": "123",
"room_type_id": "456",
"start_date": "2024-03-15",
"end_date": "2024-03-20",
"guest_info": { ... }
}/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 для распределения
Ключевые выводы из интервью
Начинайте с уточняющих вопросов
Overbooking — критическое требование, которое кардинально меняет архитектуру. Без этого вопроса можно уйти не в ту сторону.
Итеративно улучшайте дизайн
Показали эволюцию от наивной модели Reservation к Inventory-based подходу. Интервьюер оценивает не финальный ответ, а ход мыслей.
Обосновывайте выбор стратегии конкурентности
Pessimistic vs Optimistic locking — классический trade-off. Важно объяснить, почему выбрали конкретный подход для данной нагрузки.
Думайте о масштабировании заранее
Даже если текущая нагрузка невелика, покажите понимание того, как система будет расти и какие стратегии применить.
