Memcached 实战

gu043695 8年前

来自: http://blog.csdn.net/wenniuwuren/article/details/50826656


零. 简介
Memcached 是一款开源、 分布式内存对象缓存系统, 用于加快动态网站响应, 降低数据库负载

Memcached 使用简单, 支持多种语言的 API, 解决面对大量数据的缓存问题


一. 设计哲学
(1) 键值对存储
服务器不关心数据是什么样的。 存储单元由 key、 过期时间、 可选的标记和数据组成。 它不懂数据结构, 传输数据前需要序列化。

(2)一半逻辑在客户端, 另一半逻辑在服务端
客户端知道如何选择(哈希)哪个服务端去读/写存储单元, 并且知道如何处理无法连到服务端的情况
服务端知道如何存储和获取数据单元, 并且它知道如何清除或者重用内存。

(3)服务端彼此之间不通信
即服务端之间没有同步、 没有多播、 没有复制。 增加服务器就是增加可用内存。 但是正因为这个特性, Memcached 存在单点故障, 如果需要做高可用, 需要使用 Magent 这样的代理服务软件去实现高可用。

(4)时间复杂度 O(1)
所有的命令都被尽量实现为快速和对锁友好,提供了近乎确定的查询速度。 在慢的机器上查询时间低于 1ms, 在高端服务器上可以达到百万/s 的吞吐量

(5)遗忘是一种特性
Lazy Expiration + LRU :不检测 item 对象是否超时,get 时检查 item 对象是否应该删除;
</div>
删除item对象时,不释放内存,作删除标记,指针方式 slot 回收插槽,下次分配的时候直接使用;

(6)缓存无效
客户端通过 hash 直接告诉服务端缓存数据无效, 而不是多播让所有服务器的该 item 缓存无效


二. Memcached 实战

(1) 安装 memcached 很简单, 如果是 CentOS 或者 Red Hat 直接 

yum install memcached

如果是 Ubuntu/Debian 则使用 apt-get

(2) 检查 Memcached 是否安装成功:可以查看到帮助信息说明安装成功 
memcached -h

(3) 启动 Memcached (假设 138.138.138.11 是你的外网 ip, 在 CentOS7 上设置 11211 默认端口访问不了, 查看也没被占用, 很奇怪, 所以下面监听 11222 端口) 
memcached -d -u root -l 138.138.138.11 -p 11222 -vv

-d   以守护程序(daemon)方式运行
-u root  指定用户,如果当前为 root ,需要此参数指定用户
-P /tmp/a.pid 保存PID到指定文件
</div>
-m 默认 64,不包含memcached本身占用,单位为 MB
-M   内存不够时禁止 LRU
-n 48  初始 chunk=key+suffix+value+32 结构体,默认 48 字节
-f 1.25  增长因子,默认1.25
-L  启用大内存页,可以降低内存浪费,改进性能
</div>
-l  监听的 IP 地址, 服务器有两个网卡一个对内一个对外, 如果设置为 127.0.0.1 则只能本地访问 memcached, 设置外网 ip 则可以接受外来的访问
-p 11211  TCP端口,默认为11211
-U 11211 UDP端口,默认为11211,0为关闭
</div>
-c 1024 最大并发连接数,默认1024,最好是200
-t 4  线程数,默认4
-R 20  每个event连接最大并发数,默认20
-C  禁用CAS命令(可以禁止版本计数,减少开销)
-vv 打印交互式详细信息, 可以看到连接进来的人正在做什么操作

(4) 检查 Memcached 是否成功启动:
</div>
ps -ef | grep memcached

(5) 远程连接 Memcached: 连接成功显示 Connected to 138.138.138.11. Escape character is '^]'. 
telnet 138.138.138.11 11222

(6) 连接成功后输入  stats 可以查看服务整体状态
STAT pid 5013                                            memcache服务器的进程ID
STAT uptime 3524589                                服务器已经运行的秒数
STAT time 1453720323                              服务器当前的unix时间戳
STAT version 1.4.17                                   memcache版本
STAT libevent 2.0.16-stable                       
STAT pointer_size 64                                 当前操作系统的指针大小(32位系统一般是32bit)
STAT usage_user 20513.015760               进程的累计用户时间
STAT rusage_system 45473.527888         进程的累计系统时间
STAT cur_connections 102                          当前打开着的连接数
STAT total_connections 60437                  从服务器启动以后曾经打开过的连接数
STAT connection_structures 243               服务器分配的连接构造数
STAT reserved_fds 20                                
STAT cmd_get 474507075                         get命令(获取)总请求次数
STAT cmd_set 334776915                         set命令(保存)总请求次数
STAT cmd_flush 97
STAT cmd_touch 0
STAT get_hits 301883351                          总命中次数
STAT get_misses 172623724                     总未命中次数
STAT delete_misses 208322                     
STAT delete_hits 35095518
STAT incr_misses 0
STAT incr_hits 0
STAT decr_misses 0
STAT decr_hits 0
STAT cas_misses 0
STAT cas_hits 0
STAT cas_badval 0
STAT touch_hits 0
STAT touch_misses 0
STAT auth_cmds 0
STAT auth_errors 0
STAT bytes_read 268709016022            总读取字节数(请求字节数) 
STAT bytes_written 754717253318        总发送字节数(结果字节数) 
STAT limit_maxbytes 536870912            分配给memcache的内存大小(字节)
STAT accepting_conns 1
STAT listen_disabled_num 0
STAT threads 4                                        当前线程数
STAT conn_yields 17561
STAT hash_power_level 18
STAT hash_bytes 2097152
STAT hash_is_expanding 0
STAT malloc_fails 0
STAT bytes 473920740                            当前服务器存储items占用的字节数
STAT curr_items 265877                          服务器当前存储的items数量
STAT total_items 239409267                   从服务器启动以后存储的items总数量
STAT expired_unfetched 49973876
STAT evicted_unfetched 23514857
STAT evictions 27383392                        为获取空闲内存而删除的items数(分配给memcache的空间用满后需要删除旧的items来得到空间分配给新的items)
</div>
STAT reclaimed 52732799


三. 客户端的选择
客户端有三种选择: spymemcached、 java-memcached、 xmemcached
具体看  https://xmemcached.googlecode.com/svn/trunk/benchmark/benchmark.html 有性能对比图, 当然因为是 xmemcached 自己的性能测试报告, 不一定和每个人使用的时候场景一样, 具体可以自己测试后再作出选择。
</div>

引入 xmemcached-1.3.6.jar 的包
测试代码如下: 
package com.wenniuwuren.memcached;    import net.rubyeye.xmemcached.MemcachedClient;  import net.rubyeye.xmemcached.XMemcachedClientBuilder;  import net.rubyeye.xmemcached.utils.AddrUtil;    import java.util.HashMap;  import java.util.Map;    /**   * Created by wenniuwuren on 16/3/6.   */  public class MemcachedTest {        public static void main(String[] args) {            try {              //New a XMemcachedClient instance              XMemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses("138.138.138.11:11222"));              MemcachedClient client = builder.build();              Map map = new HashMap<>();              map.put("1", "2");              client.set("key", 3000, map);                Map cachedMap = (Map)client.get("key");              System.out.println(cachedMap.get("1"));            } catch (Exception e) {              e.printStackTrace();          }      }  }


四. Memcached 集群
因为 Memcached 设计哲学的极简, 所以集群不熟非常简单, 服务端新启动一个 Memcached 进程就行。 其他的交给客户端完成。 如果客户端使用普通的 Hash 算法,则新增 Memcached 会重新计算 Hash 值使旧的缓存失效。 如果客户端使用一致性 Hash 算法, 则不会影响旧的缓存数据。

新加个端口为 11333 的 Memcached 进程, 可以看到两个 Memcached 存储内容不同, 证明上述 Memcached 服务间不互相通信。


五. Memcached 局限性
(1)存储格式单一, 就是 <String, Object>, 想使用复杂点的数据结构(list、 set、 hash)一般会选用 Redis
(2)最大只能存储 1M 的 item, 而
(3)最大键长 250 字节 
(4)只存在缓存, 数据重启丢失,而 Redis 支持持久化(但是也经常会丢数据), 并在此基础上实现主从同步, 而 Memcached 存在单点故障 
(5) 数据一致性问题: Memcached 使用 CAS 保证。 而 Redis 使用事务, 保证一系列命令的原子性。