获取在Memcached中所有已设置的键

171

如何获取我所有的memcached实例中设置的键(keys)?

我尝试过搜索,但除了 PHP 支持 getAllKeys 方法之外,并没有发现更多信息。这意味着以某种方式实现是可能的。在telnet会话中如何做到相同效果?

我已经尝试了在Memcached查找表Memcached telnet命令摘要中提到与检索相关的所有选项,但它们都不起作用,我无法找到正确的方法来实现。

注意:目前我正在开发中,因此可以假定不会出现由于设置新键或其他竞争条件而导致的问题,而且键数目也将受到限制。


请查看我的帖子。我曾经遇到同样的问题,但是我找到了解决方案。 - Peter VARGA
https://github.com/clickalicious/phpmemadmin 看起来很有用(如果我能弄清楚如何在Laravel Homestead Vagrant上使用它;目前它显示没有密钥)。 - Ryan
9个回答

227

感谢这个链接(附带原始的谷歌小组讨论),我找到了一种方法:

首先,使用Telnet连接到您的服务器:

telnet 127.0.0.1 11211

接下来,列出获取板块 id 的项:

统计项目
STAT items:3:number 1
STAT items:3:age 498
STAT items:22:number 1
STAT items:22:age 498
END

'items' 后面的第一个数字是板块 id。为每个板块 id 请求缓存转储,限制最大要转储的键数:

统计缓存转储 3 100
ITEM views.decorators.cache.cache_header..cc7d9 [6 b; 1256056128 s]
END
统计缓存转储 22 100 ITEM views.decorators.cache.cache_page..8427e [7736 b; 1256056128 s] END

4
请注意,stats cachedump是一个未记录在案的功能,并不受memcached团队支持。它仅用于调试,不适用于生产环境。 - mikewied
4
b 表示字节,s 表示纪元时间秒数。 - Abraham Sangha
2
@Dan 也许你是按照活跃回答来查看的,这会根据它们最后一次活动的时间对答案帖子进行排序。如果是这样,你可以通过从问题文本下方选择其中一个“活跃/最旧/投票”来更改。除此之外,在隐身模式下,这个答案是排在最前面的。 - Anshul Goyal
1
@NikhilTalreja,随意发布更好的答案以造福社区,这个对我当时的使用情况有效。 - Anshul Goyal
8
还有一个命令 lru_crawler metadump all,它可以转储所有缓存键,而不仅仅是前1M个... https://github.com/memcached/memcached/blob/bb0980fbbafd4eb723f76918e7ca364360315c1b/doc/protocol.txt#L548 - Kaos
显示剩余6条评论

81

4
小心使用“memdump”命令,它很容易使您的终端崩溃。 - deweydb
9
小心!使用 memcached-tooldump 子命令会清空缓存 :( --最好先使用 displaystats 命令来更加安全。 - MarkHu
4
在Ubuntu Xenial中,包含memdump的软件包名为libmemcached-tools,而工具本身的二进制文件名为memcdump。 - thenickdude
8
对于那些寻找 memcached-tool 的人来说,它有点隐藏在一个目录中,并且可能不在标准的 PATH 中 - 至少在 Ubuntu Xenial 上是这样的 - 目录在这里: /usr/share/memcached/scripts/ - sxc731
如果你懒得打,可以使用别名 memctool=/usr/share/memcached/scripts/memcached-tool。 - nikhilweee

22

基于@mu 無的回答,我编写了一个缓存转储脚本。

该脚本会转储 memcached 服务器的所有内容。已在 Ubuntu 12.04 和本地主机 memcached 上进行了测试,因此您的情况可能会有所不同。

#!/usr/bin/env bash

echo 'stats items'  \
| nc localhost 11211  \
| grep -oe ':[0-9]*:'  \
| grep -oe '[0-9]*'  \
| sort  \
| uniq  \
| xargs -L1 -I{} bash -c 'echo "stats cachedump {} 1000" | nc localhost 11211'

它的作用是遍历所有缓存块并打印每个块的1000个条目。
请注意这个脚本的一些限制,例如在一个5GB的缓存服务器上可能无法扩展。但它对于在本地机器上进行调试非常有用。

4
在Debian 8上使用memcached 1.4.21-1.1+deb8u1,我不得不显式发送一个退出命令给memcached。我修改了您的命令如下,现在可以正常工作:echo -e "stats items\nquit" | nc localhost 11211 | grep -oe ':[0-9]*:' | grep -oe '[0-9]*' | sort | uniq | xargs -L1 -I{} bash -c 'echo -e "stats cachedump {} 1000\nquit" | nc localhost 11211'。感谢分享这个!对于调试非常有用 :) - Cha0s
由于某种原因,在Mac上的iTerm2中grep -oe '[0-9]*'无法正常工作,不得不替换为grep -Eo '[0-9]{1,99}'。 - max4ever
这很棒,但它缺少一些键,你有什么想法为什么会这样? - user
在我看来,这是当前得票最高选项的自动化版本。我还没有试过,但是我会点赞尝试自动化。 - Trevor Boyd Smith

19

如果您已安装 PHP 和 PHP-memcached,您可以运行以下命令:

$ php -r '$c = new Memcached(); $c->addServer("localhost", 11211); var_dump( $c->getAllKeys() );'

1
在 addServer 后,您需要执行以下操作:$c->setOption(Memcached::OPT_BINARY_PROTOCOL, false); 适用于较新版本的 Memcached。 - Anand Singh
依然是 bool(false) 的答案 :-( - Wolfgang Blessen
2
@WolfgangBlessen - 这是由于memcached中的一个错误 - 在最新版本中已经修复。https://github.com/php-memcached-dev/php-memcached/issues/203 - But those new buttons though..
@billynoah 谢谢,我现在真的看到了结果,memcached 开始变得有用了 :-) - Wolfgang Blessen

16

Bash

要在Bash中获取键列表,请按照以下步骤进行。

首先,定义以下包装函数以使其易于使用(复制并粘贴到shell中):

function memcmd() {
  exec {memcache}<>/dev/tcp/localhost/11211
  printf "%s\n%s\n" "$*" quit >&${memcache}
  cat <&${memcache}
}

Memcached 1.4.31及以上版本

你可以使用命令lru_crawler metadump all来转储缓存中所有项目的(大部分)元数据。

cachedump相比,它不会导致严重的性能问题,并且没有转储密钥数量的限制。

通过使用先前定义的函数的示例命令:

memcmd lru_crawler metadump all

查看:ReleaseNotes1431


Memcached 1.4.30及以下版本

使用items statistics命令获取slab列表,例如:

memcmd stats items

对于每个细纱类别,您可以通过指定细纱id和限制数量(0 - 无限制)来获取项目列表:

memcmd stats cachedump 1 0
memcmd stats cachedump 2 0
memcmd stats cachedump 3 0
memcmd stats cachedump 4 0
...

注意:您需要为每个Memcached服务器执行此操作。

要列出所有存根中的所有键,这是一行命令(每个服务器一个):

for id in $(memcmd stats items | grep -o ":[0-9]\+:" | tr -d : | sort -nu); do
    memcmd stats cachedump $id 0
done

注意:上述命令可能在访问项目时导致严重的性能问题,因此不建议在生产环境中运行。


注:

stats cachedump 仅转储由后台线程管理的 HOT_LRU(如果我没记错?)这意味着在新版本足够新且启用了2Q算法的情况下,您将获得仅一个LRU中内容的快照视图。

如果您想查看所有内容,则 lru_crawler metadump 1(或者 lru_crawler metadump all)是新的大多数官方支持的方法,它将异步转储您想要的所有键。您会以无序方式获取它们,但它会到达所有LRU,并且除非您删除/替换项目,否则多次运行应产生相同的结果。

来源:GH-405


相关链接:


6

最简单的方法是使用python-memcached-stats包,https://github.com/abstatic/python-memcached-stats

keys()方法应该能让你开始。

示例 -

from memcached_stats import MemcachedStats
mem = MemcachedStats()

mem.keys()
['key-1',
 'key-2',
 'key-3',
 ... ]

1
你甚至可以使用命令行执行 python -m memcached_stats <ip> <port> - Martijn
1
目前仅支持Python2。 - Marius
在返回的键的数量或大小方面会有任何限制吗? - loknath

1
我正在使用Java的spyMemcached,并使用了以下代码。它基于 Anshul Goyal的答案
@Autowired
@Qualifier("initMemcachedClient")
private MemcachedClient memcachedClient;

public List<String> getCachedKeys(){
    Set<Integer> slabIds = new HashSet<>();
    Map<SocketAddress, Map<String, String>> stats;
    List<String> keyNames = new ArrayList<>();

    // Gets all the slab IDs
    stats = memcachedClient.getStats("items");
    stats.forEach((socketAddress, value) -> {
        System.out.println("Socket address: "+socketAddress.toString());
        value.forEach((propertyName, propertyValue) -> {
            slabIds.add(Integer.parseInt(propertyName.split(":")[1]));
        });
    });

    // Gets all keys in each slab ID and adds in List keyNames
    slabIds.forEach(slabId -> {
        Map<SocketAddress, Map<String, String>> keyStats = memcachedClient.getStats("cachedump "+slabId+" 0");
        keyStats.forEach((socketAddress, value) -> {
            value.forEach((propertyName, propertyValue) -> {
                keyNames.add(propertyName);
            });
        });
    });

    System.out.println("number of keys: "+keyNames.size());
    return keyNames;
}

0

Java解决方案:

谢谢!@Satvik Nema 您的解决方案帮助我找到了方法,但它不适用于memcached 2.4.6版本。(implementation 'com.googlecode.xmemcached:xmemcached:2.4.6') 不确定什么时候包含了新的方法getStatsByItem。 我使用文档找出所需更改,并且以下代码对我有效。

// Gets all the slab IDs
            Set<Integer> slabIds = new HashSet<>();
            Map<InetSocketAddress, Map<String, String>> itemsMap = null;
            try {
                itemsMap = this.memcachedClient.getStatsByItem("items");
            } catch (Exception e) {
                log.error("Failed while pulling 'items'. ERROR", e);
            }
    
            if (Objects.nonNull(itemsMap)) {
                itemsMap.forEach((key, value) -> {
                    log.info("itemsMap {} : {}", key, value);
                    value.forEach((k, v) -> {
                        slabIds.add(Integer.parseInt(k.split(":")[1]));
                    });
                });
            }
    
            // Gets all keys in each slab ID and adds in List keyNames
            slabIds.forEach(slabId -> {
                Map<InetSocketAddress, Map<String, String>> keyStats = null;
                try {
                    keyStats = this.memcachedClient.getStatsByItem("cachedump " + slabId + " 0");
                } catch (Exception e) {
                    log.error("Failed while pulling 'cachedump' for slabId: {}. ERROR", slabId, e);
                }
                if (Objects.nonNull(keyStats)) {
                    keyStats.forEach((socketAddress, value) -> {
                        value.forEach((propertyName, propertyValue) -> {
                            //keyNames.add(propertyName);
                            log.info("keyName: {} Value: {}", propertyName, propertyValue);
                        });
                    });
                }
            });

0

编辑 - 首先我在这里发布了另一个基于slab列表+stats cachedump的解决方案,但后来我学到了一个艰难的教训,后者并不返回所有的键。

另请参阅memcached问题#405

幸运的是,有更好的解决方案lru_crawler metadump all

唯一有趣的是lru_crawler返回的是URL编码的键。我不喜欢这样,所以我的最短脚本看起来像这样:

#!/bin/bash
host=localhost
port=11211

run_memc() {
    nc -q0 $host $port
}

echo 'lru_crawler metadump all' | run_memc | grep -v ^END \
    | ruby -rcgi -ne 'puts CGI.unescape $_' | sort


我使用了Ruby的unescape,因为它是最简短的(Perl似乎没有内置的unescape/urldecode,Python的导入+循环肯定不是一行代码,而且我总是安装了一些Ruby。你的情况可能有所不同。)

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