如何使用PHP查询Memcached以获取存储的所有键列表?

9

我需要将memcached复制到另一个键值存储系统(couchbase)。如何查询memcached服务器中的内容,以获取其中的列表,以便我可以将其复制?


https://gist.github.com/vanjos/7013411 - prayagupa
5个回答

13

所有这些解决方案都是针对Memcache,这里是针对Memcached的解决方案。


function getMemcachedKeys($host = '127.0.0.1', $port = 11211)
{

    $mem = @fsockopen($host, $port);
    if ($mem === FALSE) return -1;

    // retrieve distinct slab
    $r = @fwrite($mem, 'stats items' . chr(10));
    if ($r === FALSE) return -2;

    $slab = array();
    while (($l = @fgets($mem, 1024)) !== FALSE) {
        // sortie ?
        $l = trim($l);
        if ($l == 'END') break;

        $m = array();
        // <STAT items:22:evicted_nonzero 0>
        $r = preg_match('/^STAT\sitems\:(\d+)\:/', $l, $m);
        if ($r != 1) return -3;
        $a_slab = $m[1];

        if (!array_key_exists($a_slab, $slab)) $slab[$a_slab] = array();
    }

    // recuperer les items
    reset($slab);
    foreach ($slab AS $a_slab_key => &$a_slab) {
        $r = @fwrite($mem, 'stats cachedump ' . $a_slab_key . ' 100' . chr(10));
        if ($r === FALSE) return -4;

        while (($l = @fgets($mem, 1024)) !== FALSE) {
            // sortie ?
            $l = trim($l);
            if ($l == 'END') break;

            $m = array();
            // ITEM 42 [118 b; 1354717302 s]
            $r = preg_match('/^ITEM\s([^\s]+)\s/', $l, $m);
            if ($r != 1) return -5;
            $a_key = $m[1];

            $a_slab[] = $a_key;
        }
    }

    // close
    @fclose($mem);
    unset($mem);

    // transform it;
    $keys = array();
    reset($slab);
    foreach ($slab AS &$a_slab) {
        reset($a_slab);
        foreach ($a_slab AS &$a_key) $keys[] = $a_key;
    }
    unset($slab);

    return $keys;
}

1
尽管人们还没有为它投票,但这是目前最好的答案;问题提问者询问的是带有“d”的Memcached。我不知道为什么Mark Baker的回答得到了那么多赞。 - Ryan
1
同意,最佳答案。 - Hakro
stats cachedump 返回的数据是不完整的(只返回 COLD 项,最多返回 2MB 的数据,在上述代码中每个 slab 只返回前 100 项),在运行时会锁定整个缓存,因为它仅用于小型测试和调试目的,所以被定期讨论从代码库中删除。lru_crawler 听起来更有前途:https://stackoverflow.com/a/60604336/2809546 - Vlad

10

memcache >= 2.0.0

function getMemcacheKeys() {
    $memcache = new Memcache;
    $memcache->connect('127.0.0.1', 11211) 
       or die ("Could not connect to memcache server");

    $list = array();
    $allSlabs = $memcache->getExtendedStats('slabs');
    $items = $memcache->getExtendedStats('items');
    foreach($allSlabs as $server => $slabs) {
        foreach($slabs AS $slabId => $slabMeta) {
            $cdump = $memcache->getExtendedStats('cachedump',(int)$slabId);
            foreach($cdump AS $keys => $arrVal) {
                if (!is_array($arrVal)) continue;
                foreach($arrVal AS $k => $v) {                   
                    echo $k .'<br>';
                }
            }
        }
    }   
} 

3
我想在这里提醒一下,虽然这种方法可以运作,但cachedump实际上是用于memcached调试目的,不应该像这样使用。而且未来版本的memcached也可能不再支持cachedump。(请参见memcached核心贡献者之一在此处的注释8 http://code.google.com/p/memcached/issues/detail?id=187) - mikewied
2
Cachedump似乎无法获取所有键(我一直在尝试这样做,然后发现了这个链接):http://code.google.com/p/memcached/wiki/NewProgrammingFAQ - jonderry
一个对我很有用的小但重要的区别是 getExtendedStats 函数中的 limit 参数,默认值仅为100。 更新: $cdump = $memcache->getExtendedStats('cachedump',(int)$slabId,100000000); - matija
这个函数有缺陷,因为它会使memcache处于只读状态,至少对于当前版本的memcache PECL(3.0.8)和memcached(1.4.21)是这样。 - eithed
@matija,你可以将0作为最后一个参数传递,以完全删除限制。 - Gruffy
那是memcache,问题是关于memcached的。它们是不同的库。 - Apollo

1
根据报告https://www.php.net/manual/en/memcached.getallkeys.php#123793,函数Memcached::getAllKeys自memcached 1.4.23以来就不起作用了。而且它不能保证返回所有键。
由@mark-baker、@maduka-jayalath和其他人提供的基于stats cachedump的代码有局限性,在你的memcache中有数百万个键的情况下无法返回所有键。它还会对memcache服务器产生性能影响。
有一个库可以异步地迭代所有memcache键,而不会影响性能:https://github.com/qmegas/memcache-search。它甚至不需要安装任何memcache扩展程序。

1
你是不是想说自1.4.23版本以来"Memcached::getAllKeys不起作用"?这就是你所引用链接中的内容。 - Don't Panic
1
@Don'tPanic 是的,你说得对,那是个打字错误。我已经编辑了我的消息。 - Megas

-1

-2

感谢提供示例代码

以下是如何删除特定键或多个键的方法

我正在使用一个辅助类来删除缓存,因此您必须向函数提供对memcache连接的引用

public static function removePriceCache(&$memcache, &$cacheAvailable) {

    if ($cacheAvailable == true) {
        $list = array();
        $allSlabs = $memcache->getExtendedStats('slabs');
        $items = $memcache->getExtendedStats('items');
        foreach ($allSlabs as $server => $slabs) {
            foreach ($slabs AS $slabId => $slabMeta) {
                $cdump = $memcache->getExtendedStats('cachedump', (int) $slabId);
                foreach ($cdump AS $keys => $arrVal) {
                    if (!is_array($arrVal))
                        continue;
                    foreach ($arrVal as $k => $v) {
                        //echo $k . '<br>';

                        if (stripos($k, "Price") !== false) {
                            $memcache->delete($k);
                        }
                    }
                }
            }
        }
    }
}

这将删除所有包含单词“Price”的键。


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