Курс «Архитектура мессенджера» · Часть 3 · Хранение и данные

Раздел 8. Где живут сообщения и как шардируются

Выбор БД; шардирование и по какому ключу (chatid против userid); durability и репликация; что значит «сообщение не потеряется».

Мы много раз говорили «сообщение сохраняется в базу». Пора разобраться, что это за база, почему её приходится резать на куски и как сделать, чтобы сохранённое действительно не пропало. Это первый по-настоящему «про данные» раздел.

Какая у хранилища нагрузка

Прежде чем выбирать базу, надо понять характер нагрузки — он определяет всё остальное. У сообщений он специфический:

  • Очень много записей. Сообщения постоянно добавляются — это основной поток (вспомни прикидку из Раздела 2: десятки и сотни тысяч в секунду).
  • Сообщения почти не редактируют. Написал — и всё; правки и удаления редки. Данные в основном дописываются в конец, а не меняются.
  • Чтение простое и предсказуемое. Самый частый запрос — «покажи последние сообщения этого чата», иногда — прокрутка истории вверх.
  • Объём растёт бесконечно. История копится годами и никуда не девается.

Запомни вывод: хранилище сообщений — это поток на запись с простым чтением по чату. Под это и подбирают базу.

Какую базу выбрать

Здесь всплывает классический выбор — SQL или NoSQL. Коротко, что это:

  • SQL (реляционная база) — данные в строгих таблицах со связями между ними, сильна в сложных запросах и строгой согласованности. Пример смысла: учёт пользователей, контактов, настроек.
  • NoSQL (нереляционная) — более простая и гибкая модель, заточенная под огромный объём и лёгкое расползание по многим серверам.

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

Но важная тонкость, которую ценят на интервью: это не выбор „или-или" на весь мессенджер. Для разных данных — разные базы. Сообщения — в NoSQL-стиле, а вот аккаунты, контакты, настройки (где важны строгие связи и согласованность) вполне живут в SQL. Правильная формулировка — «правильный инструмент под каждый тип данных».

Шардирование: режем данные на куски

Объём истории — это петабайты. На одну машину столько не влезет, да и поток записей одна машина не вытянет. Поэтому данные шардируют.

Шардирование — это разрезание данных на куски (их называют шарды) и раскладывание этих кусков по многим серверам, каждый кусок — на своём. Аналогия: одна гигантская тетрадь не помещается на полку, поэтому мы режем её на тома и расставляем тома по разным полкам.

По какому ключу резать: chat_id или user_id

Это главный вопрос раздела. Ключ шардирования — это признак, по которому решают, на какой сервер попадёт запись. От его выбора зависит, быстро ли потом читать.

По chat_id (по чату). Все сообщения одного чата лежат вместе, на одном шарде.

  • Плюс: главный запрос — «последние сообщения этого чата» — это обращение к одному серверу. Быстро и эффективно.
  • Минус: огромный публичный чат или канал создаёт «горячий шард» — вся нагрузка от него валится на один сервер, пока остальные простаивают.

По user_id (по пользователю). Данные раскидываются по людям.

  • Сложность: у сообщения двое участников — отправитель и получатель. На чьём шарде хранить чат? Чтение переписки может потребовать собирать данные из разных мест.

На практике чаще шардируют по чату (chat_id или conversation_id): главный паттерн доступа — «сообщения одного чата», и их выгодно держать вместе. А проблему горячих чатов-гигантов решают отдельно — например, особой обработкой каналов (Раздел 11).

Общий принцип, который стоит проговорить: ключ шардирования выбирают под главный паттерн чтения и так, чтобы нагрузка распределялась равномерно (без горячих точек).

Durability: чтобы «не потерялось»

Durability — это надёжность хранения: гарантия, что записанное не пропадёт, даже если сервер упадёт или перезагрузится. Именно это мы имели в виду под «сообщение не потеряется».

Как её добиваются — через репликацию: каждое сообщение записывают не на один сервер, а копируют на несколько (эти копии называют репликами). Аналогия: важную страницу не держат в одном экземпляре, а делают несколько фотокопий и раскладывают по разным полкам — сгорит одна, останутся другие.

Ключевой момент: запись считается успешной не когда она легла на один диск, а когда её подтвердили несколько реплик. Только после этого система говорит Алисе «отправлено» (вот откуда берётся та самая галочка из Раздела 4 — она появляется после надёжного сохранения, а не раньше).

Здесь есть компромисс: чем большего числа реплик ждём перед подтверждением, тем надёжнее, но медленнее. Баланс между скоростью и сохранностью настраивают под задачу.

Вопросы интервьюера (с разбором)

«Где и как хранятся сообщения?» Образец: «В отдельном хранилище, заточенном под нагрузку „много записей, простое чтение по чату, бесконечный рост". Сообщения в основном дописываются и почти не редактируются, поэтому база оптимизирована под добавление. Данные шардированы по многим серверам и реплицированы для надёжности.»

«Что шардируем и по какому ключу?» Образец: «Шардируем историю сообщений, чаще всего по идентификатору чата. Так все сообщения одного чата лежат вместе на одном шарде, и главный запрос — последние сообщения чата — бьёт в один сервер. Ключ шардирования выбираю под главный паттерн чтения и ради равномерной нагрузки. Минус — горячий шард на чатах-гигантах, его решаю отдельно, особой обработкой больших каналов.»

«Как гарантируешь durability?» Образец: «Репликацией: каждое сообщение пишется сразу на несколько серверов-копий, и запись считается успешной только после подтверждения от нескольких из них — тогда отправителю и показывается „отправлено". Чем больше реплик ждём, тем надёжнее, но медленнее, — этот баланс настраивается.»

«SQL или NoSQL для истории — и почему?» Образец: «Для истории сообщений — хранилище в стиле NoSQL, потому что нагрузка с огромным потоком записей и бесконечным ростом отлично ложится на горизонтальное масштабирование. Но это не выбор на весь продукт: аккаунты и контакты, где важны строгие связи и согласованность, спокойно живут в SQL. Правильный инструмент под каждый тип данных.»


#мессенджер #хранение #шардирование #репликация #durability #sql-nosql #подготовка-к-интервью