Обеспечение действия подает объекты умеренно масштабируемым способом

Приложение я продолжаю работать, имеет канал действия, где каждый пользователь видит действие их друзей (во многом как Facebook). Я ищу умеренно масштабируемый способ показать ленту активности данных пользователей на лету. Я говорю 'умеренно', потому что я надеюсь делать это только с базой данных (Postgresql) и возможно memcached. Например, я хочу это решение масштабировать 200k пользователям каждого с 100 друзьями.

В настоящее время существует основная таблица действия, которая хранит представленный HTML для данного действия (Jim добавил друга, George установил приложение, и т.д.). Эта основная таблица действия сохраняет исходного пользователя, HTML и метку времени.

Затем существует отдельное ('соединение') таблица, которая просто сохраняет указатель на человека, который должен видеть это действие в их друге канал и указатель на объект в таблице основного вида деятельности.

Так, если у меня будет 100 друзей, и я делаю 3 операции, то затем объединяющая таблица затем вырастет до 300 объектов.

Очевидно эта таблица вырастет очень быстро. Это имеет хорошее свойство, тем не менее, что выбирающее действие, чтобы показать пользователю берет единственный (относительно) недорогой запрос.

Другая опция состоит в том, чтобы просто сохранить таблицу основного вида деятельности и запросить ее путем высказывания чего-то как:

select * from activity where source_user in (1, 2, 44, 2423, ... my friend list)

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

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

Большое спасибо!

16
задан Jon Seigel 7 March 2010 в 17:50
поделиться

1 ответ

Я склоняюсь к тому, чтобы просто иметь главную таблицу активности. Если вы согласитесь с этим, вот что я бы рассмотрел для реализации:

  1. Вы можете создать несколько таблиц активности и сделать UNION ALL при получении данных из базы данных. Например, переносить их ежемесячно - activity_2010_02 и т.д. Просто на вашем примере - 200K пользователей x 100 друзей x 3 активности = 60 миллионов строк. Это не является проблемой с точки зрения производительности PostgreSQL, но вы можете рассмотреть этот вариант чисто для удобства сейчас и в перспективе для расширения в будущем.

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

Собираетесь ли вы отображать всю ленту активности, начиная с начала времен? В исходном вопросе вы не указали много деталей, но я рискну предположить, что вы собираетесь показать последние 10/20/100 элементов, отсортированных по метке времени. Пары индексов и условия LIMIT должно быть достаточно, чтобы обеспечить мгновенный ответ (как я только что проверил на таблице с примерно 20 миллионами строк). Это может быть медленнее на загруженном сервере, но это то, что должно быть решено с помощью оборудования и решений кэширования, Postgres не будет там узким местом.

Даже если вы предоставляете данные о деятельности, начиная с зари времен, постранично размещайте вывод! Здесь вас спасет оговорка LIMIT. Если базового запроса с LIMIT недостаточно, или если у ваших пользователей длинный хвост друзей, которые больше не активны, вы можете ограничить поиск последним днем/неделей/месяцем сначала и затем предоставить список идентификаторов друзей:

select * from activity 
  where ts <= 123456789 
    and source_user in (1, 2, 44, 2423, ... my friend list)

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

Это только если выбирать между двумя решениями, которые вы рассматриваете сейчас. Я бы также рассмотрел такие вещи, как:

  1. Пересмотр денормализации таблицы. Действительно ли хранение предварительно сгенерированного HTML-вывода является лучшим способом? Будет ли лучше с точки зрения производительности, если вместо этого вы будете иметь таблицу поиска действий и генерировать шаблонный вывод на лету? Предварительно сгенерированный HTML может показаться лучше с самого начала, но если учесть такие вещи, как дисковое хранилище, API, будущие изменения макета, то хранение HTML может оказаться не таким уж привлекательным. Таблица поиска может содержать возможные действия - добавление друга, изменение статуса и т.д., а журнал действий будет ссылаться на это и на id друга, если в действиях участвует другой пользователь.

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

Надеюсь, это поможет.

12
ответ дан 30 November 2019 в 23:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: