1. Проектирование системы: архитектура, выбор базы данных и протоколов передачи данных
Проектирование системы: архитектура, выбор базы данных и протоколов передачи данных
Добро пожаловать на курс «Разработка мессенджера: от архитектуры до деплоя». Это первая и фундаментальная статья, в которой мы заложим основу нашего будущего приложения. Написание мессенджера — это «классика» системного дизайна (System Design). Кажется, что задача проста: переслать текст от Алисы к Бобу. Но что происходит, когда Алиса и Боб находятся на разных континентах, у Боба плохой интернет, а одновременно с ними общаются еще миллион пользователей?
В этой статье мы разберем, как спроектировать систему, способную выдерживать высокие нагрузки, какие протоколы использовать для мгновенной доставки сообщений и где хранить петабайты истории переписки.
Оценка нагрузки и требований
Прежде чем писать код, необходимо понять масштаб задачи. В системном дизайне это называется Back-of-the-envelope estimation (расчеты на салфетке). Допустим, мы проектируем мессенджер, похожий на WhatsApp или Telegram.
Предположим следующие вводные данные: * DAU (Daily Active Users): 10 миллионов пользователей. * Каждый пользователь отправляет в среднем 20 сообщений в день. * Средний размер сообщения — 100 байт (только текст).
Рассчитаем объем входящего трафика сообщений в день ():
Где — объем данных в день, — количество пользователей (10 млн), — количество сообщений на пользователя (20), — размер сообщения (100 байт).
Подставим значения:
Это кажется немного, всего 20 ГБ текста в день. Однако, если мы добавим медиафайлы (фото, видео), нагрузка вырастет в сотни раз. Кроме того, нам нужно хранить историю за несколько лет. Для 5 лет хранения текстовых данных формула будет выглядеть так:
Где — общий объем хранилища, — объем данных в день (20 ГБ), — количество дней в году, — количество лет (5).
Эти расчеты показывают, что обычная база данных на одном сервере быстро переполнится. Нам нужна масштабируемая архитектура.
Высокоуровневая архитектура
Для современных высоконагруженных систем монолитная архитектура (когда весь код в одном приложении) подходит плохо. Мы выберем микросервисную архитектуру. Это позволит нам масштабировать отдельные части системы независимо друг от друга. Например, сервис отправки сообщений испытывает большую нагрузку, чем сервис регистрации пользователей.
Основные компоненты нашей системы:
!Высокоуровневая архитектура микросервисного мессенджера
Протоколы передачи данных
Как клиенту общаться с сервером? Самый очевидный вариант — HTTP. Но у него есть проблема: клиент всегда инициализирует запрос. Сервер не может просто так «постучаться» к клиенту и сказать: «Эй, тебе пришло сообщение».
Варианты решения:
Для нашего мессенджера мы выберем гибридный подход: * HTTP (REST API): Для действий, не требующих мгновенной реакции (регистрация, загрузка профиля, получение списка контактов, загрузка истории сообщений). * WebSocket: Исключительно для отправки и получения сообщений в реальном времени и статусов «печатает...».
Выбор базы данных
Выбор базы данных — критический этап. В мессенджере есть два принципиально разных типа данных:
1. Данные пользователей (Профиль, Друзья, Настройки)
Эти данные структурированы, меняются нечасто и требуют строгой согласованности (ACID). Нам важно, чтобы пользователь не мог зарегистрироваться дважды с одним email.* Выбор: Реляционная база данных (PostgreSQL или MySQL).
2. История сообщений (Chat Logs)
Здесь требования другие: * Огромный объем данных (как мы посчитали выше — терабайты). * Огромная скорость записи (Write-heavy workload). * Доступ обычно идет по ключу (ID чата) и сортировке по времени. * Реляционные связи не так важны.Обычный PostgreSQL начнет «тормозить» на таблице с миллиардами строк при вставке. Здесь идеально подходят NoSQL базы данных семейства Wide Column Store или Document Store.
* Выбор: Cassandra (или ее более быстрый аналог ScyllaDB) или MongoDB.
В индустрии для мессенджеров (Discord, Facebook Messenger) часто используют Cassandra из-за ее способности линейно масштабироваться при записи. Мы можем просто добавлять новые серверы, и кластер будет переваривать больше сообщений.
3. Эфемерные данные (Статус Online/Offline)
Эти данные меняются каждую секунду. Хранить их на диске — слишком медленно.* Выбор: Redis. Это база данных в оперативной памяти (In-Memory). Она работает молниеносно и поддерживает TTL (время жизни ключа), что удобно для статусов «онлайн».
Масштабирование базы данных: Шардинг
Даже самая мощная база данных имеет предел. Когда сообщений становится слишком много, мы применяем шардинг (sharding).
Шардинг — это разделение данных одной логической таблицы на несколько физических серверов (шардов). Для мессенджера логично шардировать данные по chat_id или user_id.
Формула выбора шарда () часто выглядит так:
Где — номер сервера (шарда), на который пойдут данные, — идентификатор (например, ID чата), — общее количество серверов, а — операция взятия остатка от деления.
Например, если у нас 4 сервера () и ID чата равен 10:
Значит, история этого чата будет храниться на сервере №2.
> «Преждевременная оптимизация — корень всех зол». > — Дональд Кнут
Однако в случае с архитектурой базы данных, о шардинге стоит подумать заранее, так как миграция данных на живой системе — это сложнейшая инженерная задача.
Итоговый стек технологий для курса
Подводя итог, в рамках этого курса мы будем строить систему на следующем стеке:
В следующей статье мы перейдем к настройке окружения и созданию базового каркаса приложения.