APC允许您将数据存储在密钥中,但您无法对这些密钥进行分组。
所以,如果我想要一个名为“文章”的组,并且在这个组中,我会使用文章ID的形式,我不能轻易做到这一点。
articles -> 5 -> cached data
-> 10 -> cached data
-> 17 -> cached data
...
我可以在密钥前面添加“group”名称,如:
article_5 -> cached data
article_10 -> cached data
article_17 -> cached data
...
但如果我愿意,这就不可能删除整个组:(
一个可行的解决方案是存储多维数组(这就是我现在正在做的),但我不认为这很好,因为当我想访问/或删除缓存数据时,我需要获得整个组第一。因此,如果该组中有一篇文章,您可以想象我将迭代和搜索的数组类型
你对如何实现小组活动有更好的想法吗?
<小时/> 编辑找到了另一种解决方案,不确定它是否更好,因为我不知道它有多可靠。我正在添加一个名为
__paths
的特殊键,它基本上是一个多维数组,包含缓存中所有其他条目的完整前缀键路径。当我请求或删除缓存时,我使用此数组作为参考,以快速找到我需要删除的密钥(或密钥组),因此我不必存储数组并通过所有密钥迭代... < p>
答案 0 :(得分:18)
根据您的观察,我查看了APC的缓存模型(apc_cache.c
)的基础C实现,以查看我能找到的内容。
源证实了您的观察结果,即后备数据存储中不存在分组结构,因此需要根据某些命名空间约束或对缓存层本身的修改来完成任何松散分组的对象集合。我希望通过链表找到一些依赖于密钥链接的后门,但不幸的是,似乎通过直接重新分配冲突槽而不是chaining来协调冲突。
进一步混淆了这个问题,APC似乎对用户条目使用显式缓存模型,防止它们老化。因此,遗憾的是,依赖于 memcached 的the solution Emil Vikström provided模型的LRU将无效。
不修改APC本身的源代码,这就是我要做的事情:
定义条目符合的命名空间约束。正如您最初在上面定义的那样,每个条目都会加上article_
。
在此集合中定义单独的元素列表。实际上,这将是您上面描述的5
,10
和17
方案,但在这种情况下,您可以使用某种数字类型来提高效率,而不是存储很多字符串值。
定义接口以更新这组指针并将它们与支持内存缓存进行协调,包括(至少)方法insert
,delete
,和clear
。调用clear
时,遍历每个指针,重新构建在后备数据存储中使用的密钥,并从缓存中刷新每个指针。
我在这里提倡的是一个明确定义的对象,它可以有效地执行 的操作。这与子缓存中的条目数呈线性关系,但由于您对每个元素使用数字类型,因此在开始体验实际内存痛苦之前,您需要超过1亿条目,例如,几百兆字节。
Tamas Imrei打败我suggesting an alternate strategy我已经处于记录过程中,但这有一些我想讨论的重大缺陷。
正如支持C代码中所定义的,APCIterator
是在执行搜索时使用其构造函数public __construct ( string $cache [, mixed $search = null ...]] )
在整个数据集上的线性时间操作。
在您搜索的支持元素占总数据的一小部分时,这是非常不受欢迎的,因为它会遍历缓存中的每个元素以找到您想要的元素。引用apc_cache.c
:
/* {{{ apc_cache_user_find */
apc_cache_entry_t* apc_cache_user_find(apc_cache_t* cache, char *strkey, \
int keylen, time_t t TSRMLS_DC)
{
slot_t** slot;
...
slot = &cache->slots[h % cache->num_slots];
while (*slot) {
...
slot = &(*slot)->next;
}
}
因此,我强烈建议您使用基于指针的高效虚拟分组解决方案来解决您的问题,如上所述。虽然,在严格限制内存的情况下,迭代器方法可能是最正确的,以牺牲计算为代价来节省尽可能多的内存。
祝你的申请好运。
答案 1 :(得分:4)
我在memcached中遇到过这个问题,我通过使用我的密钥中的版本号解决了这个问题,如下所示:
version -> 5
article_5_5 -> cached data
article_10_5 -> cached data
article_17_5 -> cached data
只需更改版本号,该组将有效“消失”!
memcached使用最近最少使用的策略来删除旧数据,以便在需要空间时从缓存中删除旧版本的组。 我不知道APC是否具有相同的功能。
根据MrGomez,这不适用于APC。请阅读他的帖子,并记住仅针对使用最近最少使用的策略(不是APC)的其他缓存系统的帖子。
答案 2 :(得分:3)
你可以使用似乎存在的APCIterator class,特别是对于这样的任务:
APCIterator类可以更轻松地迭代大型APC缓存。这很有用,因为它允许在步骤中迭代大缓存......
答案 3 :(得分:1)
不幸的是,APC无法做到这一点。我经常希望自己能够这样做。所以我寻找替代方案。
Zend_Cache有一种有趣的方法,但它只是使用缓存来缓存标记信息。它是一个可以反过来使用后端的组件(如apc)。
如果您想更进一步,可以安装Redis。这个包括所有原生包含的和其他一些非常有趣的功能。这可能是最干净的解决方案。如果您能够使用APC,您也应该能够使用Redis。