Как реализовать поток активности в социальной сети - PullRequest
131 голосов
/ 18 сентября 2009

Я разрабатываю собственную социальную сеть, и я не нашел в сети примеров реализации потока действий пользователя ... Например, как отфильтровать действия для каждого пользователя? Как хранить события акции? Какую модель данных и объектную модель я могу использовать для потока действий и для самих действий?

Ответы [ 6 ]

231 голосов
/ 19 ноября 2009

Сводка : Для примерно 1 миллиона активных пользователей и 150 миллионов хранимых действий я упрощаю:

  • Использование реляционной базы данных для хранения уникальных действий (1 запись на действие / «вещь, которая произошла»). Сделайте записи максимально компактными. Структура, позволяющая быстро получить пакет действий по идентификатору операции или с помощью набора идентификаторов друзей с временными ограничениями.
  • Публикуйте идентификаторы активности в Redis при каждом создании записи активности, добавляя идентификатор в список «потока активности» для каждого пользователя, который является другом / подписчиком, который должен видеть действие.

Запрос Redis, чтобы получить поток активности для любого пользователя, а затем получить необходимые данные из БД по мере необходимости. Вернитесь к запросам по БД по времени, если пользователю нужно просматривать далеко назад (если вы даже предлагаете это)


Я использую простую старую таблицу MySQL для обработки около 15 миллионов операций.

Это выглядит примерно так:

id             
user_id       (int)
activity_type (tinyint)
source_id     (int)  
parent_id     (int)
parent_type   (tinyint)
time          (datetime but a smaller type like int would be better) 

activity_type сообщает мне тип активности, source_id сообщает мне запись, с которой связано действие. Так что, если тип действия означает «добавленный избранный», то я знаю, что source_id ссылается на идентификатор избранной записи.

parent_id / parent_type полезны для моего приложения - они говорят мне, с чем связано действие. Если бы книга была добавлена ​​в избранное, то parent_id / parent_type сказал бы мне, что действие относится к книге (типу) с заданным первичным ключом (id)

Я индексирую на (user_id, time) и запрашиваю действия, которые user_id IN (...friends...) AND time > some-cutoff-point. Отключение идентификатора и выбор другого кластерного индекса может быть хорошей идеей - я не экспериментировал с этим.

Довольно простой материал, но он работает, он прост, и с ним легко работать, когда ваши потребности меняются. Кроме того, если вы не используете MySQL, возможно, вы сможете улучшить индексирование.


Для более быстрого доступа к самым последним действиям я экспериментировал с Redis . Redis хранит все свои данные в памяти, поэтому вы не можете поместить туда все свои действия, но вы можете хранить достаточно для большинства популярных экранов на вашем сайте. Последние 100 для каждого пользователя или что-то в этом роде. С Redis в миксе, это может работать так:

  • Создайте свою запись активности MySQL
  • Для каждого друга пользователя, создавшего действие, вставьте идентификатор в свой список действий в Redis.
  • Обрезать каждый список до последних X элементов

Redis работает быстро и предлагает способ передачи команд по одному соединению, поэтому отправка активности для 1000 друзей занимает миллисекунды.

Для более подробного объяснения того, о чем я говорю, см. Пример Redis в Twitter: http://redis.io/topics/twitter-clone

Обновление за февраль 2011 У меня сейчас 50 миллионов активных действий, и я ничего не изменил. Хорошая вещь о том, чтобы сделать что-то подобное этому, состоит в том, что это использует компактные, маленькие ряды. Я планирую внести некоторые изменения, которые повлекут за собой гораздо больше действий и больше запросов об этих действиях, и я определенно буду использовать Redis для ускорения работы. Я использую Redis в других областях, и он действительно хорошо работает для некоторых видов проблем.

Обновление за июль 2014 года Ежемесячно мы получаем около 700 000 активных пользователей. Последние пару лет я использую Redis (как описано в маркированном списке) для хранения последних 1000 идентификаторов активности для каждого пользователя. Обычно в системе около 100 миллионов записей активности, и они все еще хранятся в MySQL и имеют ту же структуру. Эти записи позволяют нам избегать меньшего объема памяти Redis, они служат для записи данных об активности, и мы используем их, если пользователям необходимо найти страницы назад во времени, чтобы что-то найти.

Это не было умным или особенно интересным решением, но оно хорошо мне помогло.

21 голосов
/ 23 ноября 2009

Это моя реализация потока активности с использованием mysql. Существует три класса: Activity, ActivityFeed, Subscriber.

Activity представляет запись активности, и ее таблица выглядит следующим образом:

id
subject_id
object_id
type
verb
data
time

Subject_id - это идентификатор объекта, выполняющего действие, object_id идентификатор объекта, который получает действие. type и verb описывает само действие (например, если пользователь добавит комментарий к статье, он будет «комментировать» и «создан» соответственно), данные содержат дополнительные данные во избежание объединений (например, может содержать имя и фамилию субъекта, заголовок и URL статьи, текст комментария и т. д.).

Каждое действие принадлежит одному или нескольким ActivityFeeds, и они связаны таблицей, которая выглядит следующим образом:

feed_name
activity_id

В моем приложении у меня есть один фид для каждого пользователя и один фид для каждого элемента (обычно это статьи блога), но они могут быть любыми.

Подписчик обычно является пользователем вашего сайта, но это также может быть любой объект в вашей объектной модели (например, статья может быть подписана на feed_action его создателя).

Каждый подписчик принадлежит одному или нескольким ActivityFeeds, и, как и выше, они связаны таблицей ссылок такого типа:

feed_name
subscriber_id
reason

Поле reason объясняет, почему подписчик подписался на канал. Например, если пользователь делает закладку на запись в блоге, причина - «закладка». Это поможет мне позже при фильтрации действий для уведомлений пользователей.

Чтобы получить действие для подписчика, я делаю простое объединение трех таблиц. Соединение происходит быстро, потому что я выбираю несколько действий благодаря условию WHERE, которое выглядит сейчас - time > some hours. Я избегаю других объединений благодаря полю данных в таблице Activity.

Дополнительные пояснения к полю reason. Если, например, я хочу отфильтровать действия для уведомлений по электронной почте пользователю, и пользователь добавил в закладки запись в блоге (и поэтому он подписывается на ленту сообщений с причиной «закладки»), я не хочу, чтобы пользователь получал уведомления по электронной почте о действиях над этим элементом, в то время как если он комментирует сообщение (и поэтому оно подписывается на ленту сообщений с причиной «комментарий»), я хочу, чтобы он был уведомлен, когда другие пользователи добавляют комментарии к тому же сообщению. Поле причины помогает мне в этом различении (я реализовал его с помощью класса ActivityFilter) вместе с настройками уведомлений пользователя.

14 голосов
/ 14 февраля 2012

Существует текущий формат потока активности, который разрабатывается группой хорошо известных людей.

http://activitystrea.ms/.

По сути, каждое действие имеет актера (который выполняет действие), глагол (действие действия), объект (на котором действует актер) и цель.

Например: Макс опубликовал ссылку на стену Адама.

Их спецификация JSON достигла версии 1.0 на момент написания, которая показывает шаблон для действия, которое вы можете применить.

Их формат уже принят BBC, Gnip, Google Buzz Gowalla, IBM, MySpace, Opera, Socialcast, Superfeedr, TypePad, Windows Live, YIID и многими другими.

13 голосов
/ 21 сентября 2009

Я думаю, что объяснение того, как система уведомлений работает на больших веб-сайтах, можно найти в вопросе переполнения стека как веб-сайты социальных сетей вычисляют обновления друзей? , в Стене Джереми ответ. Он предлагает использовать Message Qeue и указывает две программы с открытым исходным кодом, которые его реализуют:

  1. RabbitMQ
  2. Apache QPid

См. Также вопрос Как лучше всего реализовать поток социальной активности?

1 голос
/ 05 апреля 2012

Вам абсолютно необходима рабочая и распределенная очередь сообщений. Но на этом все не заканчивается, вам придется принимать решение о том, что хранить как постоянные данные, а что как временные и т. Д.

В любом случае, мой друг, это действительно сложная задача, если вам нужна высокопроизводительная и масштабируемая система. Но, конечно, некоторые щедрые инженеры поделились своим опытом по этому вопросу. В последнее время LinkedIn сделала свою систему сообщений Kafka с открытым исходным кодом. До этого Facebook уже предоставил Scribe сообществу открытого кода. Kafka написан на Scala, и сначала для его запуска требуется некоторое время, но я протестировал пару виртуальных серверов. Это действительно быстро.

http://blog.linkedin.com/2011/01/11/open-source-linkedin-kafka/

http://incubator.apache.org/kafka/index.html

0 голосов
/ 19 июня 2013

Вместо того, чтобы кататься самостоятельно, вы можете обратиться к стороннему сервису, используемому через API. Я запустил один под названием Collabinate (http://www.collabinate.com), который имеет серверную базу данных графа и несколько довольно сложных алгоритмов для обработки больших объемов данных с высокой степенью параллелизма и высокой производительности. Хотя он не обладает широкими функциональными возможностями, например Facebook или Twitter, этого более чем достаточно для большинства случаев использования, когда вам нужно встроить потоки активности, социальные сети или функции микроблогов в приложение.

...