【问题标题】:Key groups with APC cache具有 APC 缓存的密钥组
【发布时间】:2012-02-05 12:42:33
【问题描述】:

APC 允许您将数据存储在键中,但您不能对这些键进行分组。

因此,如果我想要一个名为“articles”的组,并且在该组中我将拥有采用文章 ID 形式的键,我将无法轻松做到这一点。

articles -> 5   -> cached data
         -> 10  -> cached data
         -> 17  -> cached data

         ...

我可以在键前加上“组”名称,例如:

article_5   -> cached data
article_10  -> cached data
article_17  -> cached data

 ...

但是,如果我想删除整个组,就不可能:(

一个可行的解决方案是存储多维数组(这是我现在正在做的),但我不认为这很好,因为当我想访问/或删除缓存数据时,我需要获取整个组第一的。因此,如果该组中有无数篇文章,您可以想象我将迭代和搜索什么样的数组

您对我如何实现小组目标有更好的想法吗?


编辑: 找到了另一个解决方案,不确定它是否更好,因为我还不知道可靠程度如何。我正在添加一个名为__paths 的特殊键,它基本上是一个多维数组,其中包含缓存中所有其他条目的完整前缀键路径。当我请求或删除缓存时,我使用这个数组作为参考来快速找出我需要删除的键(或键组),所以我不必存储数组并遍历所有键......

【问题讨论】:

    标签: php arrays caching apc


    【解决方案1】:

    根据您的观察,我查看了 APC 的缓存模型 (apc_cache.c) 的底层 C 实现,看看我能找到什么。

    来源证实了您的观察,即后备数据存储中不存在分组结构,因此任何松散分组的对象集合都需要基于某些命名空间约束或对缓存层本身的修改来完成。我希望通过链表找到一些依赖于键链的后门,但不幸的是,似乎通过直接重新分配碰撞槽而不是chaining来协调碰撞。

    进一步混淆了这个问题,APC 似乎对用户条目使用显式缓存模型,以防止它们老化。因此,很遗憾,依赖于 memcachedLRU 模型的 the solution Emil Vikström provided 将不起作用。

    在不修改 APC 本身的源代码的情况下,我会这样做:

    1. 定义条目符合的命名空间约束。正如您在上面最初定义的那样,这将类似于 article_ 附加到您的每个条目中。

    2. 定义一个单独的这个集合中的元素列表。实际上,这将是您上面描述的51017 方案,但在这种情况下,您可以使用一些数字类型来使其比存储大量字符串值更有效。

    3. 定义一个接口来更新这组指针并将它们与后备内存缓存相协调,包括(至少)方法insertdeleteclear .当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;
        }
    }
    

    因此,我强烈建议您使用高效的、基于指针的虚拟分组解决方案来解决您的问题,正如我在上面所概述的那样。尽管在内存严重受限的情况下,迭代器方法可能是最正确的,可以以牺牲计算为代价节省尽可能多的内存。

    祝你的申请好运。

    【讨论】:

      【解决方案2】:

      我曾经在使用 memcached 时遇到过这个问题,我通过在我的密钥中使用版本号解决了这个问题,如下所示:

      version -> 5
      article_5_5 -> cached data
      article_10_5 -> cached data
      article_17_5 -> cached data
      

      只需更改版本号,该组将有效“消失”!

      memcached 使用最近最少使用策略来删除旧数据,以便在需要空间时从缓存中删除旧版本组。 不知道APC有没有同样的功能


      根据MrGomez,这不适用于 APC。请阅读他的帖子,并记住我的帖子仅适用于 other 使用最近最少使用策略(不是 APC)的缓存系统。

      【讨论】:

      • APC 没有 LRU 策略,但 apc_add 确实允许 TTL,即生存时间。在这种情况下,对于此类数据,Memcache 将是更好的选择,因为它具有 LRU。
      【解决方案3】:

      您可以使用APCIterator class,它似乎特别适用于这样的任务:

      APCIterator 类可以更轻松地迭代大型 APC 缓存。这很有帮助,因为它允许逐步迭代大型缓存...

      【讨论】:

        【解决方案4】:

        很遗憾,APC 无法做到这一点。我经常希望自己能够做到。所以我寻找替代品。

        Zend_Cache 有一个有趣的方法,但它只是使用缓存来缓存标记信息。它是一个可以反过来使用后端(如 apc)的组件。

        如果你想更进一步,你可以安装Redis。这个具有原生包含的所有内容以及其他一些非常有趣的功能。这可能是最干净的解决方案。如果你能使用 APC,你应该也能使用 Redis。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-02-04
          • 2017-04-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-03
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多