2008-09-20 6 views
5

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

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

Однако и здесь возникает проблема:

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

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

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

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

Спасибо.

ответ

5

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

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

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

2

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

+0

Я не знаю, о какой структуре таблиц вы подумываете, но в любом случае соединение не понадобится, если у вас есть таблица потоков. Преимущество использования кеша было бы незначительным. – 2008-09-20 21:51:57

+0

Это, вероятно, хорошее решение, хотя с моей стороны потребуется довольно большой переписать - есть много данных для извлечения (количество сообщений в потоке, ник авторов должен быть соединен с пользовательской таблицей, количеством просмотров и т. Д.). , Спасибо за предложение! – Rexxars 2008-09-20 23:39:05

1

Одно из возможных решений заключается не в том, чтобы разбивать кеш-потоки на форуме, а скорее на информацию о потоке в 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]); 
} 

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

5

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

Метод ExtendedMemcache->set принимает 3 арг ($strGroup, $strKey, $strValue) При вызове установлен, он будет сохранять отношения между $strGroup и $strKey, в защищенной собственности, а затем перейти, чтобы сохранить отношения $strKey к $strValue в memcache.

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

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

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

1

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

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

1

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

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

7

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

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

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

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

Спасибо!

1

В ответ на flungabunga:

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

например.

get seqno_mygroup 
23 

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

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

incr seqno_mygroup 

Вуаля:

get seqno_mygroup 
24 

get mygroup24_mykey 
...empty 

и т.д ..

 Смежные вопросы

  • Нет связанных вопросов^_^