LINUX.ORG.RU

Система личных сообщений

 


2

4

Привет всем!

Подскажите, пожалуйста, как устроена система личных сообщений между пользователями в крупных проектах (Вконтакте, Одноклассники, Topface и т.п) с учетом масштабирования? Интересует именно хранение данных о пользователях/чатах/сообщениях и доступ к этим данным.

Допустим у нас есть 100 000 000 пользователей и необходимо сделать горизонтальное масштабирование (шардинг) этих данных на 200 MySQL серверов. На данный момент, я вижу это следующим образом: разделяем всех пользователей и данные на 200 серверов по user_id, получается примерно 500 000 юзеров на каждый сервер. Можно еще разделить данные на споты по 1000 юзеров и получится, что на каждом сервере БД будет 500 спотов по 1000 юзеров (всего 500 000 юзеров на сервер).

Доступ к серверам БД/спотам можно вычислять по user_id, например spot_id = user_id % 1000. Каждый спот будет хранить данные в виде таблиц, например:

Spot1: - spot1_users (информация о пользователях) - spot1_chats (информация о чатах между пользователями) - spot1_messages (сообщения из чатов) ....

Spot2: - spot2_users - spot2_chats - spot2_messages .... Проблема возникает тогда, когда необходимо хранить/получать общие данные между юзерами. Например, 2 пользователя начинают переписку между собой. В этом случае необходимо создать чат в таблице spotN_chats и поместить туда информацию chat_id (id чата), receiver_id(id получателя), sender_id (id отправителя). Сообщения будут хранится в таблице messages (chat_id, message, time).

Теперь начинается самое интересное - пользователи начинают переписку между собой. Здесь необходимо сделать такие базовые операции: 1) Создание нового чата между 2 пользователями 2) Получение информации о чате или списке чатов конкретного пользователя 3) Создание нового сообщения 4) Получение списка сообщений по chat_id

Также есть 2 варианта развития событий: 1) пользователи находятся на одном споте (например, spot1); 2) пользователи находятся на разных спотах (например, spot1 и spot2);

Задача 1. Пользователь1 решил начать переписку с пользователем2. В этом случае необходимо создать новый чат в БД. Если пользователи на одном споте, то можно просто создать новый чат в таблице spot1_chats, получать chat_id, а дальше создавать новые сообщения в таблице spot1_messages с полученным chat_id. Но если пользователи находятся на разных спотах (spot1, spot2), то такой подход не будет работать, поскольку чтобы каждый пользователь увидел список своих чатов, то их нужно дублировать на 2 споты одновременно. Но в таком случае chat_id будут разными для 2 таблиц(spot1_chats, spot2_chats) если использовать поле autoincrement для chat или же нужно строить какой-нибудь общий для 100 млн. пользователей генератор id для новых чатов. Кроме того, если 2 пользователи на одном споте, то при дублировании чатов все равно будет создан только 1 чат в таблице spot1_users, а вот если мы решим перенести 1 пользователя на другой спот, то как дублировать информацию о чатах?

Задача 2. Пользователь1 отправляет сообщение пользователю2, chat_id у нас уже есть после создания нового чата. Здесь возникает та же самая проблема, что и в первой задаче. Если 2 пользователи на одном споте, то мы просто добавляем новое сообщение в таблицу spot1_messages, но если в будущем захотим перенести пользователя на другой спот, то как дублировать сообщения? Если же пользователи на разных спотах, то для отправки сообщения необходимо создать новое сообщение в таблице spot1_messages и в таблице spot2_messages. Кроме того, если мы хотим обновлять какой-нибудь счетчик новых сообщений или время последнего сообщения в чатах, то нужно будет также обновлять информацию о чатах в таблицах spot1_chats и spot2_chats. Получается для простой отправки одного сообщения необходимо будет сделать несколько запросов в БД, а именно: создать новое сообщения в таблицах spot1_messages и spot2_messages, а также обновить информацию о чате в таблицах spot1_chats и spot2_chats.

Подскажите, пожалуйта, как правильно решить данные задачи или возможно есть какой-то другой более простой/надежный способ хранения сообщений из реального опыта.

Спасибо.

Прочитал наискосок. Первое что бросилось в глаза - зачем пользователей шардить? Шардить нужно чаты. А учетки 100мл пользователей можно на одном сервере держать.

pi11 ★★★★★ ()
Ответ на: комментарий от pi11

учетки 100мл пользователей можно на одном сервере держать

Держать то можно, но нужно постоянно взаимодействовать с данными пользователей. Например, авторизировать, получать данные о профиле пользователя и т.п. Если в онлайне будет 2-3 млн пользователей и каждый пользователь начнет просматривать других пользователей, обновлять профили и т.п., то такая БД быстро загнется. Кроме того, это единая точка отказа + какой сервер нужен для 100 млн пользователей?

serious911 ()
Ответ на: комментарий от serious911

Во-первых на этом сервере только id и данные авторизации хранить + возможно информацию о шардинге данных (зависит от реализации), а профили тоже можно шардить уже. Во-вторых сервер средненький это потянет, если сервер падает то один из слейвов встает на его место. Да и, забыл добавить, чтение данных конечно можно со слейвов делать.

p.s. В реальности с такими задачами не работал, это я так с дивана вещаю просто =)

pi11 ★★★★★ ()
Последнее исправление: pi11 (всего исправлений: 4)
Ответ на: комментарий от anonymous

Во-первых на этом сервере только id и данные авторизации хранить + возможно информацию о шардинге данных

Такой сервер и бд у меня уже есть. Используется для последовательной генерации ID пользователей и хранения данных для авторизации (user_id, email, password...). Здесь будет мастер-слейв или мастер-мастер репликация.

Шардится будут именно данные о пользователях (профили), чаты, сообщения и т.п. То есть один сервер это не потянет.

serious911 ()
Ответ на: комментарий от serious911

Разумеется не потянет. Я же отвечал на вопрос про какой сервер нужен под хранение учетных записей.

User { Account, Profile, Messages, Files, etc.. }

Нет такой сущности, как пользователь в БД.

anonymous ()
Ответ на: комментарий от nihirash

Немного слышал о XMPP/jabberd, да и ВК вроде его когда-то использовали. Возможно стоит к нему присмотрется, но пока не вижу особого смысла. Сейчас использую вебсокеты/longpolling на бекенде + сообщения хранятся в MySQL. Пока этого достаточно, но нужно масштабировать именно хранение данных в БД.

serious911 ()

Где-то недавно видел статью вконтакта о системе их сообщений, кажется, там они писали как меняли технологии и переводили все на новую.

gruy ★★★★★ ()

у вконтакте там отдельные серваки, которые ajax-запросами долбят типа im123.vk.com. а что касается вконтакте у них key-value хранилище с дублированием данных: у кадого пользователя хранятся все переписки.

UPD: https://vk.com/blog/messages-database

tz4678 ★★ ()

100M — это не шибко много, тот же мускуль вполне выдержит. Не занимайся преждевременной оптимизацией.

Miguel ★★★★★ ()
Ответ на: комментарий от Miguel

Как ты собрался реализовать систему сообщений для 100м пользователей, если не считаешь количество этих сообщений у каждого пользователя. Не повторяй мантры бездумно.

anonymous ()

Выбирай быструю не реляционную базу данных, где и храни свой чаты. Что касается обработки событии - RabbitMQ и очереди тебе в помощь.

anonymous ()
Ответ на: комментарий от anonymous

Насчёт масштабирования - у пользователя поле, в какой БД хранится его служебная информация/список всех друзей и локация чатов с каждым. Ах, и да, как упомянули выше, чаты лучше дублировать - каждому пользователю свои записи. И про кэширование данных активного пользователя не забудь - не стоит из за повторяющейся мелочей базы тревожить.

anonymous ()
Ответ на: комментарий от anonymous

Спасибо за советы. Кеширование сейчас делаю в редисе.

чаты лучше дублировать

дублировать чаты на шарде/споте пользователя или что вы имеете в виду? Если дублировать, то возникает проблема с пользователями на одном или разных шардах (как описано в вопросе).

serious911 ()
Ответ на: комментарий от anonymous

Выбирай быструю не реляционную базу данных, где и храни свой чаты. Что касается обработки событии - RabbitMQ и очереди тебе в помощь.

MongoDB/Cassandra?

serious911 ()
Ответ на: комментарий от serious911

имелось в виду, что у тебя есть диалог с Васей Пупкиным. Так вот его сообщения хранятся у тебя (помимо твоих), а твои у него (помимо его).

tz4678 ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.