Memcached缓存介绍

淡淡的烟草味﹌ 2022-02-25 14:10 451阅读 0赞

Memcached简介

Memcached是一个高性能的服务器内存缓存软件。在早期版本的Memcached使用的是alloc来分配内存,存在内存碎片,在新版本的Memcached采用了Slab Allocator来分配内存。在MC启动时会要求制定一块内存区域,然后会划分为多个Slab,每个Slab默认大小为1M,可以指定。每个Slab又包含多个truck,每个Slab的truck大小不同,但同一个Slab的truck大小是一样的。在存入数据到MC时,MC会查找最合适的truck来存储数据。比如数据是100字节,现在有truck大小分别为64byte,128byte,144byte,那么会找到128byte的truck存储。不过仍然存在空间的浪费,比如这个例子中就浪费了28byte。所以保证合适大小的空间很重要,我们可以在MC启动时指定负载因子-f参数来指定,默认是1.25.通常情况下这都是一个比较合理的值,无需修改。另外避免空间浪费的一个处理方法是,将数据大小差不多的放入到相同的MC中。比如一个MC的truck大小为1M,另外一个为1K。那么将数据量在1M左右的都放入到1M的那个MC。

与Redis比较

与Redis相比:
1.MC只支持key/value,Redis支持key/value,list,set,map等6种数据结构;

2.都支持key的过期
MC不主动检查item是否过期,只有在get时检查,但是检查到过期也不会删除,只是做一个标记。在有数据要set时该空间可以被重试使用。MC在分配空间时优先使用已经过期的key/value对的空间,如果分配的空间占满时,会使用LRU算法,删除最近最少使用的key。可以使用-M参数来启动MC,这样但MC内存耗尽时,会返回一个报错信息(对于完整数据缓存有用)。

Redis是主动监测,在key过期时会主动删除。

3.MC没有持久化功能,无法恢复数据;Redis可以定时保存数据到磁盘,Redis重启可以重新加载到内存。

应用场景

1.将变化频率低的数据事先就放入MC中;
比如商品分类、系统角色等等。

后续如有修改,修改数据库并同步到MC。
这样所有用户的请求全部请求的MC,不会请求数据库。

2.热点数据缓存

3.集群会话共享

分布式缓存设计思想

1.每台MC的内容不一样,所有的服务器内容加起来接近数据库的容量;
2.通过在客户端程序或在负载均衡器上使用Hash算法,让同一内容始终分配到同一台MC。
3.普通的HASH算法会导致MC节点宕机后数据发生流动,可能发生雪崩;
4.采用一致性HASH算法可以使节点宕机对数据的流动降到最低。
5.每个MC节点之间互不通信,数据独立存取。

安装Memcache

安装libevent

由于Memcached使用了libevent库,所以要先安装libevent。
从https://github.com/libevent/libevent/releases获取最新稳定版本下载。这里下载的是libevent-2.1.8-stable.tar.gz。

  1. tar zxvf libevent-2.1.8-stable.tar.gz
  2. cd libevent-2.1.8-stable
  3. ./configure
  4. make
  5. make install

问题:
执行./configure时出错。错误信息:libevent error: no acceptable C compiler found in $PATH
解决办法:安装gcc,执行yum install gcc,然后再执行./configure

安装Memcached

从http://memcached.org/downloads下载最新稳定版本,这里下载的是memcached-1.5.10.tar.gz。

  1. tar -zxvf memcached-1.5.10.tar.gz
  2. cd memcached-1.5.10
  3. ./configure
  4. make
  5. make install

验证是否安装成功
memcached -h
提示:
memcached: error while loading shared libraries: libevent-2.1.so.6: cannot open shared object file: No such file or directory
解决:

  1. find / -name "libevent-2.1.so.6"

可以找到

  1. /usr/local/lib/libevent-2.1.so.6
  2. /data/tools/libevent-2.1.8-stable/.libs/libevent-2.1.so.6

/usr/local/lib加到/etc/ld.so.conf中
27301574.jpg

然后执行ldconfig,然后再次执行memcached -h就正常了。

启动Memcached

  1. memcached -m 64 -p 11211 -d -c 8192 -u root

相关参数可以使用memcached -h查看。本例中-m 64指定内存大小为64M,-p 11211指定端口,-d指定为守护进程,-c指定连接数,-u指定用户(在用root启动时需要指定)。
77633311.jpg

增加实例,只需修改启动的端口即可。下面新增一个实例

  1. memcached -m 64 -p 11212 -d -c 8192 -u root

命令行客户端操作MC数据

MC命令

  • 添加数据(add)

    1. add key flag expiretime bytes
    2. value

    key : 给这个值设置一个名字
    flag : 标志,是一个整数
    expiretime : 有效期,以秒为单位,0表示没有延迟
    bytes : 这是一个需要存储在memcached的数据的长度
    value : 是一个需要存储的数据。数据需要将通过在新的一行后输入
    注意:bytes要和value的长度一致,否则会出现CLIENT_ERROR bad data chunk错误

  • 为一个新的或现有的键(key)设置一个值(set)

    1. set key flag expiretime bytes
    2. value
  • 替换已存在的 key(键) 的 value(数据值)(replace)

    1. replace key flag expiretime bytes
    2. value
  • 向已存在 key(键) 的 value(数据值) 后面追加数据(append)

    1. append key flag expiretime bytes
    2. value
  • 向已存在 key(键) 的 value(数据值) 前面追加数据(prepend)

    1. prepend key flag expiretime bytes
    2. value
  • 获取存储在 key(键) 中的 value(数据值)(get)

    1. get key
  • 删除已存在的 key(键)(delete)

    1. delete key
  • incr 与 decr 命令用于对已存在的 key(键) 的数字值进行自增或自减操作

    1. incr key increment_value
    2. decr key increment_value
  • 清理缓存中的所有数据(flush_all)

    1. flush_all [time]
    2. - time : (可选) 在指定时间后执行清理缓存操作
  • stats / stats slabs / stats sizes / stats items

    1. stats 显示统计信息例如 PID(进程号)、版本号、连接数等
    2. stats slabs 显示各个slab的信息,包括chunk的大小、数目、使用情况等
    3. stats sizes 显示所有item的大小和个数
    4. stats items 显示各个 slab item 的数目和存储时长
    5. 命令格式:
    6. gets key
    7. 命令格式:
    8. cas key flags exptime bytes unique_cas_token [noreply]
    9. value
  • gets / cas

    1. gets 获取带有 CAS 令牌的 value(数据值)
    2. cas 执行一个”检查并设置”的操作

参考MemCache 入门极简教程

通过Telnet来测试

  1. // 添加数据
  2. add key001 0 10 5 // 回车
  3. hello
  4. // 获取数据
  5. get key001
  6. // 删除数据
  7. delete key001
  8. // 向value前追加数据
  9. prepend key001 0 0 3
  10. 123
  11. // 向value后追加数据
  12. append key001 0 0 3
  13. 123
  14. // 将key001的value替换为world
  15. replace key001 0 0 5
  16. world

通过nc测试

  1. 写入:
  2. printf "set key001 0 0 5\r\nhello\r\n" | nc 127.0.0.1 11211
  3. 读取:
  4. printf "get key001\r\n" | nc 127.0.0.1 11211
  5. 删除:
  6. printf "delete key001\r\n" | nc 127.0.0.1 11211
  7. # cas操作需要先根据gets key来获取CAS令牌
  8. # 1.获取令牌
  9. printf "gets key001\r\n" | nc 127.0.0.1 11211
  10. # 2.cas更新key的value
  11. printf "cas key001 0 0 5 14 \r\nworld\r\n" | nc 127.0.0.1 11211

Memcached客户端Xmemcached使用

1.引入xmemcached的依赖

  1. <dependency>
  2. <groupId>com.googlecode.xmemcached</groupId>
  3. <artifactId>xmemcached</artifactId>
  4. <version>2.4.5</version>
  5. </dependency>

注意:xmemcached依赖slf4j,默认会打印一堆的Debug日志,可以引入slf4j和相关的日志实现的依赖,然后配置xmemcached的日志级别为info。
比如log4j,可以配置log4j.logger.com.google=info

2.基本使用

  1. XMemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses("192.168.200.109:11211 192.168.200.109:11212"));
  2. builder.setSessionLocator(new KetamaMemcachedSessionLocator()); // 一致性哈希,使得某个key存的时候存都某个节点,取的时候也会从该节点获取
  3. MemcachedClient mc = builder.build();
  4. // 清空数据
  5. mc.flushAll();
  6. mc.add("hello",30,"你好,Memcached!");
  7. String value = mc.get("hello");
  8. System.out.println("hello=" + value);
  9. mc.delete("hello");
  10. value = mc.get("hello");
  11. System.out.println("hello==" + value);
  12. // 如果不存在key则创建,存在则覆盖value
  13. mc.set("key001",0,"test key");
  14. // 更新过期时间
  15. mc.touch("key001",3);
  16. Thread.sleep(3000L);
  17. value = mc.get("key001");
  18. System.out.println("key001=====" + value);
  19. // cas操作,内部先通过gets命令拿到token,然后再执行cas操作。
  20. mc.set("abc",0,0);
  21. mc.cas("abc", 0, new CASOperation<Integer>() {
  22. @Override
  23. public int getMaxTries() { // cas重试次数
  24. return 3;
  25. }
  26. @Override
  27. public Integer getNewValue(long currentCAS, Integer currentValue) {
  28. return 99; // 要设置的新值
  29. }
  30. });
  31. int casValue = mc.get("abc");
  32. System.out.println("abc=" + casValue);
  33. mc.add("hello",0,"world");
  34. if (mc.add("hello",10,"abcd")) {
  35. System.out.println("key is exists");
  36. }
  37. // 数字原则更新,类似java中的AtomicInteger
  38. System.out.println(mc.incr("aaa",5,0)); // 对aaa加5,默认值为0(aaa不存在时)
  39. System.out.println(mc.decr("aaa",2)); // 对aaa减2
  40. // 或者使用Counter
  41. Counter counter = mc.getCounter("counter",0);
  42. System.out.println(counter.addAndGet(5));
  43. System.out.println(counter.decrementAndGet());
  44. // 命名空间
  45. String ns = "namespace";
  46. mc.withNamespace(ns, new MemcachedClientCallable<Boolean>() {
  47. @Override
  48. public Boolean call(MemcachedClient memcachedClient) throws MemcachedException, InterruptedException, TimeoutException {
  49. boolean result = memcachedClient.set("key1",0,"hello");
  50. return result;
  51. }
  52. });
  53. // 或者使用
  54. mc.beginWithNamespace(ns);
  55. mc.add("key2",20,"world");
  56. mc.add("key3",30,"你好");
  57. System.out.println("key3==>" + mc.get("key3"));
  58. mc.endWithNamespace();
  59. value = mc.withNamespace(ns, new MemcachedClientCallable<String>() {
  60. @Override
  61. public String call(MemcachedClient client) throws MemcachedException, InterruptedException, TimeoutException {
  62. return client.get("key2");
  63. }
  64. });
  65. System.out.println("with namespace key2=" + value);
  66. value = mc.get("key1");
  67. System.out.println("key1=" + value);
  68. value = mc.get("key2");
  69. System.out.println("key2=" + value);
  70. value = mc.get("key3");
  71. System.out.println("key3=" + value);
  72. // 让命名空间的所有key都失效
  73. mc.invalidateNamespace(ns);
  74. value = mc.get("key1");
  75. System.out.println("key1=" + value);
  76. value = mc.get("key2");
  77. System.out.println("key2=" + value);
  78. value = mc.get("key3");
  79. System.out.println("key3=" + value);
  80. mc.shutdown();

这里只是基本使用,可以查看下面的参考链接查看全部用法。

参考:Xmemcached 中文用户指南、Memcached的几种Java客户端(待实践)

参考:Memcached 教程

Memcached监控

这里推荐使用MemAdmin,需要PHP环境。参考:windows下memadmin安装

发表评论

表情:
评论列表 (有 0 条评论,451人围观)

还没有评论,来说两句吧...

相关阅读

    相关 memcached+net缓存

    最近对线上项目进行了一次缓存方面的优化,本来6月就该写的,但是项目一直忙,就给自己理由偷懒了 缓存方面的思考参考代震军的文章比较多,文章地址: http://www.cnb

    相关 分布式缓存memcache

    MemCache是一个自由、源码开放、高性能、分布式的分布式内存对象缓存系统,用于动态Web应用以减轻数据库的负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高