目前,用到memcache的公司和网站也越来越多。memcache的客户端操作一般都只提供了get,set等简单的操作,这些操作都是非常高效的。 虽然memcache是个key-value存储的系统,但是在某些时候,我们可能需要遍历memcache的数据。
memcache的stats命令包括:
stats
stats reset
stats malloc
stats maps
stats sizes
stats slabs
stats items
stats cachedump slab_id limit_num
stats detail [on|off|dump]
通过命令完成遍历
通过这些stats命令我们就可以完成memcache存储的内容的遍历,ok,下面我们通过telnet直接连接到memcache通过这些命令来完成相关的操作。
telnet到192.168.15.225(局域网测试机器)的memcache服务器
执行stats items命令,可以看到出现 很多的items行。
贴上一段php实现的遍历memcache数据的代码,其他语言可以参考代码自己实现。
<?php
$host='localhost';
$port=11211;
$mem=new memcache();
$mem->connect($host,$port);
$items=$mem->getextendedstats ('items');
$items=$items["$host:$port"]['items'];
foreach($items as $key=>$values){
$number=$key;
$str=$mem->getextendedstats ("cachedump",$number,0);
$line=$str["$host:$port"];
if( is_array($line) && count($line)>0){
foreach($line as $key=>$value){
echo "<pre>".$key.'=>';
print_r($mem->get($key));
echo "</pre><br/>";
}
}
}
?>
memcached如何实现高性能批量删除,插入
memcached 的批量删除,向来是 memcached 使用者很头疼的事情,因为 memcached 采取的缓存方案是哈希表结构,所以没有办法实现 delete from tablename where key like ‘%xx%’ 类似这样的批量删除功能。所以不得不自己采取一些策略实现批量删除。常见的删除方案主要有以下两种:
第一种方案:通过记录 key 到 db 然后循环删除。
其实这也是最常规的删除方法,最容易想到,可能大部分人首先都会这么考虑。具体方法如下:
1. 添加业务数据时,在向 memcached 缓存 set 数据的时候,将其 key 记录到数据库(或内存中,或文件中,由于数据量大,内存中基本不可行),也就是每 set 一条数据到 memcached 缓存中,就向记录 key 的数据表(这类专门用于辅助删除缓存的表可以按业务分类建表,为了方便,我们下文简称 keytable, 因为不可能所有的 key 都用一张表,即使按业务分类建,数据量也是很庞大的) insert 一条记录。数据表结构可以设计为这两个字段: key( 对应缓存 key), id( 对应业务实体 id) ,这里的存储 id 主要是方便批量查询出需要从缓存删除的 key 时方便 , 也可以根据实际业务设计。
2. 删除业务数据时,首先从数据库的业务数据表删除数据,然后从 keytable 中查询出 keylist. 查询语句类似, select key from keytable where 条件 ,再然后循环 keylist 从 memcached 缓存中 remove 掉相应的记录,最后删除 keytable表中相应的记录,删除语句类似 delete key from keytable where 条件.
这种方法的优点:方案设计思路简单,符合常规思维,而且能达到精确删除的目的。
这种方法的缺点:删除代价比较高,需要数据库或其他存储介质辅助,而且实际应用中,缓存量是很大的,会导致大量频繁的对 keytable 表的 insert 操作,性能问题将会很严重,需要根据具体情况运用。
这种方案主要是利用 memcached 缓存根据 lru 算法进行定期自动清理不用或少用的缓存,通过对 key 增加版本管理来实现。
该方案的具体方法如下(拿商品数据举例说明):
1. 对缓存中的每个 key 进行版本管理,比如缓存商品数据的 key 为 product_10001.0, 这里的 product 表示商品这类业务数据, product_10001 表示具体的商品对象 10001 , 0 表示版本号。
2. 在 memcached 中维护一版本记录数据,这个很简单,比如整个系统只有商品,订单,用户这三类缓存数据,则在memcached 中只维护三个 key ,类似 product_version,book_version,user_version. 他们的取值范围为 0-99 之间循环,之所有循环是防止数据版本多了无限增大,管理麻烦,而且数字大了占用空间大(要对应到每个 key 的值)。
3. 删除商品数据时,首先从数据库删除对应商品数据的记录。然后更新对应商品的版本: product_version = product_version+1 (记得当 product_version=99 时, product_version=0 )。
4. 从 memcached 中 get 数据时,需要 get 两次,首次按 get 对应业务数据的版本号,如 product_version ,然后根据数据本身的 key+ 最新的 product_version 作为真正的 key 去取数据。这样删除了的数据自动为过期数据, memcached 会根据 lru 算法清理。
5. 向 memcached 中 set 数据时,也是先取最新的 product_version ,然后将数据本身的 key+product_version 作为 key保存数据到缓存。
这种方案的优点:减少了批量删除从 memcached 真正删除数据的麻烦。利用 memcached 自身的特点解决删除问题,符合 memcached 的设计思想。
这种方案的缺点: a. 每次 set 数据都要,先 get 版本,然后 set, 性能上差不多降低了 1 倍,虽然性能方面还是不错。不过这个问题好像没有办法解决,原先考虑在客户端缓存版本,因为版本毕竟不是时时都变,但是考虑到版本数据时多进程间共享数据,所以不能这样做,每次必须从 memcached 中取版本。否则难以保证是最新的。 b. 这种方案对内存上有点浪费,虽然 memcached 会根据 lru 算法清理低版本的垃圾数据,但是毕竟不是实时清理,所以必然浪费内存,所以内存不足的情况下,要仔细考虑采取此方案。