Laravel 5.5 - Уведомления/Подуведомления для 1 миллиона подписчиков?

Я использую таблицу notifications и таблицу subnotifications, а также использую очереди, поэтому они работают в фоновом режиме, когда пользователь что-то публикует. Когда у пользователя есть 10 подписчиков, и они создают сообщение, таблица notifications получает одну запись, которая включает данные публикации для уведомления, а таблица subnotifications получает 10 записей (одно подуведомление на подписчика, каждое из которых ссылается на идентификатор уведомления, поэтому нам не нужно повторять данные уведомления 10 раз с read_at, чтобы узнать, было ли оно прочитано этим подписчиком или нет).

Это быстро и отлично работает без каких-либо проблем. Однако при тестировании с 1 миллионом подписчиков вставка подуведомлений для одного сообщения занимает около ~6 часов! Это, конечно, неприемлемо, так как вставка 1 миллиона подуведомлений, по одному на подписчика, занимает слишком много времени. Представьте, что один и тот же пользователь публикует 10 сообщений, что займет ~60 часов вставки и 10 миллионов строк подуведомлений.

Я просто хочу, чтобы подписчики знали, что есть новый пост, если они его еще не читали. Есть ли лучший и более эффективный способ масштабирования?

ОБНОВЛЕНИЕ: застрял с текущим подходом, см. ниже...

Если у подписчика $user есть 100 лидеров, за которыми он следит (конечно, за которыми он следит с разными временными метками created_at в таблице подписчиков), каким будет правильный запрос, чтобы узнать о новых сообщениях лидеров с момента, когда подписчик подписался на каждого лидера? Я застрял на created_at с этим псевдокодом:

// Assume `leader_id` is a column in the notifications table
DB::table('notifications')
  ->whereIn('leader_id', $leaderIds)
  ->where(`created_at`, '>', $whatTimestampsGoHere)
  ->paginate(20);

Существует 100 различных временных меток, и я застрял в том, как решить эту проблему правильно и эффективно. Любые идеи?


person Wonka    schedule 29.03.2018    source источник
comment
Почему бы не вставлять в подуведомления только тогда, когда пользователи их читают? Получите уведомления для отображения из таблицы notifications, где нет записи в subnotifications с user_id и этим идентификатором уведомления, и как только пользователь увидит, добавьте запись в subnotifications   -  person Sérgio Reis    schedule 29.03.2018
comment
Спасибо! Это звучит как отличная альтернатива, но проблема, я думаю, будет заключаться в том, что если у пользователя сегодня есть 3 подписчика и он создает сообщение, мы можем проверить, существуют ли они в subnotifications с помощью строки user_id/notification_id, чтобы узнать, прочитано ли оно. или не. Но если они получат 7 новых подписчиков завтра, новых 7 не следует уведомлять, так как они начали подписываться после публикации. Должен ли я сканировать таблицу подписчиков, чтобы сравнить их следующую временную метку ‹ временную метку уведомления и игнорировать новых подписчиков после публикации? Это эффективно или есть лучший способ?   -  person Wonka    schedule 29.03.2018
comment
Хм, это звучит более разумно, таким образом вы на самом деле сохраняете много вставок в базу данных и сохраняете функциональность как есть.   -  person Sérgio Reis    schedule 29.03.2018
comment
Не могу понять этот вопрос   -  person Sérgio Reis    schedule 09.04.2018
comment
Если вы подписались на 100 человек, в таблице подписчиков будут записаны ваши временные метки follower_id, leader_id и created_at. Когда вы просматриваете свои уведомления, вы должны видеть только новый контент, опубликованный вашими руководителями. Это легко понять, если у вас был только 1 лидер, поскольку вы сравниваете отметку времени, на которую вы подписались, с отметкой времени уведомления. Но так как у вас есть 100 лидеров, вы не хотите получать их старые сообщения до того, как вы подписались на них, только сообщения после того, как вы подписались на них, но у вас нет 1 временной метки только для сравнения, у вас есть 100 временных меток, вот в чем проблема. банкомат..   -  person Wonka    schedule 09.04.2018
comment
Хм, а вы не можете загрузить своих лидеров и нетерпеливо загрузить их контент? $user->leaders()->with('notifications') лидеры — это пользователи, на которых вы подписаны, и уведомления о том, что вам нужно. (1 пользователь имеет много подписчиков, 1 подписчик (я думаю, пользователь) имеет много уведомлений), загружая контент, вы также можете фильтровать, загружая уведомления после временной метки created_at.   -  person Sérgio Reis    schedule 10.04.2018
comment
Проблема заключается в том, что $user->leaders()->with('notifications') не получает уведомления для подписчика, поскольку предполагается, что $user является уведомляемым, хотя notifiable_id в db равно 0 (чтобы обозначить его для всех подписчиков), а не $user id. Единственным реальным идентификатором является столбец leader_id в таблице notifications, который является leader_id (идентификатором пользователя) всякий раз, когда есть 0 для уведомляемого. Как мы можем тогда использовать значение leader_id и с готовностью загружать лидеров для их отслеживаемых временных меток, чтобы иметь возможность сравнивать временные метки? Я думаю, что запрос, возможно, придется изменить...   -  person Wonka    schedule 10.04.2018
comment
Если отношения установлены правильно, вы можете выполнить этот запрос, laravel.com /docs/5.5/eloquent-relationships#one-to-many все функции отношений принимают дополнительные параметры в виде имен столбцов/таблиц.   -  person Sérgio Reis    schedule 10.04.2018


Ответы (1)


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

Также, как уже было сказано, при получении уведомлений для показа пользователям извлекайте их из notifications, но ограничивайте уведомления уведомлениями, созданными после, когда пользователь начал подписаться, чтобы новые пользователи не были завалены уведомлениями.

person Sérgio Reis    schedule 29.03.2018
comment
Привет, Серхио, я создал новый вопрос здесь: stackoverflow.com/questions/49764452, чтобы разрешить локальное воссоздание проблемы, поскольку я не могу не удалось заставить запрос работать должным образом со сравнением временных меток created_at, и я не хотел продолжать добавлять к этому вопросу. Спасибо за направление, чувак, я очень ценю твою помощь :) - person Wonka; 11.04.2018