Я создал форум, и мы реализуем решение кэширования apc и memcache для сохранения работы базы данных.
Я начал внедрять уровень кэша с такими ключами, как «Категории :: getAll», и если бы у меня были данные, специфичные для пользователя, я бы добавил ключи с такими же "User::getFavoriteThreads|1471"
как идентификатор пользователя, поэтому вы получите "User::getFavoriteThreads|1471"
. Когда пользователь добавил новый любимый поток, я бы удалил ключ кеша, и он воссоздал запись.
Однако и здесь возникает проблема:
Я хотел кэшировать потоки на форуме. Достаточно просто, «Форум :: getThreads | $ iForumId». Но … С разбиением на страницы мне пришлось бы разбить это на несколько записей кэша, например
"Forum::getThreads|$iForumId|$iLimit|$iOffset".
Что хорошо, пока кто-то не добавляет новую тему в форум. Теперь я должен удалить все ключи в разделе "Forum::getThreads|$iForumId"
, независимо от того, какой предел и смещение.
Что было бы хорошим способом решения этой проблемы? Я бы предпочел не перебирать все возможные пределы и смещать, пока не найду что-то, что больше не соответствует.
Благодарю.
Вы также можете взглянуть на стоимость хранения данных кэша с точки зрения ваших усилий и стоимости процессора против того, что будет покупать ваш кеш.
Если вы обнаружите, что 80% просмотров вашего форума просматривают первую страницу потоков, тогда вы можете решить кешировать только эту страницу. Это означало бы, что чтение и запись в кэше намного проще для имплантации.
Аналогично со списком любимых тем пользователя. Если это то, что каждый человек посещает редко, кеш может не слишком повысить производительность.
Просто обновление: я решил, что точка Джоша в использовании данных была очень хорошей. Люди вряд ли будут просматривать страницу 50 форума.
Основываясь на этой модели, я решил кэшировать 90 последних тем в каждом форуме. В функции выборки я проверяю лимит и смещение, чтобы увидеть, находится ли указанный срез потоков в кеше или нет. Если он находится в пределах кеша, я использую array_slice () для извлечения правой части и возврата ее.
Таким образом, я могу использовать один кэш-ключ для каждого форума, и для очистки / обновления кеша требуется очень мало усилий 🙂
Я также хотел бы отметить, что в других более тяжелых тяжелых запросах я пошел с моделью flungabunga, сохраняя отношения между ключами. К сожалению, переполнение стека не позволит мне принять два ответа.
Благодаря!
Мне удалось решить эту проблему, расширив класс memcache
с помощью специального класса (например, ExtendedMemcache), который имеет защищенное свойство, которое будет содержать хеш-таблицу из группы с ключевыми значениями.
Метод ExtendedMemcache->set
принимает 3 аргумента ( $strGroup
, $strKey
, $strValue
). Когда вы вызываете set, он сохраняет связь между $strGroup
и $strKey
в защищенном свойстве, а затем продолжает хранить $strKey
к отношениям $strValue
в memcache
.
Затем вы можете добавить новый метод в класс ExtendedMemcache
называемый «deleteGroup», который при передаче строки найдет ключи, связанные с этой группой, и по очереди очистит каждый ключ.
Это было бы примерно так: http://pastebin.com/f566e913b Надеюсь, все это имеет смысл и работает для вас.
PS. Я полагаю, что если вы хотите использовать статические вызовы, защищенное свойство может быть сохранено в memcache
самостоятельно под собственным ключом. Просто мысль.
Вы по существу пытаетесь кэшировать представление, которое всегда будет сложно. Вместо этого вы должны пытаться кэшировать данные только потому, что данные редко меняются. Не кэшируйте форум, кешируйте строки потоков. Затем ваш вызов db должен просто вернуть список идентификаторов, которые у вас уже есть в вашем кеше. Вызов db будет быстро освещаться в любой таблице MyISAM, а затем вам не нужно делать большое соединение, которое ест память db.
Одно из возможных решений заключается не в том, чтобы разбивать кеш потоков на форуме, а скорее на поток информации на 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]); }
Это означает, что у вас есть немного больше работы, чтобы вытащить их на каждой странице, но теперь нужно только беспокоиться о том, чтобы недействить кеш в одном месте при обновлении / добавлении нового потока.
flungabunga: Ваше решение очень близко к тому, что я ищу. Единственное, что мешает мне сделать это, – это сохранить отношения в memcache после каждого запроса и загрузить их обратно.
Я не уверен, насколько это повлияло бы на производительность, но это кажется немного неэффективным. Я сделаю некоторые тесты и посмотрю, как это происходит. Спасибо за структурированное предложение (и некоторый код, чтобы показать его, спасибо!).
Будьте очень осторожны в том, чтобы делать такую оптимизацию, не имея трудных фактов для измерения.
В большинстве баз данных имеется несколько уровней кэшей. Если они настроены правильно, база данных, вероятно, будет намного лучше работать в кешировании, чем вы можете сделать сами.
В ответ на flungabunga:
Другой способ реализации группировки – поместить имя группы и порядковый номер в сами ключи и увеличить порядковый номер, чтобы «очистить» группу. Вы сохраняете текущий действительный порядковый номер для каждой группы в своем собственном ключе.
например
get seqno_mygroup 23 get mygroup23_mykey <mykeydata...> get mygroup23_mykey2 <mykey2data...>
Затем просто «удалить» группу:
incr seqno_mygroup
Вуаля:
get seqno_mygroup 24 get mygroup24_mykey ...empty
и т.д..