Memcached 培训

dreamlan 贡献于2015-07-09

作者 lantian  创建于2014-05-03 12:08:00   修改者dm  修改于2014-08-29 04:55:00字数11312

文档摘要:什么是Memcached Memcached是一个免费开源的、高性能的、具有分布式内存对象的缓存系统,它通过减轻数据库负载加速动态Web应用。最初版本由LiveJournal的BradFitzpatrick在2003年开发完成。目前全世界很多用户都在使用它来构建自己的大负载网站或提高自己的高访问网站的响应速度。Memcache是这个项目的名称,而Memcached是服务器端的主程序文件名。工作原理:①客户端第一次访问应用程序时,会到数据库(RDBMS)中取出数据,返回给客户端;同时也将取出的数据保存到memcached中。②第二次访问时,因为数据已经缓存,不用去数据库查询了,直接从memcached取。
关键词:

什么是Memcached Memcached是一个免费开源的、高性能的、具有分布式内存对象的缓存系统,它通过减轻数据库负载加速动态Web应用。最初版本由LiveJournal的Brad Fitzpatrick在2003年开发完成。目前全世界很多用户都在使用它来构建自己的大负载网站或提高自己的高访问网站的响应速度。Memcache是这个项目的名称,而Memcached是服务器端的主程序文件名。 工作原理: ①客户端第一次访问应用程序时,会到数据库(RDBMS)中取出数据,返回给客户端;同时也将取出的数据保存到memcached中。 ② 第二次访问时,因为数据已经缓存,不用去数据库查询了,直接从memcached取。 Memcached的特征 Memcached作为高性能的缓存服务器,具有如下特征: 1.协议简单 Memcached的协议实现比较简单,使用的是基于文本行的协议,能直接通过telnet在Memcached服务器上存取数据。 2.基于libevent的事件处理 了解libevent的用户都知道,libevent是一套利用C开发的程序库,它将BSD系统的kqueue、Linux系统的epoll等事件处理功能封装成一个接口,确保即使服务器端的连接数增加也能发挥很好的性能。Memcached利用这个库进行异步事件处理。 3.内置的内存管理方式 Memcached有一套自己管理内存的方式,这套管理方式非常高效,所有的数据都保存在Memcached内置的内存中,当存入的数据占满空间时,使用LRU算法自动删除不使用的缓存,即重用过期数据的内存空间。Memcached是为缓存系统设计的,没有考虑数据的容灾问题,和机器的内存一样,重启机器数据将会丢失。 4.互不通信的Memcached之间具有分布特征 各个Memcached服务器之间互相不通信,都是独立的存取数据,不共享任何信息。通过对客户端的设计,让Memcached具有分布式,能支持海量缓存和大规模应用。 Memcached的安装 Windows下安装 下载地址:http://code.jellycan.com/files/memcached-1.2.6-win32-bin.zip 一般情况下,我们用linux作为生产环境,但是开发还是在windows下面,所以这里先介绍下 win版本作为学习用。这是一个由Kenneth Dalgleish基于Kronuz的1.2.1构建。官方的memcached的团队不对这个版本支持! 1、下载memcache for windows,解压到d:\memcached。 2、在命令行状态下输入: d:\memcached\memcached.exe -d install 。至此memcached已经安装成windows服务(win7需要管理员身份运行) 3、在命令行下输入: d:\memcached\memcached.exe -d start 以启动memcached服务。当然也可以选择在windows服务中启动 Linux下安装(基于Centos6.5) libevent下载地址:http://libevent.org/ memcached下载地址:http://memcached.org/ 首先,memcached是基于libevent的,所以确保你的系统已经装了libevent,libevent是个程序库,它将Linux的epoll、BSD类操作系统的kqueue等事件处理功能封装成统一的接口。即使对服务器的连接数增加,也能发挥O(1)的性能。 memcached使用这个libevent库,因此能在Linux、BSD、Solaris等操作系统上发挥其高性能。 安装libevent # tar xzvf libevent-2.0.21-stable.tar.gz ##解压 # cd libevent-2.0.21-stable # ./configure --prefix=/usr # make # make install 安装完后可以查看下/usr/lib是否有libevent等文件(ls -al /usr/lib | grep libevent) 然后安装memcached # tar xzvf memcached-1.4.20.tar.gz # cd memcached-1.4.20 # ./configure --with-libevent=/usr # make # make install 安装结果(ls -al /usr/local/bin/memcached)如图: 然后执行命令启动memcached #/usr/local/bin/memcached -d -m 1024 -u root -p 11211 -P /tmp/memcached.pid 启动过程中所用选项说明如下: -p,使用的TCP端口。默认为11211。 -m,最大内存大小。默认为64MB。 -vv,以very verbose模式启动,将调试信息和错误输出到控制台。 -d,作为守护进程在后台运行。 -c,最大运行的并发连接数,默认是1024,按照服务器的负载量来设定。 -P,设置保存Memcache的pid文件。 -l,绑定地址(默认:所有都允许,无论内外网或者本机更换IP,有安全隐患,若设置为127.0.0.1就只能本机访问)。 -u,运行Memcached的用户,默认不能由root用户启动,所以当前用户为root用户时,需要利用-u参数来指定。 -f,块大小增长因子,默认是1.25,根据存入的数据的大小可进行调整。 telnet连接 连接:telnet ip 端口 例如:telnet 127.0.0.1 11211 基本命令: 可以使用五种基本 memcached 命令执行最简单的操作。这些命令和操作包括: · set · add · replace · get · delete 语法: command 参数 用法 key key 用于查找缓存值 flags 可以包括键值对的整型参数,客户机使用它存储关于键值对的额外信息 expiration time 在缓存中保存键值对的时间长度(以秒为单位,0 表示永远) bytes 在缓存中存储的字节点 value 存储的值(始终位于第二行) 数据存取 set key1 0 180 3 abc STORED add key1 0 180 3 xyz NOT_STORED get key1 VALUE key1 0 3 abc END replace key1 0 180 3 xyz STORED get key1 VALUE key1 0 3 xyz END delete key1 DELETED 数字加减 set key2 0 180 4 1234 STORED incr key2 3 1237 get key2 VALUE key2 0 4 1237 END decr key2 1 1236 get key2 VALUE key2 0 4 1236 END 查看缓存服务器状态 命令:stats STAT pid 2711 //进程id STAT uptime 2453 //总的运行时间,单位描述 STAT time 1344856333 //当前时间 STAT version 1.4.18 //版本 STAT pointer_size 32 //服务器指针位数,一般32位操作系统是32 STAT rusage_user 0.002999 //进程的累计用户时间 STAT rusage_system 1.277805 //进程的累计系统事件 STAT curr_connections 10 //当前连接数 STAT total_connections 11 //服务器启动后,总连接数 STAT connection_structures 11 //连接结构的数量 STAT cmd_get 17 //总获取次数 STAT cmd_set 1 //总写入次数 STAT cmd_flush 1 //总的的清空次数 STAT get_hits 1 //总的命中次数 STAT get_misses 7 //获取没有命中次数 STAT delete_misses //删除没有命中次数 STAT delete_hits 4 //删除命中次数 STAT incr_misses //递增操作没有命中次数 STAT incr_hits //递增操作命中次数 STAT decr_misses //递减操作没有命中的次数 STAT decr_hits //递减操作命中的次数 STAT cas_misses //cas设置没有命中次数 STAT cas_hits //cas命中次数 STAT cas_badval //cas操作找到key,但版本过期,没有设置成功 STAT bytes_read 455 //总共获取数据量 STAT bytes_written 1175 //总共写入数据量 STAT limit_maxbytes 1048576 //最大允许使用内存,单位字节 STAT accepting_conns 1 STAT listen_disabled_num 0 STAT threads 5 //当前线程数 STAT conn_yields 0 STAT bytes 56 //已用缓存空间 STAT curr_items 1 //当前缓存的keyvalue数 STAT total_items 7 //总共缓存的keyvalue数,包括过期删除的 STAT evictions //通过删除keyvalue,释放内存次数 END 理解memcached的内存存储 数据存储方式:Slab Allocation Slab Allocator的基本原理是按照预先规定的大小,将分配的内存分割成特定长度的块,以解决内存碎片问题。 Slab Allocation的原理相当简单。 将分配的内存分割成各种尺寸的块(chunk),并把尺寸相同的块分成组(chunk的集合) Slab Allocation的主要术语 Page 分配给Slab的内存空间,默认是1MB。分配给Slab之后根据slab的大小切分成chunk。 Chunk 用于缓存记录的内存空间。 Slab Class 特定大小的chunk的组。 memcached根据收到的数据的大小,选择最适合数据大小的slab。  memcached中保存着slab内空闲chunk的列表,根据该列表选择chunk,  然后将数据缓存于其中。 Slab Allocation的缺点 Slab Allocator解决了当初的内存碎片问题,但新的机制也给memcached带来了新的问题。 这个问题就是,由于分配的是特定长度的内存,因此无法有效利用分配的内存。 例如,将100字节的数据缓存到128字节的chunk中,剩余的28字节就浪费了。 数据过期方式 • Lazy Expiration memcached内部不会监视记录是否过期,而是在get时查看记录的时间戳,检查记录是否过 期。这种技术被称为lazy(惰性)expiration。因此,memcached不会在过期监视上耗费CPU时间。 • LRU memcached会优先使用已超时的记录的空间,但即使如此,也会发生追加新记录时空间不 足的情况,此时就要使用名为 Least Recently Used(LRU)机制来分配空间。顾名思义,这是删除“最近最少使用”的记录的机制。因此,当memcached的内存空间不足时(无法从slab class 获取到新的空间时),就从最近未被使用的记录中搜索,并将其空间分配给新的记录。从缓存的实用角度来看,该模型十分理想。 基于客户端的Memcached分布式 假设memcached服务器有node1~node3三台,分布式结构如下图。 客户端做路由的原理非常简单,应用服务器在每次存取某key的value时,通过某种算法把key映射到某台memcached服务器nodeA上,因此这个key所有操作都在nodeA上,结构图如下所示: 存储某个key-value 接下来获取保存的数据。 获取时也要将要获取的键“tokyo”传递给函数库。函数库通过与数据保存时相同的算法,根据“键”选择服务器。使用的算法相同,就能选中与保存时相同的服务器,然后发送get命令。只要数据没有因为某些原因被删除,就能获得保存的值。 这样,将不同的键保存到不同的服务器上,就实现了memcached的分布式。 memcached服务器增多后,键就会分散,即使一台memcached服务器发生故障无法连接,也不会影响其他的缓存,系统依然能继续运行。 因此关键在于算法的选择,最基本的要求就是能让数据平均到所有服务器上。这自然而然让我想到了hash算法,spymemcached是一个用得比较广的java客户端,它就提供了一种简单的hash算法,实现类为ArrayModNodeLocator,从key映射到node的源码如下: public MemcachedNode getPrimary(String k) { return nodes[getServerForKey(k)]; } private int getServerForKey(String key) { int rv=(int)(hashAlg.hash(key) % nodes.length); assert rv >= 0 : "Returned negative key for key " + key; assert rv < nodes.length : "Invalid server number " + rv + " for key " + key; return rv; } 从上面可知它是把所有node放在数组里,通过hash算法把key映射到某index,然后通过这个index在数组里取node。 再则需要考虑如何容错,比如当某个node当掉了,如何自动地转到其他node上,上面的简单hash路由策略采用的方法是在数据组里顺序向下轮询node,找第一个工作正常的node即可。 最后要考虑当需要移除node或添加node的时候,如何有效地调整映射关系,这自然又让我们想到一致性hash算法,关于一致性hash算法稍后说明,这里先看看spymemcached是如何利用这个算法来做路由的,实现类为KetamaNodeLocator,从key映射到node的源码如下: public MemcachedNode getPrimary(final String k) { MemcachedNode rv=getNodeForKey(hashAlg.hash(k)); assert rv != null : "Found no node for key " + k; return rv; } MemcachedNode getNodeForKey(long hash) { final MemcachedNode rv; if(!ketamaNodes.containsKey(hash)) { // Java 1.6 adds a ceilingKey method, but I'm still stuck in 1.5 // in a lot of places, so I'm doing this myself. SortedMap tailMap=ketamaNodes.tailMap(hash); if(tailMap.isEmpty()) { hash=ketamaNodes.firstKey(); } else { hash=tailMap.firstKey(); } } rv=ketamaNodes.get(hash); return rv; } 这段代码非常清晰,就是通过ketamaNodes这个数据结构按照一致性hash算法把node分区,每次都把映射到一个分区的key对应到负责这个分区的node上。 常用算法介绍 目前有两种分布式算法使用得最多,一种是根据余数来计算分布,另一种是根据一致性散列算法来计算分布。 余数分布式算法: 根据余数分布式算法先求得键的整数散列值,再除以服务器台数,根据余数来选择将键存放到哪一台服务器上。这种方法虽然计算简单,效率很高,但在服务器增加或减少时,会导致几乎所有的缓存失效,所以在大规模部署中,很少使用这种方法。 一致性散列算法: 一致性散列的原理如下图所示,先算出Memcached服务器(节点)的散列值,并将其分散到0到2的32次方的圆上,然后用同样的方法算出存储数据的键的散列值并映射到圆上,最后从数据映射到的位置开始顺时针查找,将数据保存到查找到的第一个服务器上。如果超过2的32次仍然找不到服务器,就会将数据保存到第一台Memcached服务器上。 从上图的状态中添加一台memcached服务器。余数分布式算法由于保存键的服务器会发生巨大变化而影响缓存的命中率,但Consistent Hashing中,只有在圆上增加服务器的地点逆时针方向的第一台服务器上的键会受到影响。 Memcached Java客户端介绍 Spymemcached · An improved Java API maintained by Matt Ingenthron and others at Couchbase. · Aggressively optimised, ability to run async, supports binary protocol, support Membase and Couchbase features, etc. See site for details. 简单例子 MemcachedClient c=new MemcachedClient(     new InetSocketAddress("hostname", portNum)); // Store a value (async) for one hour c.set("someKey", 3600, someObject); // Retrieve a value (synchronously). Object myObject=c.get("someKey"); 异步数据获取 Memcache客户端可能要处理大量的异步消息,或者需要处理的memcached不能连通。如果mem server不可用,Memcacahe链接会继续尝试连接已挂起的服务,直到连接成功。为了避免应用被挂起,可以使用异步机制处理超时请求或取消请求。 // Get a memcached client connected to several servers MemcachedClient c=new MemcachedClient(         AddrUtil.getAddresses("server1:11211 server2:11211")); // Try to get a value, for up to 5 seconds, and cancel if it doesn't return Object myObj=null; Future f=c.asyncGet("someKey"); try {     myObj=f.get(5, TimeUnit.SECONDS); } catch(TimeoutException e) {     // Since we don't need this, go ahead and cancel the operation.  This     // is not strictly necessary, but it'll save some work on the server.     f.cancel(false);     // Do other timeout related stuff } 与spring集成                                                               属性说明: Servers 一个字符串,包括由空格或逗号分隔的主机或IP地址与端口号 Daemon 设置IO线程的守护进程(默认为true)状态 FailureMode 设置故障模式(取消,重新分配,重试),默认是重新分配 HashAlg 设置哈希算法(见net.spy.memcached.HashAlgorithm的值) InitialObservers 设置初始连接的观察者(观察初始连接) LocatorType 设置定位器类型(ARRAY_MOD,CONSISTENT),默认是ARRAY_MOD MaxReconnectDelay 设置最大的连接延迟 OpFact 设置操作工厂 OpQueueFactory 设置操作队列工厂 OpTimeout 以毫秒为单位设置默认的操作超时时间 Protocol 指定要使用的协议(BINARY,TEXT),默认是TEXT ReadBufferSize 设置读取的缓冲区大小 ReadOpQueueFactory 设置读队列工厂 ShouldOptimize 如果默认操作优化是不可取的,设置为false(默认为true) Transcoder 设置默认的转码器(默认以net.spy.memcached.transcoders.SerializingTranscoder) UseNagleAlgorithm 如果你想使用Nagle算法,设置为true WriteOpQueueFactory 设置写队列工厂 AuthDescriptor 设置authDescriptor,在新的连接上使用身份验证 封装的工具类: import java.util.concurrent.TimeUnit; import javax.annotation.PreDestroy; import net.spy.memcached.MemcachedClient; import net.spy.memcached.internal.OperationFuture; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Repository; @Repository public class CacheUtil { @Autowired MemcachedClient memcachedClient; public MemcachedClient getMemcachedClient() { return memcachedClient; } /** * Get with a single key * @param key * @return */ public Object get(String key) { return memcachedClient.get(key); } /** * Set an object in the cache * and Get the results of the given operation * @param key * @param obj * @param timeout * @return */ public boolean set(String key, Object obj, int timeout) { OperationFuture of = memcachedClient.set(key, timeout, obj); try { return of.get(5, TimeUnit.SECONDS); } catch (Exception e) { throw new RuntimeException(e); } } /** * Set an object in the cache * @param key * @param obj * @param timeout */ public void setAsync(String key, Object obj, int timeout) { try { memcachedClient.set(key, timeout, obj); } catch (Exception e) { throw new RuntimeException(e); } } /** * Delete the given key from the cache * and Get the results of the given operation * @param key * @return */ public boolean remove(String key) { OperationFuture of = memcachedClient.delete(key); try { return of.get(5, TimeUnit.SECONDS); } catch (Exception e) { throw new RuntimeException(e); } } /** * Delete the given key from the cache * @param key */ public void removeAsync(String key) { try { memcachedClient.delete(key); } catch (Exception e) { throw new RuntimeException(e); } } /** * Get the values for multiple keys from the cache * @param keys * @return */ public Map getMulti(String... keys) { Map map = new HashMap(); map = memcachedClient.getBulk(keys); return map; } @PreDestroy public void shutdown() { memcachedClient.shutdown(10, TimeUnit.SECONDS); } } XMemcached  简单例子 MemcachedClient client=new XMemcachedClient("host",11211); //同步存储value到memcached,缓存超时为1小时,3600秒。 client.set("key",3600,someObject); //从memcached获取key对应的value Object someObject=client.get("key"); //从memcached获取key对应的value,操作超时2秒 someObject=client.get("key",2000); //更新缓存的超时时间为10秒。 boolean success=client.touch("key",10); //删除value client.delete("key"); 设置权重 MemcachedClientBuilder builder = new    XMemcachedClientBuilder(AddrUtil.getAddresses("localhost:12000 localhost:12001"),new int[]{1,3});    MemcachedClient memcachedClient=builder.build();

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 8 金币 [ 分享文档获得金币 ] 1 人已下载

下载文档