Структура хранения сообщений чата в базе данных [закрыт]
Закрыт. На этот вопрос невозможно дать объективный ответ. Ответы на него в данный момент не принимаются.
Хотите улучшить этот вопрос? Переформулируйте вопрос так, чтобы на него можно было дать ответ, основанный на фактах и цитатах.
Закрыт 7 лет назад .
Собственно, вопрос навеян другим вопросом. Заключается в следующем. Какой оптимальный способ хранения сообщений чата? Может быть лучше их сохранять вообще просто в файл (ведь обращение к старым практически исключено, а вычитка последних может идти и из оперативной памяти)? Или может быть лучше (как в упомянутом вопросе) рассматривать хранение сообщений в базе в виде JSON-строк за определенный период времени? А может все-таки лучше их хранить в базе в виде «одно сообщение — одна строка» и при этом все данные расположены по полям? Какие еще есть варианты? Какие у этих вариантов (и других) плюсы и минусы?
Отслеживать
задан 25 июл 2016 в 20:38
user212277 user212277
Если вам дан исчерпывающий ответ, отметьте его как верный (галочка напротив выбранного ответа)
25 июл 2016 в 21:34
@Mihanik71 Несомненно, так и поступлю. Но не ранее, чем отвечающие начнут читать вопрос и отвечать по существу вопроса.
– user212277
26 июл 2016 в 8:06
Укажите какими средствами делается серверная часть. И какую БД вы имеете ввиду. Если реляционную — отдельная строка на сообщение, без вариантов. Если документарную или около того — то видимо JSON или как там она документ хранит. С файлами — в определенных случаях можно сделать оптимально, но объем работы на пару порядков выше.
26 июл 2016 в 8:21
@Mike Прочитайте вопрос. Ведь черным по белому написано: как лучше хранить сообщения чата? Может лучше вообще без базы? Причем здесь Ваши комментарии по поводу базы данных? Причем здесь непосредственно JSON, если я в вопросе написал, что это как вариант, а как другой вариант — традиционное сохранение в базе по строкам и полям. Какая разница при этом какими средствами делается серверная часть? Есть средства, которые позволят ее сделать, но не позволят использовать базу данных или файловую систему?
– user212277
26 июл 2016 в 8:28
Очень хотелось бы уточнить у тех, кто требует правки, как можно отредактировать простой вопрос:Какой оптимальный способ хранения сообщений чата?И да.Ну очень много ответов может быть основано сугубо на чьем-то мнении. Вот их бы и хотелось услышать. Но услышать мнения по существу вопроса, а не ответы о том, как данные из базы будут потом плохо читаться.В вопросе указано, что это чат (не мессенджер) и читаться сообщения не будут.Ответов по существу нет, несмотря на разжеванный вопрос?Как, уважаемые, господа-товарищи вы предлагаете его переформулировать?Может прочтете его внимательно для начала?
– user212277
26 июл 2016 в 8:55
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
Хранение в JSON данных за день/месяц/год:
+Легко отдавать данные за период
-Отсутствует возможность поиска
-Увеличение размера хранимых данных
-Большой объём передаваемых данных
-Усложнение системы хранения данных (сначала нужно хранить где то данные за период, потом переносить в базу)
Хранение в файлах данных за день/месяц/год:
+Легко отдавать данные за период
-Отсутствует возможность поиска
-Увеличение размера хранимых данных
-Большой объём передаваемых данных
-Усложнение системы хранения данных (сначала нужно хранить где то данные за период, потом переносить в файл)
Хранение в базе:
+Легко отдавать данные за период
+Стандартные возможность поиска
+Передаём только нужные данные
-Хранятся актуальные и старые сообщения
В лучшую сторону ничего не изменится если Вы будете хранить сообщения в JSON.
- Места занимает столько же, а то и больше.
- Теряется возможность запросов. Нельзя будет сделать сложных запросов.
- Передавать данные сложнее. (Кто то очень активный наобщается на 10 метров и будете Вы на клиент их передавать).
Хранить в файлах историю по дням можно, но тоже не особо что то поменяет.
Вы боитесь что если у Вас будет несколько миллионов записей, то у Вас скорость запросов упадёт при обычном селекте? Это не так доступ же линейный.
А по всему остальному в чём разница — хранить в базе или в файлах? Что то что то место занимает.
Лучше чем просто в базе ещё вроде не придумали.
Проектирование архитектуры базы данных для чата
Как вообще, должен работать чат. У вас есть пользователи, которые могут общаться в чате. Чат может состоять из нескольких групп (таблица chat), по сути, из отдельных чатов в каждом из которых могут общаться пользователи (таблица party). Сообщения каждого чата добавляются (таблица messages) от участников чата, которым можно показывать уведомления о добавлении новых сообщений и проверять, какие сообщения пользователь уже прочитал (таблица message_status).
Полагаю, что у вас уже есть таблица users, в которой хранятся пользователи.
Таблица со списком групп чата
В таблице со списком групп чата будут храниться данные группах чата. Таблица выглядит следующим образом:
| Наименование | Описание |
| chat_id | порядковый id чата |
| name | заголовок чата, его название |
| user_id | id пользователя создавшего чат |
Таблица со списком участников чата
В таблице списка участников чата будет храниться связь между группой чата и пользователями, которые участвуют в беседе группы чата. Таблица выглядит следующим образом:
| Наименование | Описание |
| chat_id | id группы чата |
| user_id | id пользователя, который учавствует в переписке чата |
Таблица со списком сообщений
В таблице со списком сообщений будут храниться сообщения, которые пользователи пишут друг другу в чате. Таблица выглядит следующим образом:
| Наименование | Описание |
| message_id | порядковый id сообщения |
| chat_id | id чата |
| user_id | id пользователя, который добавил сообщение |
| contect | содержимое сообщения |
| date_create | дата добавления сообщения |
Таблица со статусами сообщений
В таблице со статусами сообщений будут храниться статусы уведомлений, определяющих просмотрел ли определенный пользователь новое добавленное сообщение. Таблица выглядит следующим образом:
| Наименование | Описание |
| message_id | id сообщения |
| user_id | id пользователя |
| is_read | прочитано ли сообщение |
Доводилось ли вам создавать чат для своего сайта? Если да, то какая архитектура в нем используется?
Система личных сообщений
Подскажите, пожалуйста, как устроена система личных сообщений между пользователями в крупных проектах (Вконтакте, Одноклассники, 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.
Подскажите, пожалуйта, как правильно решить данные задачи или возможно есть какой-то другой более простой/надежный способ хранения сообщений из реального опыта.
БД для хранения сообщений чата, какую выбрать?
Добрый день, делаю проект на Yii2, в нем уже реализован чат на комет сервере чат уже полностью работает, пользователи могут общаться только в приватных беседах т.е. только 2 пользователя друг с другом. При отправке сообщения, оно улетает аяксом в php скрипт, валидируется по определенным правилам и если все ок, записывает в таблицу бд и возвращает успех на клиентскую часть после чего уже сообщение попадает в окошко чата.
Структура бд:
tbl_dialog:
dialog_id — id Диалога
dialog_one_user_id — id первого юзера
dialog_two_user_id — id второго юзера
dialog_time — время создания диалога
tbl_message
chat_messages_id — id сообщения
chat_messages_text — текст сообщения
chat_messages_fk_dialog_id — id Диалога к которому относится сообщение
chat_messages_fk_user_id — id отправителя
chat_messages_fk_to_user_id — id получателя
chat_messages_ip — ip отправителя
chat_messages_isRead — прочитано ли сообщение получателем
chat_messages_isVisible_one_user — видимость сообщение для первого юзера
chat_messages_isVisible_two_user — видимость сообщение для первого юзера (для возможности отчисти сообщений, если просто удалять тогда сообщение пропадет из истории у обоих юзеров)
chat_messages_time — время отправки сообщения
Вся система работает с бд MySQL — InnoDB, сообщения пишутся в бд при каждой отправке (INSERT), пока сервис еще не запущен, сообщений мало (только мои тестовые) все работает шустро, но вот когда запущу и количество сообщений перевалит за несколько миллионов, что будет тогда с моей бд? Начнутся жесткие тормоза при select и insert?
Вот пока не поздно думаю стоит ли переписывать хранение сообщений на другую NoSQL БД, с ними не работал никогда, почитал доки и на первый взгляд ничего сложного.
В голове вертятся 2 варианта реализации:
1) перевести табличку tbl_message в коллекцию MongoDB и так же писать туда сообщения при каждой отправке (т.е. пользователь отправил 1 сообщение и мы его сразу в бд записали, по одной записи делать буду и так каждое сообщение). Как Mongo будет вести себя при вставке сообщения, когда в коллекции будет за 20 млн записей? Правильная ли эта схема?
1) Записывать каждое сообщение в память в виде массива сообщений (memcached или redis или еще что то — посоветуйте) и по крону допустим каждую минуту или 5 мин брать весь массив сообщений, писать через транзакцию в MySQL, далее чистим массив сообщений для новых записей. Так получается что не будет несколько инсертов в секунду, т.к. сообщения будут храниться в памяти. Но тут опять засада, сможет ли MySQL нормально работать с огромной таблицей 20млн записей?
Сам текст сообщений очень короткий, что то типа «Привет! Как дела?»
- Вопрос задан более трёх лет назад
- 17752 просмотра
3 комментария
Средний 3 комментария
