我已经创建了一个论坛,我们正在实现一个apc和memcache缓存解决方案,以便为数据库保存一些工作。

我开始使用像“Categories :: getAll”这样的键来实现缓存层,如果我有特定于用户的数据,我会使用像用户ID之类的东西来附加密钥,这样你就可以得到 "用户:: getFavoriteThreads | 1471" 。当用户添加新的收藏夹线程时,我将删除缓存键,它将重新创建该条目。

然而,问题出现了:

我想在论坛中缓存线程。很简单,“论坛:: getThreads | $ iForumId”。但是......通过分页,我必须将其分成几个缓存条目,例如

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

哪个好,直到有人在论坛中发帖新帖。我现在必须删除" Forum :: getThreads | $ iForumId" 下的所有密钥,无论限制和偏移是什么。

解决这个问题的好方法是什么?我真的不想循环遍历每个可能的限制和偏移,直到找到不再匹配的东西。

感谢。

有帮助吗?

解决方案

您可能还想了解一下根据您的工作量和CPU成本存储缓存数据的成本,以及缓存将如何为您购买的成本。

如果您发现80%的论坛视图正在查看主题的第一页,那么您可以决定仅缓存该页面。这意味着缓存读取和写入都更容易实现。

与用户最喜欢的主题列表相同。如果这是每个人很少访问的内容,那么缓存可能无法提高性能。

其他提示

只是更新: 我认为Josh关于数据使用的观点非常好。 人们不太可能继续查看论坛的第50页。

基于这个模型,我决定在每个论坛中缓存90个最新的线程。在提取函数中,我检查limit和offset以查看指定的线程片段是否在缓存中。如果它在缓存限制范围内,我使用array_slice()来检索正确的部分并将其返回。

这样,我可以在每个论坛使用一个缓存密钥,清理/更新缓存只需要很少的工作量: - )

我还想指出,在其他资源较多的查询中,我使用了flungabunga的模型,存储了密钥之间的关系。不幸的是,Stack Overflow不会让我接受两个答案。

谢谢!

我设法通过使用自定义类(比如ExtendedMemcache)扩展 memcache 类来解决这个问题,该类具有受保护的属性,该属性将包含组到键值的哈希表。

ExtendedMemcache-> set 方法接受3个args( $ strGroup $ strKey $ strValue ) 当你调用set时,它将在受保护的属性中存储 $ strGroup $ strKey 之间的关系,然后继续存储 $ strKey memcache 中的代码>到 $ strValue 关系。

然后,您可以将新方法添加到名为“deleteGroup”的 ExtendedMemcache 类中,当传递字符串时,将找到与该组关联的键,并依次清除每个键。

这将是这样的: http://pastebin.com/f566e913b 我希望所有这些都有意义,并为你效劳。

PS。我想如果你想使用静态调用,protected属性可以保存在 memcache 本身的自己的密钥下。只是一个想法。

你实际上是在尝试缓存一个视图,这总是会变得棘手。您应该尝试仅缓存数据,因为数据很少更改。不要缓存论坛,缓存线程行。然后你的db调用应该只返回你已经在缓存中的id列表。数据库调用将在任何MyISAM表上快速闪烁,然后您不必进行大型连接,这会占用数据库内存。

一种可能的解决方案是不在论坛中对线程的缓存进行分页,而是将线程信息放入 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:

实现分组的另一种方法是将组名加序号放入密钥本身,并将序列号增加到“清除”。群组。您可以将每个组的当前有效序列号存储在其自己的密钥中。

e.g。

get seqno_mygroup
23

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

然后“删除”小组只是:

incr seqno_mygroup

瞧:

get seqno_mygroup
24

get mygroup24_mykey
...empty

等。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top