如何在memcached中删除具有相同前缀键的项目?

31

比如,我有一些具有相同前缀的缓存项,例如

'app_111111', 'app_222222', 'app_333333', ...

我能通过哪些memcached命令删除这些名为 'app_xxxxxx' 的项吗?

->

是否可以通过任何Memcached命令删除这些名为'app_xxxxxx'的项?


1
https://dev59.com/3XI-5IYBdhLWcg3w9tdw - Aaron W.
4个回答

42

Memcached默认不提供此功能,因此您需要自己构建。

我的解决方法是在我的应用程序中定义前缀(或命名空间)以表示键组。我在Memcached中设置的任何键都有该前缀。每当我想要从Memcached“删除”内容时,我只需更改前缀。每当我想要在Memcached中查找键时,我将该前缀添加到它上面。

在您的情况下,您可以首先将前缀设置为MyAppPrefix1,这样您的键将被存储为MyAppPrefix1::app_333333MyAppPrefix1::app_444444等。

稍后,当您想要“删除”这些条目时,请将您的应用程序设置为使用MyAppPrefix2。然后,当您尝试从Memcached获取名为app_333333的键时,它将查找MyAppPrefix2::app_333333,第一次找不到,就像已被删除一样。


5
你要如何删除旧记录?通过时间过期吗? - Alfonso Fernandez-Ocampo
1
@AlfonsoFernandez-Ocampo 当然可以,为什么不呢?当需要时,Memcache会删除它们。 - yefrem
1
看起来很不错,但是Memcached会在过期时间到达或即将满时删除吗? - kscius

9

这个php函数怎么样:

function deletekeysbyindex($prefix) {
    $m = new Memcached();
    $m->addServer('localhost', 11211);
    $keys = $m->getAllKeys();
    foreach ($keys as $index => $key) {
        if (strpos($key,$prefix) !== 0) {
            unset($keys[$index]);
        } else {
            $m->delete($key);
        }
    }
    return $keys;
}

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


2
这并不保证可行。由于memcache不能保证返回所有键,因此您也不能假设已返回所有键。 http://php.net/manual/zh/memcached.getallkeys.php - Timothy Martens
3
感谢 @TimMartens 指出这一点。我想这已经是最好的结果了吧?我希望能有更多关于 getAllKeys() 方法在何时和为何可能不能正常工作的信息...你能提供一些启示吗?文档并没有太大帮助。 - But those new buttons though..

1
这是一个可行的方法,尽管有点慢。在一个有60万个键的服务器上,完成这个操作需要半秒钟的时间。
    $prefix = 'MyApp::Test';
    $len = strlen($prefix);

    $proc = popen('/usr/local/bin/memdump --servers=localhost', 'r');
    while (($key = fgets($proc)) !== false) {
        if (substr_compare($key, $prefix, 0, $len) === 0) {
            $memcached->delete(substr($key, 0, -1));
        }
    }

0

我们不能在一个请求中完成对memcache的操作,我们只能这样做:

public function clearByPrefix($prefixes = array()) {
    $prefixes = array_unique($prefixes);

    $slabs = $this->memcache->getExtendedStats('slabs');
    foreach ($slabs as $serverSlabs) {
        if ($serverSlabs) {
            foreach ($serverSlabs as $slabId => $slabMeta) {
                if (is_int($slabId)) {
                    try {
                        $cacheDump = $this->memcache->getExtendedStats('cachedump', (int) $slabId, 1000);
                    } catch (Exception $e) {
                        continue;
                    }

                    if (is_array($cacheDump)) {
                        foreach ($cacheDump as $dump) {
                            if (is_array($dump)) {
                                foreach ($dump as $key => $value) {

                                    $clearFlag = false;
                                    // Check key has prefix or not
                                    foreach ($prefixes as $prefix) {
                                        $clearFlag = $clearFlag || preg_match('/^' . preg_quote($prefix, '/') . '/', $key);
                                    }
                                    // Clear cache
                                    if ($clearFlag) {
                                        $this->clear($key);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

然后像这样调用该函数:

        $prefixes = array();

        array_push($prefixes, 'prefix1_');
        array_push($prefixes, 'prefix2_');
        array_push($prefixes, 'prefix3_');

        $this->clearByPrefix($prefixes);

1
即使您的代码似乎很容易理解,您也可以解释它的作用以及为什么您认为这个解决方案有助于提问者。顺便说一句,如果您只需要调用strpos函数,使用preg_match函数就有些过度了。 - Andras Gyomrey
也许我应该在我的代码中加更多注释 :) 关于preg_match,我不认为这是过度的。你知道,对于这种情况来说,它只是一件简单的事情。我甚至打算将正则表达式在未来变得更复杂。:)谢谢你的评论,兄弟! - Thanh Vo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接