Как реализовать поток активности в социальной сети

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

Ответ 1

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

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

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


Я использую обычную старую таблицу 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 в миксе он может работать следующим образом:

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

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

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

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

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

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

Ответ 2

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

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

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. Я избегаю других объединений благодаря полю данных в таблице действий.

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

Ответ 3

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

http://activitystrea.ms/.

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

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

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

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

Ответ 4

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

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

Ответ 5

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

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

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

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

Ответ 6

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