К основному содержимому
к интервью
Конспект интервью2023Fellow

Техническое интервью: Архитектурная секция

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

C++ Russia 20237 минут

Конспект сокращён относительно полного интервью; примеры и оценки передают опыт и позиции участников.

Основная линия материала
01

Шлагбаум, камера и границы системы

Формат объявили сразу: короткий список требований по ссылке, ограниченное время на то, чтобы придумать реализацию и обосновать выбранные решения, и разбор этих решений с интервьюером. Перед началом ведущий порекламировал телеграм-канал Александра с разборами книг, а затем назвал себя жертвой, расшарил экран и стал рисовать схему в коллаборативной среде. Александр уточнил, что парковка «не супер умная, а скорее со шлагбаумом»: есть какое-то количество мест и есть контроль въезда и выезда. Из нефункциональных требований кандидат зацепился за два: парковки в разных городах России и высокая доступность — значит, система заведомо распределённая и одним дата-центром не обойтись. Отдельно он отметил высокую конкурентность, то есть много пользователей. Конкретные rps договорились не обсуждать: сегодня нагрузка может быть и небольшой, но с ростом бизнеса она вырастет, поэтому масштабирование стоит заложить заранее.

Дальше кандидат резал объём. За скобки вынесли бэк-офис, где заводят новые парковки и оформляют документы, и процессинг платежей — им занимается кто-то другой. Внешней системой признали и контроль доступа: шлагбаум с камерой, которая считывает госномер. Проектировать её не стали, договорились принимать два события — машина заехала и машина выехала, а госномера достаточно для идентификации. Кандидат сознательно ввёл сильное допущение: машины не взлетают, попасть на парковку и покинуть её можно только мимо камеры, которая не ошибается. Саму парковку тоже упростили: план не рисуем, конкретное место не выдаём, для каждой парковки хранится только счётчик свободных мест — по сути семафор. Александр спросил, поддерживаем ли овербукинг, как в самолётах; решили, что точно нет, а пользователей считаем аккуратными, по одному месту на машину. Долгая работа в авиации сказывалась: места кандидат по привычке называл сидячими, как в самолёте.

02

Гео-индекс, семафор и отложенные события

Сценарий, до которого кандидат не дошёл, добавил интервьюер: смотреть интересно не на одну парковку, а на прямоугольник карты — торговый центр и всё вокруг него. Отсюда потребовался запрос «выдай ближайшие парковки сразу с количеством свободных мест» и гео-индекс по GPS-координатам. Александр заострил, что запрос выходит одновременно нагруженным и быстро меняющимся: человек двигает точку на карте и обновляет экран, а счётчики в это время меняются от чужих броней и въездов. Кандидат согласился: координаты парковок приложение может закэшировать — парковки появляются и исчезают редко; счётчики свободных мест кэшировать опасно, на чтение ещё можно обсуждать, на запись — ни в коем случае. Их сразу признали узким горлышком и оставили некэшируемыми. Естественным ключом партиционирования назвали те же координаты: близкие парковки лежат рядом, запрос «найди ближайшие» собирает данные из одной партиции, а синхронизировать счётчики между партициями не нужно.

Ядром решения стала атомарная операция: не «прочитать значение и записать на единицу меньше», а декремент, который не даёт уйти ниже нуля и при нуле возвращает отказ — в мобильном приложении это «извините, пока вы думали, все места забронированы». Отмену брони обрабатывают обратным инкрементом и удалением записи об ожидаемой машине. Для брони, не подтверждённой приездом за пятнадцать минут, кандидат завёл очередь отложенных сообщений — событий «на будущее», которые вычитываются с задержкой; перед снятием брони проверяется таблица приехавших, а пользователю уходит уведомление через вторую очередь. События от шлагбаума приходят отдельным потоком от системы контроля доступа и пишутся прямо в базу: car in подтверждает бронь, car out возвращает место в счётчик. При отказе вместе с ошибкой можно отдать обновлённый счётчик. С хранилищем кандидат определялся с оговорками: атомарные счётчики он точно помнил в MongoDB, семафорную семантику предлагал дописать скриптом на самой базе и честно признал, что отчасти выдаёт желаемое за действительное. На двух копиях счётчиков ради доступности время закончилось.

03

Разбор: PostgreSQL, гео-балансировка, читаемость схемы

На разбор осталось десять минут. Сильной стороной Александр назвал границы: кандидаты часто закапывают себя, соглашаясь сделать всё сразу, а здесь были выбраны интересные сценарии — взаимодействие с пользователем и с системой шлагбаумов. Он же снизил градус вокруг конкуренции за места: пока мест на парковке много, разобрать их одновременно маловероятно, жарко становится на последней паре мест и в утренние и вечерние пики. Главным пробелом оказалась сущность, о которой не говорили, — сами заказы; к ней Александр подвёл вопросом ещё до перерыва. Кандидат согласился и добавил booking history: весь поток событий пользователя со статусами, что получилось и что нет, практически только на запись, лог-ориентированное хранилище, подключённое к общей шине событий. Иронию он отметил сам: занимается data science и обычно упрекает других, что данных не собрали, а тут забыл спроектировать историческое хранилище.

Своё решение Александр строил иначе. Он взял бы реляционную базу — тот же PostgreSQL — с ограничением, не дающим счётчику уйти ниже нуля; напрягали бы его только одновременные изменения по одной и той же парковке. Нагрузку на чтение карты он снимал бы отдельной копией данных, соглашаясь на лаг: человек видит последнее место, переходит к бронированию и получает отказ. Гео-распределение, по его мнению, проще сделать на балансировке трафика по регионам присутствия — Москва и область, Петербург и Ленинградская область, Дальний Восток; никто не бронирует одновременно во Владивостоке и в Москве, хотя на стыках округов внутри Москвы вопросы остаются. Статусную модель заказа — создан, оплачен, приехал, пошёл отсчёт времени — он считал обязательной, а синхронные операции и события смешивал осознанно: инструмент выбирается под сценарий. В перерыве прозвучала и оценка схемы: без комментариев автора понять по ней происходящее почти невозможно. Читаемость входит в матрицу оценки кандидата, но за тридцать минут вместо привычных сорока пяти или часа Александр это в упрёк не ставил.

Выводы

Что стоит унести с собой

  1. 01Счётчик свободных мест — это семафор, а не число в таблице: без атомарного декремента, который отказывает на нуле, овербукинг приходит обычной гонкой запросов.
  2. 02Конкуренция за места не равномерна: пока мест много, борьбы нет — горячо становится на последней паре мест и в утренние и вечерние пики.
  3. 03Промежуточные таблицы система по ходу удаляет, поэтому историческое хранилище заказов проектируют сразу, а не достают статусы и аналитику задним числом.
  4. 04Гео-распределение не обязательно решать в базе: если сценариев «забронировать в двух регионах сразу» не бывает, трафик и данные локализуются на балансировке.

Источники