Как хранить чат в базе данных
Перейти к содержимому

Как хранить чат в базе данных

  • автор:

Структура хранения сообщений чата в базе данных [закрыт]

Хотите улучшить этот вопрос? Переформулируйте вопрос так, чтобы на него можно было дать ответ, основанный на фактах и цитатах.

Закрыт 6 лет назад .

Собственно, вопрос навеян другим вопросом. Заключается в следующем. Какой оптимальный способ хранения сообщений чата? Может быть лучше их сохранять вообще просто в файл (ведь обращение к старым практически исключено, а вычитка последних может идти и из оперативной памяти)? Или может быть лучше (как в упомянутом вопросе) рассматривать хранение сообщений в базе в виде JSON-строк за определенный период времени? А может все-таки лучше их хранить в базе в виде «одно сообщение — одна строка» и при этом все данные расположены по полям? Какие еще есть варианты? Какие у этих вариантов (и других) плюсы и минусы?

Хранение в JSON данных за день/месяц/год:

+Легко отдавать данные за период

-Отсутствует возможность поиска

-Увеличение размера хранимых данных

-Большой объём передаваемых данных

-Усложнение системы хранения данных (сначала нужно хранить где то данные за период, потом переносить в базу)

Хранение в файлах данных за день/месяц/год:

+Легко отдавать данные за период

-Отсутствует возможность поиска

-Увеличение размера хранимых данных

-Большой объём передаваемых данных

-Усложнение системы хранения данных (сначала нужно хранить где то данные за период, потом переносить в файл)

Хранение в базе:

+Легко отдавать данные за период

+Стандартные возможность поиска

+Передаём только нужные данные

-Хранятся актуальные и старые сообщения

В лучшую сторону ничего не изменится если Вы будете хранить сообщения в JSON.

  • Места занимает столько же, а то и больше.
  • Теряется возможность запросов. Нельзя будет сделать сложных запросов.
  • Передавать данные сложнее. (Кто то очень активный наобщается на 10 метров и будете Вы на клиент их передавать).

Хранить в файлах историю по дням можно, но тоже не особо что то поменяет.

Вы боитесь что если у Вас будет несколько миллионов записей, то у Вас скорость запросов упадёт при обычном селекте? Это не так доступ же линейный.

А по всему остальному в чём разница — хранить в базе или в файлах? Что то что то место занимает.

Лучше чем просто в базе ещё вроде не придумали.

Mihanik71's user avatar

Если вы будете хранить сообщения в файлах, вам придется решить несколько вопросов:

  • один файл или много.
  • если один файл, как обеспечить многопоточную запись.
  • как индексировать записи
  • если много файлов — как быть с файловой системой? сколько этих файлов, сколько места на жестком диске потеряется? Как индексировать записи, как обеспечить многопоточную запись в кучу файлов?

если вы будете хранить сообщения в файлах, то вы не будете этого делать. Ну или напишете, фактически, через год-два, свою собственную базу данных. Скорее всего очень медленную и плохую. Если ваш стартапик при этом не лопнет — задача решена!

Если хранить сообщения в SQL БД, упаковывая все поля в JSON, вы изобретете знаменитый (вру) двойной велосипед, вы будете хранить неструктурированные данные в RDBMS. Все будет очень медленно и плохо. Практически единственным способом поиска для вас будет оператор LIKE, индексы в данном случае не имеют смысла, все будет ОЧЕНЬ, ОЧЕНЬ плохо.

Выбор между NoSQL или SQL делайте сами, но, в любом случае и те и другие хранят поля документа/таблицы раздельно.

Очень советую почитать немножко про базы данных в целом.

P.S. представьте себе данные типа

превратим это в json-строку:

вторая строчка длиннее. В базе данных это будет выглядеть скорее так: покемон,vorobusheq,ei ti c индексом на смещения в файлах базы данных

БД для хранения сообщений чата, какую выбрать?

Добрый день, делаю проект на 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млн записей?

Name already in use

alt text

alt text

  • если ресайзим таблицу с помощью консистентного хеширования, то должны отремапить только часть ключей (K/n).
  • K — число ключей, n — число слотов
  • у нас 2^160 — слотов, node (1-4) — физические ноды = машины
  • каждая физическая машина будет держать несколько виртуальных нод
  • партиция = слот, и к какой машине этот слот привязан
  • у каждой машины по 8 партиций
  • если какая-то машина переполнена, то можно перемапить какаую-то партицию и она будет на другой машине

alt text

  • пишем на 3 последовательные партиции и это будут реплики
  • мы знаем, что ключ попадает в первую партицию, но запишем ещё в 2 следующие партиции
  • так как машины чередуются, то информация будет на разных машинах
  • когда ищем ключ, идём в первую партицию, эта машина оффлайн, но знаем, что было 3 реплики, идём на следующую машину по кольцу и вынимаем значение
  • на всех репликах должна храниться одна и та же информация
  • сообщение отправленное от клиента1 клиенту2 должно быть отмечено у клиента2, как «принятое», а клиента1, как «отправленное»
  • каждый клиент имеет доступ к отправленным/полученным сообщениям от других клиентов
  • запись/изменение данных либо во все реплики, либо ни в одну

P — partition tolerance

  • расщепление распределённой системы на несколько изолированных секций не приводит к некорректности отклика от каждой из секций

В данном случае мы жертвуем доступностью, то есть если у нас что-то не отвечает, то ждём пока не придёт ответ. Если всё хорошо, то пишем во все реплики.

  • Метод отправки сообщения
Параметр Описание
chatID номер конкретного диалога
textMessage текст сообщения
stringInfo информация об отправке
  • Метод удаления сообщения из диалога
Параметр Описание
messageID номер сообщения, которое удаляем
  • Метод создания нового диалога
Параметр Описание
listClientsID список ID участников
  • Метод удаления определённого диалога
Параметр Описание
chatID номер диалога, который удаляем
  • Метод добавления клиента(ов) в определённый диалог
Параметр Описание
chatID номер диалога, в который добавляем клиентов
listClientsID список ID клиентов, которых добавляем в диалог
  • Метод удаления клиента(ов) из оперделённого диалога
  • Метод добавления вложения(документа) в диалог
  • Метод удалиения вложения в диалог
  • Метод регистрации клиента
Параметр Описание
login логин клиента
password пароль клиента
Параметр Описание
statusMessage true-зарегистрирован, false-нет

API, которое реализовали

  • Метод отправки сообщения
Параметр Описание
chatID номер конкретного диалога
textMessage текст сообщения
stringInfo информация об отправке
  • Метод создания нового диалога
Параметр Описание
listClientsID список ID участников
  • Метод удаления сообщения по ID из всех диалогов
Параметр Описание
messageID номер сообщения, которое удаляем
  • Метод регистрации клиента
Параметр Описание
login логин клиента
password пароль клиента
Параметр Описание
statusMessage true-зарегистрирован, false-нет
  • Поплавков Михаил
  • Медведев Михаил
  • Тузов Григорий

Схема с двумя бд

  • в одной базе данных — «СООБЩЕНИЯ» храним сообщения, в другой — «OTHERS» всё остальное (users, chats, users_chats)
  • нет целостности по сообщениям: схема допускает то, что в сообщении может быть ссылка на несуществующего пользователя или чат, то есть на сообщение не накладывается никаких дополнительных ограничений
  • таким образом можем выполнить шардирование, то есть разделить базу данных «СООБЩЕНИЯ» на несколько шардов
  • если происходит измениние в любой таблице из «OTHERS» затрагивающее бд, в которой хранятся сообщения, то отправляем запрос в эту бд и записываем его в лог, а также ждём ответ, чтобы убдеиться, что всё хорошо. Если бд упала, тогда после восстановления смотрим в лог и отправляем те запросы, которые были отправлены, но не были выполнены. (или по истечению заданного таймаута отправляем повторные запросы)
  • как вариант, старые сообщения можно перенести на дешёвую машину, обладующую малыми мощностями (старые сообщения — к ним редко идут запросы)

База данных с сообщениями

База данных с остальными таблицами

Footer

© 2023 GitHub, Inc.

You can’t perform that action at this time.

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.

Проектируем систему сообщений в стиле Facebook

В этом посте мы постараемся разобраться, как организовать систему общения между пользователями в стиле Facebook.

Структура БД

Для данной системы нам понадобится всего три таблицы: Users, Conversation и Conversation_Reply.

Таблица пользователей

В данной таблице должна храниться вся информация о зарегистрированных пользователях.

Данный будут храниться в следующем виде; пароль должен хешироваться с помощью md5.

Таблица диалогов

Данная таблица хранит информацию о диалогах пользователей. Поля user_one и user_two являются внешними ключами к полю users.user_id.

Система ответов

Содержит все ответы на сообщения пользователей. Тут user_id_fk — это внешний ключ к полю users.user_id; и c_id_fk — внешний ключ для поля conversation.c_id

Списки далогов

Тут используем отношения таблиц users и conversation. К таблице users будем обращаться по алиасу U, а к conversation по алиасу C . В данном листинге user_one = ’13’ и user_two=’13’ относятся к таблице users и значению поля user_id.

Последние сообщения диалога

Выводим содержимое ответов на диалог с c_id=’2′ из таблицы conversation_reply.

Выводим все диалоги пользователя arun:

Обновление диалога

Используем отношение между таблицами и users и conversation_reply. К таблице users будет обращаться по алиасу U, а к conversation_reply по алиасу R . В данном листинге c_id_fk = ‘2’ относится к таблице convesation и значению поля c_id.

Обновление диалога

Используем отношение между таблицами и users и conversation_reply. К таблице users будет обращаться по алиасу U, а к conversation_reply по алиасу R . В данном листинге c_id_fk = ‘2’ относится к таблице convesation и значению поля c_id.

Показать сообщения диалога с c_id=2.

Проверка существования диалога

Следующий запрос проверяет наличие диалога.

Создание диалога

Вставка ответа

Данный урок подготовлен для вас командой сайта ruseller.com
Источник урока: http://www.9lessons.info/2013/05/message-conversation-database-design.html
Перевел: Станислав Протасевич
Урок создан: 17 Сентября 2013
Просмотров: 33393
Правила перепечатки

5 последних уроков рубрики «PHP»

Фильтрация данных с помощью zend-filter

Когда речь идёт о безопасности веб-сайта, то фраза "фильтруйте всё, экранируйте всё" всегда будет актуальна. Сегодня поговорим о фильтрации данных.

Контекстное экранирование с помощью zend-escaper

Обеспечение безопасности веб-сайта — это не только защита от SQL инъекций, но и протекция от межсайтового скриптинга (XSS), межсайтовой подделки запросов (CSRF) и от других видов атак. В частности, вам нужно очень осторожно подходить к формированию HTML, CSS и JavaScript кода.

Подключение Zend модулей к Expressive

Expressive 2 поддерживает возможность подключения других ZF компонент по специальной схеме. Не всем нравится данное решение. В этой статье мы расскажем как улучшили процесс подключение нескольких модулей.

Совет: отправка информации в Google Analytics через API

Предположим, что вам необходимо отправить какую-то информацию в Google Analytics из серверного скрипта. Как это сделать. Ответ в этой заметке.

Подборка PHP песочниц

Подборка из нескольких видов PHP песочниц. На некоторых вы в режиме online сможете потестить свой код, но есть так же решения, которые можно внедрить на свой сайт.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *