内存缓存和通配符

Posted

技术标签:

【中文标题】内存缓存和通配符【英文标题】:memcache and wildcards 【发布时间】:2010-12-08 10:18:38 【问题描述】:

我只是想知道是否有一种方法可以使用通配符作为键值来清除内存缓存。

假设我有一个带有键“1234~foo”和另一个“1234~foo~bar”的缓存。

我有什么办法可以通过使用 clear("1234*") 之类的方法来清除缓存并从上面清除它们吗?

我希望这是有道理的。

谢谢。

【问题讨论】:

【参考方案1】:

不,没有直接简单的方法可以做到这一点。 FAQ 解决了这个问题,并提供了一种解决方法:

按命名空间删除

虽然 memcached 不支持任何类型的通配符删除或按命名空间删除(因为没有命名空间),但可以使用一些技巧来模拟这一点。但是,它们确实需要额外访问 memcached 服务器。

php 中使用名为 foo 的命名空间的示例:

$ns_key = $memcache->get("foo_namespace_key");
// if not set, initialize it
if($ns_key===false) 
    $ns_key=rand(1, 10000);
    $memcache->set("foo_namespace_key", $ns_key);

// cleverly use the ns_key
$my_key = "foo_".$ns_key."_12345";
$my_val = $memcache->get($my_key);

//To clear the namespace do:
$memcache->increment("foo_namespace_key");

【讨论】:

这个解决方案太酷了。但是,为什么 memcached 规划器会忽略通配符删除这样的(看似)不可或缺的功能呢?我猜是某种性能原因。有人知道吗? 他们并没有忽视它——相反,数据结构并不是为了处理它而构建的。 Memcache 最重要的是原始速度,并且没有索引或排序。你必须列举一切。因此,由您来解决。 Memcache 通常针对 O(1) 操作。通过通配符删除不是 O(1),并且可能会在相对较长的时间内锁定服务器。见code.google.com/p/memcached/wiki/NewOverview IMO,你不能在 memcached 中创建区域或部分,这很糟糕。 App Fabric 就是这样做的。而不是存储对象,您可以实际存储类型。 丑陋的黑客。您的条目仍然存在。你没有删除它们。根据您的用例,希望条目在短时间内“脱落”是不够的。【参考方案2】:

Eric Petroelje 关于命名空间解决方案的说明:

请记住,您不知道 memcached 何时会驱逐您的命名空间键。 Memcache 可能会驱逐您的命名空间键,然后在尝试设置新键时,它有 1 到 10000 的概率会选择相同的索引键 - 这意味着您将获得“脏”结果。这不太可能,但归根结底,它并不安全。

Poul Vernon 的解决方案也存在同样的问题。

一个安全的解决方案是为“指针键”/“命名空间键”使用可靠的存储(例如磁盘)。

【讨论】:

使用Memcached::touch 将确保Paul Vernons 的解决方案保持完整。 @AVIDeveloper 否,因为我们仍然不确定,memcache 何时/是否会驱逐密钥,“触摸”仅“为项目设置新的过期时间”。而且该解决方案也存在竞争条件问题。 只能使用时间戳。更正它在你下面过期,但这实际上是一个早期/意外的缓存刷新。如果您无法处理所有相关键的刷新,那么此解决方案无论如何都不适合您。【参考方案3】:

这个函数在php中怎么样:

function deleteKeysByIndex($search) 
    $m = new Memcached();
    $m->addServer('localhost', 11211);
    $keys = $m->getAllKeys();
    foreach ($keys as $index => $key) 
        if (strpos($key,$search) !== false) 
            $m->delete($key);
         else 
            unset($keys[$index]);
        
    

    // returns an array of keys which were deleted
    return $keys;

删除以 $prefix 开头的键并返回所有已删除键的列表。我刚才在共享服务器上运行了 30,000 多个密钥,而且速度非常快 - 可能不到一秒。

【讨论】:

也可以通过将匹配的键存储到数组中并在末尾使用$m->deleteMulti($keys)来实现。php.net/manual/en/memcached.deletemulti.php 问题在于您需要在一个脚本或会话中完成所有操作。这里的想法是,我可以随时随地在服务器上运行此代码,并删除密钥。 在这种情况下,单独删除它们非常有意义。使用您的方法,可以取消执行并在需要时重新启动它。我实际上想知道deletedeleteMulti 在性能方面是否有任何区别,但我认为您只能真正观察到 1M+ 键的任何区别。 memcached getAllKeys 不保证返回所有键。 php.net/manual/en/memcached.getallkeys.php @awm - 没有。这将要求密钥以$search 开头。这将删除任何位置包含$search 的键。【参考方案4】:

为“1234”创建一个内存缓存条目,并在其中存储相关键的数组。在您的删除例程中读取并遍历这些键以删除。

【讨论】:

我之前试过这个方法,但是在重负载下它不起作用,因为删除关联数组中所有键的速度不够快。 +1 是唯一有效的解决方案。另一个需要一个希望和一个祈祷(没有兰特碰撞和及时的条目下降)。 关于ksvendsen 的回复,使用Memcached::touch 将确保解决方案保持完整。

以上是关于内存缓存和通配符的主要内容,如果未能解决你的问题,请参考以下文章

如何为linux释放内存和缓存

Chrome 内存缓存与磁盘缓存

gpu性能和gpu内存

内存缓存与。内存缓存 [重复]

第三章 - CPU缓存结构和java内存模型

将 LRU 图像缓存与 HTTPResponseCache 结合用于磁盘和内存缓存