Кеширование постраничных результатов, чистка при обновлении - как решить?

Я создал форум, и мы внедряем решение для кэширования apc и memcache, чтобы сохранить работу базы данных.

Я начал реализовывать слой кэша с ключами, такими как «Categories :: getAll», и, если у меня были данные, специфичные для пользователя, я бы добавил ключи с такими вещами, как идентификатор пользователя, так что вы получите"User::getFavoriteThreads|1471", Когда пользователь добавляет новый избранный поток, я удаляю ключ кеша, и он воссоздает запись.

However, and here comes the problem:

Я хотел кешировать темы на форуме. Достаточно просто, & quot; Форум :: getThreads | $ iForumId & quot ;. Но ... При разбиении на страницы мне нужно разделить это на несколько записей в кеше, например

"Forum::getThreads|$iForumId|$iLimit|$iOffset".

Что нормально, пока кто-нибудь не создаст новую тему на форуме. Теперь мне придется удалить все ключи в"Forum::getThreads|$iForumId", независимо от того, что предел и смещение.

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

Благодарю.

Ответы на вопрос(8)

В ответ на флунгабунгу:

Другой способ реализовать группировку состоит в том, чтобы поместить имя группы плюс порядковый номер в сами ключи и увеличить порядковый номер до «очистить». группа. Вы сохраняете текущий действительный порядковый номер для каждой группы в своем собственном ключе.

например

get seqno_mygroup
23

get mygroup23_mykey
<mykeydata...>
get mygroup23_mykey2
<mykey2data...>

Затем, чтобы "удалить" группа просто:

incr seqno_mygroup

Вуаля:

get seqno_mygroup
24

get mygroup24_mykey
...empty

так далее..

Просто обновление: Я решил, что мнение Джоша об использовании данных было очень хорошим. Люди вряд ли будут продолжать просматривать страницу 50 форума.

Основываясь на этой модели, я решил кэшировать 90 последних тем на каждом форуме. В функции извлечения я проверяю лимит и смещение, чтобы увидеть, находится ли указанный фрагмент потоков в кэше или нет. Если он находится в пределах кеша, я использую array_slice (), чтобы получить нужную часть и вернуть ее.

Таким образом, я могу использовать один ключ кеша для каждого форума, и для очистки / обновления кеша требуется очень мало усилий :-)

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

Спасибо!

Мне удалось решить эту проблему путем расширенияmemcache класс с пользовательским классом (скажем ExtendedMemcache), который имеет защищенное свойство, которое будет содержать хэш-таблицу значений групп и ключей.

ExtendedMemcache->set метод принимает 3 аргумента ($strGroup,$strKey, $strValue) When you call set, it will store the relationship between $strGroup, а также$strKeyв охраняемой собственности, а затем перейти к хранению$strKey в$strValue отношения вmemcache.

Затем вы можете добавить новый метод кExtendedMemcache класс с именем «deleteGroup», который при передаче строки находит ключи, связанные с этой группой, и очищает каждый ключ по очереди.

Это было бы что-то вроде этого: http://pastebin.com/f566e913b Я надеюсь, что все это имеет смысл и работает для вас.

PS. Я полагаю, если вы хотите использовать статические вызовы, защищенное свойство может быть сохранено вmemcache сам под своим собственным ключом. Просто мысль.

Решение Вопроса

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

Если вы обнаружите, что 80% просмотров вашего форума просматривают первую страницу тем, вы можете решить кэшировать только эту страницу. Это будет означать, что чтение и запись в кеш намного проще.

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

Одно из возможных решений - не разбивать кэш потоков на форуме, а поместить информацию о потоках вForum::getThreads|$iForumId, Тогда в вашем PHP-коде вытащите только те, которые вы хотите для данной страницы, например,

$page = 2;
$threads_per_page = 25;
$start_thread = $page * $threads_per_page;

// Pull threads from cache (assuming $cache class for memcache interface..)
$threads = $cache->get("Forum::getThreads|$iForumId");

// Only take the ones we need
for($i=$start_thread; $i<=$start_thread+$threads_per_page; $i++)
{
    // Thread display logic here...
    showThread($threads[$i]);
}

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

 Rexxars21 сент. 2008 г., 01:35
Я думал об этом, но я преобразовываю существующий форум в этот, и один форум имеет 220 000 потоков, что будет много данных для хранения таким образом. Возможно, это лучшее решение, если данных было меньше. Спасибо!

flungabunga: Ваше решение очень близко к тому, что я ищу. Единственное, что мешает мне сделать это, - это сохранять отношения в memcache после каждого запроса и загружать их обратно.

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

Будьте очень осторожны при выполнении такого рода оптимизации, не имея веских фактов для сравнения.

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

Вы, по сути, пытаетесь кэшировать представление, которое всегда будет сложным. Вместо этого вы должны пытаться кэшировать только данные, потому что данные редко меняются. Не кешируйте форум, кешируйте цепочки потоков. Тогда ваш вызов db должен просто вернуть список идентификаторов, который у вас уже есть в вашем кэше. Вызов db будет быстро выполняться на любой таблице MyISAM, и тогда вам не нужно делать большое соединение, которое съедает память db.

 Rexxars21 сент. 2008 г., 01:39
Это, вероятно, хорошее решение, хотя с моей стороны это потребовало бы довольно большой переписки - нужно извлечь много данных (количество сообщений в ветке, ник авторов должен быть объединен из пользовательской таблицы, количество просмотров и т. Д.). Спасибо за предложение!
 20 сент. 2008 г., 23:51
Я не знаю, о какой структуре таблицы вы думаете, но объединение в любом случае не понадобится, если у вас есть таблица потоков. Выгода с точки зрения использования кэша будет незначительной.
 21 сент. 2008 г., 12:02
Похоже, вы могли бы добиться эквивалентного ускорения, немного денормализуя. Сохраните количество сообщений, имя автора, количество просмотров и т. Д. В записи темы.

Ваш ответ на вопрос