Как стать автором
Обновить

Комментарии 68

не понял а при чем здесь хаб BigData. Ну разбили ленту на шарды — проблема-то? простой паттерн шардирования. Для борьбы с разбуханием данных используем виртуальный шардинг, где данные по шардам разводятся не по алгоритму — остаток от деления иди юзера, а через специальный конфиг, в котором можно задавать вес шарды. Другой вопрос в том, что автор правильно заметил, что новостная лента нужна на определенный срок, и нас на врядли бы заинтересовали новости друзей годичной давности… К сожалению — описываемый подход применим к любителям монги. Однако, при использовании виртуального шардинга, с легкостью можно чистить устаревшие шарды.
Добавил BigData, т.к. обычно при решении задачи формирования ленты сталкиваешься с большими объёмами данных. И описанные здесь подходы по организации больших данных вполне применимы не только при работе с MongoDB.

Про виртуальный шардинг — весьма интересно, раньше не слышал о нём. Возможно у вас есть пару полезных ссылок?
гуглите в сторону virtual buckets
Спасибо
А расскажите, какие нагрузки выдерживали Ваши разработанные соцсети?

Я вот честно до сих пор воспринимаю MongoDb как сырое решение, не заточенное для production.
Поэтому первая мысль для решения такой задачи — использовать распределенный индекс для хренения всех постов в виде (user_id, post_id, time) — например ElasticSearch. Пробовали? Какие результаты?
ничего ж не мешает пойти на сайт и посмотреть, что ее используют в продакшине очень многие. www.mongodb.org/about/production-deployments/
Я прекрасно понимаю, что есть куча компаний, использующие ее. Более того, даже знаю системы, работающие с реальными деньгами, которые имеют только MongoDB на уровне storage (и которые всю транзакционность врукопашную писали). Но это не меняет того факта, что она у меня дико косячила и косячила у других людей — чьими историями завален интернет. И тот же PostgreSQL на порядок быстрее и надежнее (ну да, шардинга нормального нет… но его же можно реализовать, не? и вообще virtual shards сейчас в моде, а монга так вроде не умеет).
берите CouchBase
Где-то до полумилионна записей (постов) в день.

Что мне особенно нравится в MongoDB, так как отличная динамика развития продукта. И то что было даже год назад, не идёт ни в какое сравнение с тем, что есть сегодня.

Ваш вариант с ElasticSearch выглядит весьма интересно, но нет, я так не пробовал.
Да ладно? А почему они тогда держат целую команду разработчиков SQL Server?
Или у них монга не основной storage?
MSSQL используется для других задач.
Сам сайт работает на MongoDB

Некоторые магазины тоже так делают.
К примеру данные в MSSQL для 1С а сайт на MySQL (Percona) с прослойкой redis, не буду говорить какой магазин так работает))
Видимо wb примерно так же использует.
Это предположение или факт?
Зачем им целый отдел MS SQL под «другие задачи»?
Как работает магазин на СУБД, которая не обеспечивает надежность хранения?

Объявление о работе недвусмысленно говорит нам, что сайт wb.ru таки на MS SQL работает www.sql.ru/forum/1070106/trebuetsya-programmist-ms-sql

Mongo если и есть, то только для кеша.
Прослойка на redis это всего лишь кеш. От него не требуется ни обслуживать сложные запросы, ни обеспечивать надежное долговременное хранение, ни разруливать транзакционность, ни сохранять консистентность. А от MSSQL\MySQL или любой другой SQL базы все это требуется.

Монга же пытается сделать вид что она умеет все, что умеет SQL база, но при этом быстро работает. По факту и работает не быстро, и не умеет нифига толком.
Видимо с redis вы мало работали. Да и с mongo.

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

На помощь нам придут другие технологии. В данном случае redis. В других mongo или еще что.
Ага, проблема во мне, конечно.

Синхронизировать все операции позволяет SSIS — бесплатный компонент SQL Server. Зачем там Mongo или Redis для меня загадка. Может приведете пример как оно может помочь?
Зачем wb.ru mongo? Это наверное лучше все же у них спросить.

В другом проекте, все оч. просто.
Прошла операция на кассе, в следствии чего данные обновились в mssql.
В тот же момент покупатель приобрел товар (сотни товаров) в интернет магазине (mysql).
Т.е. мы имеем 2 БД которые не как не пересекаются и на старте имеют разную структуру данных, после определенных операций, мы имеем еще более разные данные.
А еще есть специализированный торговый софт, который имеет свои данные и свою структуру и свою бд.

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

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

Почему разные БД и такой зоопарк? Так Москва не сразу строилась, сначала было одно, затем появилось другое/третье… Затем все объединилось.

Я ведь не говорю что так надо делать, что это правильно.
Я указал что использует wb. Почему это так? Повторюсь: спросите у разработчиков.
Но предположения есть, wb, зарождался за долго до их популярности.
Сначала там работал один программист, который на коленке сваял что то. Затем их стало больше.
Через год пару первых программистов ушло и т.д. За 2-3 года сменилось много разработчиков, и каждый привносил свое.
Когда пошли инвестиции, когда компания стала акционерной, то появились уже не только разработчики но и менеджеры, тим лиды, ИТ деректора и все что должно быть в крупных компаниях.
Вот тогда то и начали все структурировать, разгонять, чистить. Но основу не убрали.

P.S.
Замечу что C# ASP.NET (код с нуля без фреймворка) + MongoDB работает и по сей день довольно быстро.
Откуда уверенность что там монга? Я в открытых источниках не нашел такой инфы, а верить на слово как-то не привык.

Так вот, при каждых операциях, определенная структура данных ложится в redis

А зачем тут redis? Данные просто попадают в базу и периодически синхронизируются в одно хранилище с помощью SSIS.

Почему разные БД и такой зоопарк? Так Москва не сразу строилась, сначала было одно, затем появилось другое/третье… Затем все объединилось.

Есть подтверждение? Или это фантазии?
Есть.
Близкий друг один из первых разработчиков wb с ~2008, сейчас работает там же.
Вы упомянули штат разработчиков SQL Server.
У каждого свои запросы.
Есть магазин butik.ru — там работает на данный момент 2 программиста и все.
Нет штата разработчиков SQL Server, нет около 50 разработчиков front/back — end.
Просто 2 разработчика и управляющий проектом.
Зато работает так же быстро и хорошо как wb, просто не захотели становится акционерным.
Может нагрузка совершенно разная.
Почти что одинаковая. Процентов на 10% меньше.
А для чего группировать записи в первых двух подходах?
Группировать по времени будет удобно, если ваш тайм-лайн как-то сильно завязан на временные интервалы (например, прдеставлен в виде календаря). Второй вариант сгодится для стандартной ситуации, если размер стораджа для вас не критичен.
Нет, вопрос был немного в другом.
Почему не использовать 1 запись = 1 документ?

Уточню:
1 запись в на стене пользователя = 1 запись в коллекции монго
Т.е. полностью без группировок.
Такой вариант вполне приемлемый. Скажу более, я именно такой вариант использовал, пока не узнал о новых подходах на MongoDB World. Первые два подхода на практике не использовал, но может кому-то понадобятся, поэтому я о них упомянул. А вот третий подход, с кэшированием, считаю мега крутым.
Да, дело в том, что когда мы делали ленту, мы тоже генерировали в монге ленту под каждого пользователя и хранили в виде 1 запись в ленте = 1 запись в колекции.
Вариант с кешированием — возможно да, крутой. С другой стороны, для кеша тогда не обязательно использовать монгу )
Конечно необязательно. Я вот даже примеры монговские в спойлеры попрятал. Но тем не менее, монга очень хорошо подходит и для варианта с кэшем с её capped-массивами и шардированием.
В монге collection-level lock на запись. То есть любая запись в агрегированные ленты лочит всю коллекцию. Учитывая, что писать надо в ленты всех друзей, то это приведет к тому, что большая часть лент будет залочены большую часть времени под нагрузкой.

Тут сразу возникает вторая проблема — не атомарность записи. Если по какой-то причине запись прервется, то ленты окажутся не консистентными. Вообще сложно будет добиться консистентной в такой системе.

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

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

Вот тут описана суть проблем — habrahabr.ru/post/231213/ и решение, к которому пришли те, кто это делал.
Даже с локом на коллекцию, система без проблема держала нагрузку до полмиллиона постов в сутки. Это конечно близко не стоит с Diaspora и Facebook, но и вовсе не мало.

А в новом релизе уже реализован document-level lock. Вот так сразу снимаются все проблемы.
Полмиллиона постов или полмиллиона записей? У вас же количество записей будет зависеть от количества связей.
Предположим в сети 5000 человек, у каждого по 150 друзей и все написали по посту. У вас в базу улетело 750,000 записей. Система ляжет.
Причем писать надо не только посты, но и все лайки\комменты. Поэтому вполне реальный сценарий.

Причем надо тестировать не только количество постов, но и отзывчивость системы в этот момент.

Можно разрулить через очередь, но может получиться лаг между постом и тем когда его увидели, в минуты или даже часы, что делает соцсеть бесполезной.
Записей в сервис ленты. Да, рулили именно через очереди, поэтому и с отзывчивостью было всё ок.
А сколько было пользователей\связей? Это ключевой параметр, который причем квадратичный рост нагрузки дает.
Ключевой параметр я уже вам написал. Пользователей и связей может быть сколь угодно много, но все они будут неактивными, это не показатель. И про квадратичную зависимость улыбнуло. Это показывает, что вы далеки от темы и от математики.
Нет, вы его пропустили. Пока неизвестно сколько у вас связей в системе количество постов ничего не значит. Если пользователь один и связей у него ноль, то максимальное количество постов в единицу времени будет одно, а если тысячи пользователей и сотни связей, то получится совсем другое число.

Вот я и спрашиваю: полмиллиона при каком количестве пользователей и связей было.

Про квадратичную зависимость не знаю что вас улыбнуло, но в системе с N пользователями у каждого может быть до N-1 связей. Это и получается O(N^2). У вас другие выкладки?
Вы невнимательно читаете. Я написал про полмиллиона записей в сервис ленты, а не контента. Т.е. это записи в персональные ленты пользователей. Самая что ни на есть ключевая метрика.

Вы это серьёзно, про N-1 связей у каждого пользователя? Скажите честно, вы разрабатывали хотя бы одну социальную сеть, живущую в продакшене? В реальности, средняя цифра связей у каждого пользователя — это практически константа, абсолютно не зависящая от общего количества пользователей.

А, понял. Запись в сервис ленты не означает, что пост появится у подписчиков. Тогда поставим вопрос по-другому.
500,000 записей в сутки — примерно 6 записей в секунду. Так вот при 5 записях в секунду, при 5000 пользователей и 150 связях в среднем у каждого, а также при равномерном распределении записей по пользователям через сколько времени посты «друзей» появляются в ленте пользователей? Какая средняя длина очереди? Какое время обработки элемента в очереди?

Я разрабатывал соцсеть еще в 2008 году, до кризиса. Тестировал на 2000 пользователей и 100 связей у каждого, сбор ленты прямо из базы с кешированием работал успешно, но нагрузку на запись не тестил, так как по сценариям предполагалось не более одного поста и 10 лайков в день от пользователя.

По поводу связей у каждого пользователя — это очень интересная величина. В современных соцсетях пользователи отслеживают «акторов», каждый из которых может быть как пользователем, так и группой или прозвиольным объектом (open graph например). Так вот в корпоративных соцсетях есть тенденция подписки каждого пользователя на большое количество акторов, причем люди не сами подписываются, а подписка делается по бизнес-правилам. Поэтому при общем количестве акторов N и пользователей M, то количество связей растет как O(M*N). Хотя я лично ограничивал количество подписок на акторов до 500, больше пользователю не надо обычно, а планированию быстродествия очень помогает.
А, понял. Запись в сервис ленты не означает, что пост появится у подписчиков.

Не верно. Как раз таки если событи уже попало в сервис ленты, то оно обязательно отобразится у пользователя в его персональной ленте.
У какого пользователя? Который добавил или который подписан на того, кто добавил? То есть добавление и репликация происходит синхронно? Если да, то сколько связей между пользователями? Какое распределение записей по пользователям? При тестировании запросы на запись выполнялись параллельно или последовательно?
Вообще единственное живое решение для 10,000+ активных пользователей — как раз построение ленты при чтении+кеширование.
По сути ленты с последними сообщениями всех пользователей\групп лежат в кеше. При запросе ленты из кеша достаются ленты всех друзей и по ним строится агрегированная лента. При записи пост пишется просто в ленту (список постов) в кеша.

Если надо показывать ленту со старыми сообщениями, то делается просто запрос к СУБД с целым одним джоином.

В качестве стореджа можно использовать любую РСУБД, так как подавляющее большинство запросов не будет долетать до СУБД. СУБД можно будет шардить по пользователям совершенно без проблем.

С точки зрения архитектуры получится примерно как монга, но более гибко. В монге кеш получатся прибит к стореджу, а сторедж мягко говоря слабоват. В случае разделенных кеша и базы их можно масштабировать отдельно, база умеет достаточно хорошо делать джоины, а кеш, управляемый приложением, повышает эффективность использования памяти.
Проблема в том, что в новостной ленте часто показывается много больше активности пользователей, чем отображается на стене этих пользователей. Т.е. помимо постов друзей, в ленту попадает что они лайкали, с кем подружились, во что сыграли, etc.
А в чем проблема? Не показывать часть событий на отдельных лентах? Это сложно?
Это не сложно, но что это даст? Ведь у каждого фолловера свои персональные настройки того, что он читает. Представьте, что вам надо взять все записи всех ваших друзей, отсортировать их по времени, а потом отфильтровать кастомными фильтрами.
Если материализовывать ленту ситуация будет еще хуже. Любая смена фильтра — пересборка всей ленты. Если вы умеете пересобирать ленту за приемлемое время, то зачем её материализовывать?
Я ж целую статью написал о том, когда какой подход лучше. А вы двумся строчками комментария авторитетно заявляете, что это не так.
ОК, пойдем сначала.
В своей статье вы упустили два критичных момента:
1) Изменение состава «друзей» потребует пересборки ленты, причем быстро. А если есть еще фильтры для ленты, то изменение фильтров также потребует пересборки.
2) Не атомарность процесса сборки ленты приводит к проблемам. Репликация постов может остановиться по куче причин и оставить систему в не консистентном состоянии (особенно если оно рабтает на монге).

Особенно интересно как вы решаете первую проблему. Говорить что это не проблема — не катит. Все соцсети сразу перестают показывать посты тех, от кого вы отписываетесь.
1. В своей статье я сознательно опустил огромную кучу нюансов, с которыми сталкивался лично и описал магистральные идеи. Иначе пришлось бы раздувать статью до неприличных размеров. Но от ответа уходить не стану. Проблема решается довольно просто путём добавления ID автора к ссылке на событие (пост/лайк/etc). Т.е. мы храним не только ID оригинального события, но и юзера, который это событие породил. Таким образом очень легко и быстро можно «отписывать» от пользователей.
2.
особенно если оно рабтает на монге
Огорчает ваше предвязтое отновшение к Монге, в таком ключе тяжело вести конструктивный диалог. Я вот даже отадлённо не представляю, как в более-менее большой сети этот процесс можно реализовать атомарно. Вот честно.
Вы «выплеснули с водой ребенка», потому что опустили самые важные аспекты соцсети, такие как UX и privacy.
1) Предположим вы научилсь быстро удалять пост из ленты при отписке. Но тут снова возникает две проблемы:
а) Как обрабатывается подписка на другого пользователя? Обычно подписавшись человек ожидает все посты\действия пользователей, вы же предлагаете делать это в фоне, что сильно ухудшает UX.
б) Если у вас в ленте есть спамер который запостил 100500 сообщений, вытеснив все остальные (у вас же есть ограничение на размер материализованной ленты). Вы его удаляете и у вас девственно чистая лента.
Вообще проблема спамеров очень серьезно стоит при материализованной ленте.

2) Мое отношение к монге основано на практике использования, когда после пары перезагрузок потерялось несколько записей «очереди» и возникли проблемы. А если в монге накрутить гарантии и write concern, то начинает тормозить, что работать невозможно.

3) Рассказываю тайну: есть NoSQL базы, которые поддерживают multi-document transactions, в том числе в распределенной среде, но монга так не умеет и пока не двигается в этом направлении. Но самое главное что честная атомарность такого процесса будет очень медленной, что сделает фактически бессмысленным материализацию лент.

4) С учетом факторов выше и требований privacy (если я удалил пост — он должен везде исчезнуть) заниматься репликацией ленты не стоит в большинстве случаев, только при очень слабых требованиях consistency\privacy\времени_обновления. Настолько слабые требования мне, например, не встречались.
Из всех веток наших дискуссий я понял, что помимо Монги у вас был неудачный опыт с формированием ленты на запись. Расскажу одну историю. Пару недель назад заводил профиль в Facebook своей бабушке. Добавил ей пару человек из мемьи в друзья. Представьте себе моё удивление, когда после добавления друзей я увидел у неё `девственно чистую ленту` (вы не против заимствования термина). Лента заполнилась, если я не ошибаюсь, на следующий день. Думаю вывод из этого вы можете сделать сами. Хотя я сам не считаю такою ситуацию нормальной, думаю это какая-то перемудрённая система приоритетов в их очередях. Но факт остаётся фактом.

И на счёт столь важной для вас темы приватности и удаления. На самом деле, если после удаления/скрытия поста/фото/etc что-то пойдёт не так, и процесс удаления ссылок на запись в лентах подписчиков оборвётся, то ничего страшного не произойдёт. Объясню почему. В летах подписчиков останется ссылка на запись, но оригинал записи уже будет помечена как удалённая/приватная. Поэтому подписчки её не увидят. А возникшую ситуацию можно использовать с пользой как триггер для перезапуск операции удаления ссылок.
А меня как раз удачный опыт, ибо я делаю примерно тоже самое, что делает монго. Только у меня кешем управляет приложение. Это дает гораздо более эффективное использование памяти и надежное хранение в РСУБД. А ткже автоматически дает возможность получить ленту за любой диапазон времени (возможно небыстро, но без больших усилий). При этом нигода не испытывал тех проблем, на которые можно нарваться с хранением материализованной ленты в монге.

Ваш пример с FB не доказывает правильность вашего подхода ;)
Представьте, что пользователь может добавлять некоторые посты из своей ленты в черный список, скрывать их, добавлять сложные фильтры для своей ленты. Как вы тогда будете формировать запрос к СУБД? Я сталкивался с этой проблемой и приходилось отказываться от обычных запросов к СУБД, приходилось фильтровать в момент создания поста (в момент формирования индивидуальной ленты подписчика).

Вот еще пример фильтра: скрывать из ленты все лайки, скрывать все лайки только от родственников и т.д.
Скрыть некоторые посты вообще не проблема. В кеше лежат например 150 постов со всеми лайками и комментами для каждого пользователя. Для построения агрегированной ленты надо взять из кеша ленты всех друзей, сделать merge по дате поста, выкинуть скрытые и отдать на клиент.

Про фильтры не очень понятно. Что надо скрывать, посты или лайки? Лайки можно поправить при агрегации, с постами — зависит от предиката. В чем проблема сделать нужный запрос в СУБД?

Почему бы просто не прикрутить к фильтрованным лентам кеш? они же меняться будут реже гораздо и их тупо меньше.
Представьте ленту которая состоит из различного рода контента — «фото», «текст», «ссылка», «репост». Заказчиком поставлена задача, чтобы пользователь мог добавлять в игнор например обновления типа «фото» от пользователя «Вася пупкин». Или сделать так, чтобы в его ленте появлялись только «фото» и «ссылки» от пользователей находящихся с меткой «родственники». Кеширование не спасает, т.к. это часто обновляемая лента и главная для пользователя. Сделать это через JOINы будет все сложнее и сложнее, т.к. в моей практике заказчик хотел все более сложные фильтры для лент, чтобы у пользователей могло быть несколько тематических лент. Сплошная головная боль.

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

В случае сложных предикатов сформировать ленту при записи все равно недостаточно, ибо предикат поменяется и надо будет ленту пересобрать, причем быстро. А имея быстрый алгоритм сбора ленты достаточно прикрутить простое кеширование и не надо думать о консистентности.
Сложности в формировании запроса. Было поставлено условие, что новые фильтры не влияют на ранее добавленные в ленту элементы, поэтому пересобирать ленту не нужно, либо в отложенном режиме.
При таком условии кеширование прикрутить элементарно. В памяти лежит список постов по ИД ленты и набор фильтров. Каждый новый пост проверяется по фильтрам и пишется в список если соответствует. Старые можно со временем отсекать, чтобы объем данных в памяти не пух.

А чем запросы то генерили? Я вот на C# программирую, с появлением Linq вообще отпала проблема создания сложных запросов. Для других языков тоже есть генераторы, хоть и послабее.
самый большой недостаток системы — неудобная работа с удалением как записей, так и отписки от чтения новостей определенного пользователя, особенно при большом обьеме подписчиков у людей. как вы боретесь с этими проблемами? когда мне надо было писать ленту новостей этот подход я рассматривал одним из самых первых, но осознав описанные выше проблемы решил от него отказаться.
Решается довольно просто. Записи в ленте помимо ID оригинального события (поста/лайка/etc) должны содержать ID автора этого ивента. Добавляем индекс по ID автора и процессим удаление/отписку в бэкграунде. Запрос конечно получается ощутимо тяжелее чтения, но во-первых такого рода запросы случаются несравнимо реже запросов на чтение. Ну и во-вторых, скорость таких запросов некритична.
с удалением именно записей — критично, если речь идет о серьезном проекте. взять фб или вк — там все происходит моментально, при этом не совсем уверен на счет фб, но в вк в добавок к моментальному удалению записей на сервере, есть еще и моментальное удаление этих записей из ленте на клиенте с помощью пушей.
например я добавил фото, а оказалось что это не то фото, и я его сразу удаляю. а у вас оно будет висеть в ленте пока не сработает скрипт в фоне.
Охохо, знали бы вы, сколько там всякой всячины с удалением фото. И посты в ленте, которые удалили или сделали приватными, не такая уж и редкость (когда переходишь по ним, попадаешь на страницу с ошибкой). Более того, там и новый посты не моментально появляются. Часто видишь пост «just now», у которого уже несколько десятков лайков.

А самое главное, в бизнес требованиях к нашей системе необходимости «моментального» удаления небыло. Так что 10-20-30 секунд это абсолютно ок.
Just now имеет фиксированный промежуток времени. Минуту примерно или 30 секунд (не помню точно). 15 лайков собрать за это время легко.
Такая отмазка не катит. Удаление подписки, как и удаление постов (или смена приватности) должна обрабатываться сразу, а не фоновой задачей. Фоновая задача еще может отвалиться и оставить удаленный пост в ленте пользователя, что совсем нехорошо.
Стас, это не «отмазка», а пример из рабочих проектов. При чём не только из тех проектов, в которых я участвовал. Поэтому мне совершенно не понятно ваше хейтерство.
У вас спрашивают как вы решаете проблемы. Вы начинаете отвечать что у других тоже есть проблемы, а у вас это вообще не проблема.

Тога напишите в начале вашего поста те требования, которые были при проектировании. Вы же пишете какбы универсальные способы, а на деле они не покрывают элементарных требований по UX и privacy.

А теперь перейдем к конкретным вопросам:
Фоновая задача может поломаться удалив часть постов из лент, а другие оставив. Каким образом вы делаете так, чтобы все посты гарантированно удалились?
Вы немного перепутали. Я не школьник на экзамене.
То есть ответа на вопрос у вас нет?
Это как выйти на конференции с докладом, а на вопросы по докладу сказать, что вы не на экзамене.
я правильно понял что при последнем подходе мы наполняем кэш опрашивая читаемых пользователей (формируем ленту при чтении), а затем обновляем созданный кэш по модели материализованной ленты, добавляя в него новые записи и удаляя старые?
Зарегистрируйтесь на Хабре, чтобы оставить комментарий