Побудова системи повідомлень [закрита]


170

Я на початку створення системи повідомлень у стилі Facebook для нашої сторінки (тип соціальних ігор), і зараз я досліджую, що було б найкращим способом розробити таку систему. Мене не цікавить, як надсилати сповіщення користувачеві або щось подібне (поки що навіть). Я досліджую, як побудувати систему на сервері (як зберігати сповіщення, де їх зберігати, як їх отримати тощо).

Отже ... деякі вимоги, які ми маємо:

  • у пік ми маємо близько 1 тис. одночасних користувачів, які ввійшли (та ще багато гостей, але вони тут не мають значення, оскільки вони не матимуть сповіщень), що призведе до багатьох подій
  • будуть різні типи сповіщень (користувач A додав вас як друга, користувач B прокоментував ваш профіль, користуваче C сподобалось ваше зображення, користувач D побив вас у грі X, ...)
  • більшість подій генерують 1 сповіщення для 1 користувача (користувачеві X сподобалось ваше зображення), але трапляються випадки, коли одна подія генерує багато сповіщень (наприклад, день народження користувача Y)
  • повідомлення повинні бути згруповані разом; якщо, наприклад, чотирьом різним користувачам подобається якесь зображення, власник цього зображення повинен отримати одне повідомлення про те, що чотирма користувачам зображення сподобалось, а не чотири окремих повідомлення (як це робить FB)

Добре, тому я думав, що я повинен створити якусь чергу, де я б зберігав події, коли вони відбудуться. Тоді я мав би фонову роботу ( карусель ?), Який би дивився на цю чергу і генерував сповіщення на основі цих подій. Потім ця робота зберігатиме сповіщення в базі даних для кожного користувача (тому, якщо подія стосується 10 користувачів, буде 10 окремих сповіщень). Тоді, коли користувач відкриє сторінку зі списком сповіщень, я прочитав би всі ці сповіщення для нього (ми думаємо обмежити це до 100 останніх повідомлень) і згрупувати їх разом, а потім нарешті відобразити їх.

Що мене турбує цей підхід:

  • складний як чорт :)
  • тут найкраща сховище для бази даних (ми використовуємо MySQL) або я повинен використовувати щось інше (redis теж здається непоганим)
  • що я повинен зберігати як сповіщення? ідентифікатор користувача, ідентифікатор користувача, який ініціював подію, тип події (щоб я міг їх згрупувати і відобразити відповідний текст), але тоді я начебто не знаю, як зберігати фактичні дані сповіщення (наприклад, URL-адреса та назва зображення, яке сподобалось). Чи потрібно просто "запікати" цю інформацію, коли я генерую повідомлення, або я повинен зберігати ідентифікатор запису (зображення, профілю, ...), який впливає, і витягувати інформацію з БД під час відображення сповіщення.
  • продуктивність повинна бути в порядку, навіть якщо мені доведеться обробляти 100 сповіщень під час відображення сторінки сповіщень
  • можлива проблема продуктивності для кожного запиту, оскільки мені доведеться відображати кількість непрочитаних повідомлень користувачеві (що може бути проблемою, оскільки я б групував сповіщення разом). Цього можна уникнути, хоча якби я створив перегляд сповіщень (там, де вони згруповані) у фоновому режимі, а не під час руху

Отже, що ви думаєте про моє запропоноване рішення та мої проблеми? Будь ласка, прокоментуйте, якщо ви думаєте, що я повинен зазначити щось інше, що було б актуальним тут.

О, ми використовуємо PHP для своєї сторінки, але це не повинно бути великим фактором тут.


Скільки часу вам знадобилося створити цю систему сповіщень як зусиль одного чоловіка. Я просто хочу мати оцінку, щоб зробити терміни відповідно.
Шахаряр

@Shaharyar Я думаю, це залежить від складності системи сповіщень.
Тянь

Я використовував ту саму систему з MySQL для створення системи пріоритетів на основі пріоритету. Хороша річ у тому, що він масштабує кілька тисяч користувачів, якщо більше, ніж це, то підірває, спеціально для Android та GCM. Я хотів би знати такі альтернативи MySQL, як redis, rabbitMQ, Kafka, які, природно, містять чергу повідомлень, тип функціональності.
Анкіт Маротхі

Відповіді:


168

Повідомлення про те, що щось (об'єкт = подія, дружба ..) змінюється (дієслово = додається, запитується ..) кимось (актором) і повідомляється користувачеві (темі). Ось нормалізована структура даних (хоча я використовував MongoDB). Вам потрібно повідомити певних користувачів про зміни. Отже, це сповіщення від користувачів. Це означає, що якщо було залучено 100 користувачів, ви генеруєте 100 сповіщень.

╔═════════════╗      ╔═══════════════════╗      ╔════════════════════╗
║notification ║      ║notification_object║      ║notification_change ║
╟─────────────╢      ╟───────────────────╢      ╟────────────────────╢
║ID           ║—1:n—→║ID                 ║—1:n—→║ID                  ║
║userID       ║      ║notificationID     ║      ║notificationObjectID║
╚═════════════╝      ║object             ║      ║verb                ║
                     ╚═══════════════════╝      ║actor               ║
                                                ╚════════════════════╝

(Додайте часові поля, де вважаєте за потрібне)

Це в основному для групування змін по об'єкту, щоб ви могли сказати "У вас є 3 запити друзів". І групування за актором є корисним, так що ви можете сказати, що "Користувач Джеймс Бонд вніс зміни у вашому ліжку". Це також дає можливість перекладати та рахувати сповіщення як завгодно.

Але, оскільки об’єкт - це лише ідентифікатор, вам потрібно буде отримати всю додаткову інформацію про об'єкт, який ви хочете, за допомогою окремих викликів, якщо об'єкт насправді не зміниться і ви хочете показати цю історію (наприклад, "користувач змінив назву події на ... ")

Оскільки сповіщення близькі до реального часу для користувачів на сайті, я б зв'язав їх із клієнтом nodejs + websockets з php, що підштовхує оновлення до nodejs для всіх слухачів, коли зміни додаються.


1
noti_object.object ідентифікує тип зміни, як рядок "дружба". Фактична посилання на змінений об'єкт із додатковими даними, про які я говорю, знаходиться в
noti_change.notificationObjectID

2
Це може бути тупим питанням, але з цим налаштуванням, що робити, коли користувач побачив або діяв у сповіщенні? Ви просто видалите його з бази даних або просто використовуєте дати, щоб побачити, чи користувач увійшов у систему з моменту створення повідомлення?
Jeffery Mills

4
Я знаю, що ця тема вже досить стара, однак я трохи спантеличений щодо першої таблиці, яка конкретно мета цієї таблиці? в чому полягає перевага в тому, щоб це було окремою таблицею порівняно з тим, щоб вказати користувальницький номер ідентифікатора в таблицю_об'єктів сповіщень? Іншими словами, коли ви створите новий запис у сповіщенні та коли ви просто додасте об’єкт та змінитесь до наявного сповіщення за допомогою цієї структури?
Bas Goossen

3
@JefferyMills Ви можете мати поле статусу, як is_notification_readу notificationтаблиці, і правильно позначити його, якщо воно є unread, readабо deleted.
Кевін

2
Я також намагався зрозуміти деякі аспекти цього рішення і поставив окреме запитання щодо нього: dba.stackexchange.com/questions/99401/…
user45623

27

Це справді абстрактне запитання, тому я думаю, що нам просто доведеться обговорити це, а не вказувати, що ви повинні чи не повинні робити.

Ось що я думаю про ваші проблеми:

  • Так, система сповіщень є складною, але не настільки пекла. Ви можете мати багато різних підходів до моделювання та впровадження таких систем, і вони можуть мати від середнього до високого рівня складності;

  • Іноді я завжди намагаюся робити речі, керовані базами даних. Чому? Тому що я можу гарантувати повний контроль над усім, що відбувається - але це тільки я, ви можете мати контроль без підходу, керованого базою даних; повірте, ви хочете контролювати цю справу;

  • Дозвольте пояснити реальний випадок для вас, щоб ви могли почати звідкись. У минулому році я моделював та впроваджував систему сповіщень у якійсь соціальній мережі (звичайно, не як у facebook). Як я зберігав сповіщення там? У мене була notificationsтаблиця, де я зберігав generator_user_id(ідентифікатор користувача, який генерує сповіщення), target_user_id(вид очевидний, чи не так?), notification_type_id(Що посилається на іншу таблицю з типами сповіщень), і все що необхідні речі нам потрібні для заповнення наших таблиць (часові позначки, прапори тощо). У моїй notification_typesтаблиці раніше було відношення до notification_templatesтаблиці, в якій зберігалися конкретні шаблони для кожного типу сповіщень. Наприклад, у мене був POST_REPLYтип, який мав вигляд шаблону, як, наприклад{USER} HAS REPLIED ONE OF YOUR #POSTS . Звідти я щойно лікував{}як змінна та #як опорна ланка;

  • Так, продуктивність повинна і повинна бути нормальною. Коли ви думаєте про сповіщення, ви думаєте про те, що сервер натискає з ніг на голову. Якщо ви збираєтеся робити це за запитами ajax або будь-яким іншим, вам доведеться турбуватися про продуктивність. Але я думаю, що це вже вдруге турбота;

Ця модель, яку я сконструював, звичайно, не єдина, за якою ви можете наслідувати, і не найкраща. Я сподіваюся, що моя відповідь, принаймні, наслідує вас у правильному напрямку.


Чому я не мав би контроль над іншим сховищем даних?
Ян Ганчич

Ну, я цього не казав. Що я сказав, це те, що я можу гарантувати контроль даних лише за допомогою підходу, керованого базою даних; але це тільки я. Я перефразую це.
Даніель Рібейро

@DanielRibeiro заповнювачі місць ({...}) у шаблоні сповіщень потребують заміни даних заповнювачів із різних наборів таблиць у базі даних для різних типів сповіщень. Наприклад, один шаблон - "{user} сподобався вашій фотографії". І т. Д. {PageName} і {user} та інші заповнювачі відображатимуть з різних таблиць баз даних, тому якою має бути схема, щоб динамічно оцінювати значення заповнювачів.
Ashish Shukla

DanielRibeiro, як ви замінили заповнювачі, як запитав @Ashish Shukla,
Shantaram Tupe

@AshishShukla Ви використовували чи заміняли заповнювачі, і як?
Шантарам Тупе

8
╔════════════════════╗
║notification        ║
╟────────────────────╢
║Username            ║
║Object              ║
║verb                ║
║actor               ║
║isRead              ║
╚════════════════════╝

Це виглядає гарною відповіддю, а не 2 колекції. Ви можете здійснювати запит за іменем користувача, об'єктом та isRead, щоб отримувати нові події (наприклад, три очікувані запити друзів, 4 запитання тощо).

Повідомте мене, чи є проблема з цією схемою.


3
У верхній відповіді використовується нормалізована структура даних, що означає відсутність надмірностей у таблицях. Чи відповідає це ваша відповідь?
Аарон Холл

4

Я особисто не дуже добре розумію схему прийнятої відповіді, тому я буду приєднувати базу діаграм бази даних про те, що я міг би дізнатися з прийнятої відповіді та інших сторінок.

введіть тут опис зображення

Поліпшення добре сприймаються.


Здається, що message_template буде в таблиці NotificationType. Також здається, що main_url буде в таблиці сповіщень, тоді ви можете усунути таблицю Notification_Message. Чи можете ви пояснити причину самостійної роботи таблиці NotificationMessage?
Джефф Райан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.