Получить доступ

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

SeniorЗадачи на проектирование
Ещё спрашивают так:
  • Как доставлять сообщения в реальном времени миллионам пользователей?
  • Как хранить историю переписки?
  • Как гарантировать порядок сообщений в чате?
Коротко

Клиенты держат постоянное соединение (WebSocket) с шлюзами; сообщение пишется в хранилище, шардированное по chat_id, получает порядковый номер в чате и доставляется онлайн-участникам через шлюзы, офлайн — пушем.

  • Порядок — номер сообщения внутри чата (последовательность на шард чата), а не время клиента
  • Идемпотентность отправки: клиентский id сообщения, повтор не создаёт дубль
  • Синхронизация после офлайна: «дай всё после номера N» по каждому чату

А ещё Реестр «пользователь → шлюз» в Redis; большие группы — отдельная стратегия рассылки

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

Требования: личные и групповые чаты (до тысяч участников), доставка онлайн за доли секунды, история, статусы «доставлено/прочитано», работа с нескольких устройств, офлайн и пуш-уведомления. Оценка: 50 млн активных в день, 40 сообщений на пользователя — 2 млрд в день (~25 000/с, пик ×3), 10 млн одновременных соединений.

Соединения. Клиенты держат WebSocket (или MQTT) со шлюзами — тонкими сервисами на event loop, по сотне тысяч соединений на узел. Шлюз регистрирует в Redis «пользователь/устройство → шлюз». Балансировщик L4, переподключение с отсрочкой и джиттером при выкатке шлюзов.

Отправка:

  1. клиент шлёт сообщение с client_msg_id (UUID) — для идемпотентности повторов;
  2. сервис сообщений проверяет права, назначает номер в чате (монотонный счётчик на чат — в шарде чата) и пишет в хранилище;
  3. подтверждение отправителю с номером;
  4. событие «новое сообщение» уходит в шину, сервис доставки находит шлюзы участников и отправляет; офлайн-устройствам — пуш (FCM/APNs).

Хранилище истории: запросы «последние N сообщений чата» и «после номера X» → wide-column (Cassandra, ScyllaDB) с ключом партиции chat_id (и бакетом по времени для очень больших чатов) и сортировкой по номеру; или шардированный PostgreSQL по chat_id. Медиа — в объектном хранилище, в сообщении — ссылка.

Порядок. Время клиента ненадёжно, время серверов расходится. Порядок внутри чата задаёт номер, выданный одним местом (лидер шарда чата). Между чатами порядок не нужен. Клиент показывает по номеру и дозапрашивает пропуски.

Доставка и синхронизация. Каждое устройство помнит последний полученный номер по каждому чату (или глобальный курсор «ящика» пользователя). После переподключения — «отдай всё новее курсора». Доставка онлайн — at-least-once с дедупликацией на клиенте по номеру.

Групповые чаты: до сотен участников — рассылка по участникам; для тысяч и каналов — не раскладывать в «ящики» каждого, а читать из чата (как fan-out on read в ленте), уведомлять только онлайн.

Статусы «доставлено/прочитано» — курсоры на участника и чат (последний прочитанный номер), обновляются пачками, не на каждое сообщение.

Ещё: сквозное шифрование меняет архитектуру (сервер не видит содержимое — поиск и модерация на клиенте), поиск по истории — отдельный индекс, лимиты на спам, хранение по закону.

Пример

send(chat=777, client_msg_id=a1b2, text="привет")
→ сервис сообщений (шард по chat 777): seq = 10 452 → INSERT messages(777, 10452, ...)
→ ack отправителю {seq: 10452}
→ Kafka "chat-events" → доставка: Redis route:user:42 → gateway-17 → WebSocket push
Офлайн-устройство при входе: GET /sync?chat=777&after=10431 → 21 сообщение

Что хотят услышать

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

Частые ошибки

  • Упорядочивать сообщения по времени клиента.
  • Хранить всю историю в одной таблице без ключа партиции по чату.

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем