作为一个工作将近三年的Java程序猿,因为一直做一些应用系统,且大多都是数据管理类的单系统应用,很少接触一些比较好的技术,比如缓存、负载均衡以及WebService等。经过和朋友聊天,确定了一些要攻克的技术,作为这一阶段的学习内容。
之前没有接触过memcached时,总觉得缓存应该是一项非常复杂的技术,其入门难道也一定很高。偶尔看一下,也总有一种丈二和尚摸不着头脑的感觉。不过,认真学习起来,发现它还是很容易就能学会并且掌握的。
这里摘抄一些来自于百度百科的介绍:
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信。
Memcached分为服务器端和客户端,在使用Memcached之前,需要安装Memcached服务。下面介绍如何在win7中安装Memcached。
下载Memcached:http://www.urielkatz.com/projects/memcached-win64/memcached-win64.zip
解压后得到一个Memcached.exe文件。启动命令行,将目录切换到Memcached.exe所在目录,在命令行中输入如下命令并回车:
D:\dev\memcached-win64>memcached.exe -d install
至此Memcached服务就安装成功了。在安装Memcached的过程中,你可能会遇到如下问题:
D:\dev\memcached-win64>memcached.exe -d install failed to install service or service already installed造成这个错误的原因可能有以下两个:
-p 监听的端口 -l 连接的IP地址, 默认是本机 -d start 启动memcached服务 -d restart 重起memcached服务 -d stop|shutdown 关闭正在运行的memcached服务 -d install 安装memcached服务 www.2cto.com -d uninstall 卸载memcached服务 -u 以的身份运行 (仅在以root运行的时候有效) -m 最大内存使用,单位MB。默认64MB -M 内存耗尽时返回错误,而不是删除项 -c 最大同时连接数,默认是1024 -f 块大小增长因子,默认是1.25 -n 最小分配空间,key+value+flags默认是48 -h 显示帮助
如下图,表示Memcached已经启动:
接下来可以测试一下是否能够与Memcached通讯。还是使用命令行,这里使用telnet命令。如下:
telnet 127.0.0.1 11211
telnet的格式为telnet ipaddress port,刚才以指定端口11211的方式启动Memcached服务,所以这里可以telnet这个端口。输入以上命令并回车后,DOS窗口会变成空白,表示通讯成功。此时回车,会得到一个ERROR,不用担心,这是因为该命令不存在。如下:
接下来可以通过stats命令查看一下Memcached的相关状态:
1. pid: memcached服务进程的进程ID 2. uptime: memcached服务从启动到当前所经过的时间,单位是秒。 3. time: memcached服务器所在主机当前系统的时间,单位是秒。 4. version: memcached组件的版本。这里是我当前使用的1.2.6。 5. pointer_size:服务器所在主机操作系统的指针大小,一般为32或64. 6. curr_items:表示当前缓存中存放的所有缓存对象的数量。不包括目前已经从缓存中删除的对象。 7. total_items:表示从memcached服务启动到当前时间,系统存储过的所有对象的数量,包括目前已经从缓存中删除的对象。 8. bytes:表示系统存储缓存对象所使用的存储空间,单位为字节。 9. curr_connections:表示当前系统打开的连接数。 10. total_connections:表示从memcached服务启动到当前时间,系统打开过的连接的总数。 11. connection_structures:表示从memcached服务启动到当前时间,被服务器分配的连接结构的数量,这个解释是协议文档给的,具体什么意思,我目前还没搞明白。 12. cmd_get:累积获取数据的数量,这里是3,因为我测试过3次,第一次因为没有序列化对象,所以获取数据失败,是null,后边有2次是我用不同对象测试了2次。 13. cmd_set:累积保存数据的树立数量,这里是2.虽然我存储了3次,但是第一次因为没有序列化,所以没有保存到缓存,也就没有记录。 14. get_hits:表示获取数据成功的次数。 15. get_misses:表示获取数据失败的次数。 16. evictions:为了给新的数据项目释放空间,从缓存移除的缓存对象的数目。比如超过缓存大小时根据LRU算法移除的对象,以及过期的对象。 17. bytes_read:memcached服务器从网络读取的总的字节数。 18. bytes_written:memcached服务器发送到网络的总的字节数。 19. limit_maxbytes:memcached服务缓存允许使用的最大字节数。这里为67108864字节,也就是是64M.与我们启动memcached服务设置的大小一致。 20. threads:被请求的工作线程的总数量。这个解释是协议文档给的,具体什么意思,我目前还没搞明白。
在这一步,你有可能遇到的问题是,在输入telnet命令时,发现它是一个无效的命令。这是因为默认情况下,win7并没有安装此服务。你可用通过控制面板——程序与功能——打开或关闭windows功能,勾选telnet服务器、telnet客户端并点击确定来安装telnet服务,如下图:
安装并启动Memcached后,就可用在项目中使用Memcached了。许多语言都实现了连接memcached的客户端,仅仅在memcached网站上列出的语言就有perl、php、python、ruby、c#、c/c++、lua等等。这里以java作为示例,演示如何在程序中使用Memcached。
要在Java中使用Memcached,需要用到以下jar包:
首先用eclipse新建一个普通的java项目,将上面的jar包添加到项目中,新建一个class如下:
package com.tang; import java.util.Date; import com.danga.MemCached.MemCachedClient; import com.danga.MemCached.SockIOPool; /** * 演示Memcached缓存框架 * * @author tang */ public class MemcachedDemo { public static void main(String[] args) { MemCachedClient client = new MemCachedClient(); // 指定memcached服务地址 String[] servers = { "127.0.0.1:11211" }; // 指定memcached服务器负载量 Integer[] weights = { 3 }; // 从连接池获取一个连接实例 SockIOPool pool = SockIOPool.getInstance(); // 设置服务器和服务器负载量 pool.setServers(servers); pool.setWeights(weights); /* 设置基本参数 */ // 设置初始连接数5 pool.setInitConn(5); // 最小连接数 5 pool.setMinConn(5); // 最大连接数 250 pool.setMaxConn(250); // 最大空闲时间5小时 pool.setMaxIdle(1000 * 60 * 60 * 5); // 设置主线程睡眠时间 // 每隔30秒醒来 然后 // 开始维护 连接数大小 pool.setMaintSleep( 30 ); // 设置tcp 相关的树形 // 关闭nagle算法 pool.setNagle( false ); // 设置读取超时3秒 pool.setSocketTO(3000); // 不设置连接超时 pool.setSocketConnectTO( 0 ); // 开始初始化 连接池 pool.initialize(); // 设置压缩模式(该方法已过时) // client.setCompressEnable( true ); // 如果超过64k压缩数据(该方法已过时) // client.setCompressThreshold( 64 * 1024 ); // 写入缓存数据 client.set("key", "value"); client.set("timeout", "10秒后失效的数据", new Date(10 * 1000)); // 读取缓存数据 System.out.println(client.get("key")); System.out.println(client.get("timeout")); try { Thread.sleep(12 * 1000); System.out.println("12秒过后,key为timeout的缓存数据已经失效"); } catch (InterruptedException e) { e.printStackTrace(); } // 12秒后读取缓存数据 System.out.println(client.get("key")); System.out.println(client.get("timeout")); } }
运行程序,结果如下:
value 10秒后失效的数据 12秒过后,key为timeout的缓存数据已经失效 value null
以上示例可以看出,Memcached通过set向缓存中写入数据,通过get读取缓存中的数据。set同时还可以提供其它参数,比如缓存过期时间等。设置缓存过期时间的缓存,会在指定时间后失效,失效后再读取改缓存,就会得到一个null。
MemCachedClient 类 常用的方法说明
创建 client对象 设置参数:
MemCachedClient mc = new MemCachedClient();
//压缩模式
mc.setCompressEnable(true);
// 如果 cache数据 大于4 KB 就启用压缩
mc.setCompressThreshold(4096);
// 基本类型tostring方法
// 通常不需要设置
mc.setPrimitiveAsString(true);
存储一个对象:
MemCachedClient mc = new MemCachedClient();
String key = "cacheKey1";
Object value = SomeClass.getObject();
mc.set(key, value);
用客户端hashcode 存储一个对象:
MemCachedClient mc = new MemCachedClient();
String key = "cacheKey1";
Object value = SomeClass.getObject();
Integer hash = new Integer(45);
mc.set(key, value, hash);
set方法:在cache中存储一个指定对象
add 和replace 方法功能差不多
add -- 如果不存在 这个key的对象,将会存储一个对象到cache中
replace --只有当存在指定key对象的时候 会覆盖已有对象
删除一个对象:
MemCachedClient mc = new MemCachedClient();
String key = "cacheKey1";
mc.delete(key);
结合hashcode 删除一个对象:
MemCachedClient mc = new MemCachedClient();
String key = "cacheKey1";
Integer hash = new Integer(45);
mc.delete(key, hashCode);
怎么cache计数,增 减计数:
MemCachedClient mc = new MemCachedClient();
String key = "counterKey";
mc.storeCounter(key, new Integer(100));
System.out.println("counter after adding 1: " mc.incr(key));
System.out.println("counter after adding 5: " mc.incr(key, 5));
System.out.println("counter after subtracting 4: " mc.decr(key, 4));
System.out.println("counter after subtracting 1: " mc.decr(key));
利用客户端的hashcode存储计数 增减 计数:
MemCachedClient mc = new MemCachedClient();
String key = "counterKey";
Integer hash = new Integer(45);
mc.storeCounter(key, new Integer(100), hash);
System.out.println("counter after adding 1: " mc.incr(key, 1, hash));
System.out.println("counter after adding 5: " mc.incr(key, 5, hash));
System.out.println("counter after subtracting 4: " mc.decr(key, 4, hash));
System.out.println("counter after subtracting 1: " mc.decr(key, 1, hash));
获取一个对象:
MemCachedClient mc = new MemCachedClient();
String key = "key";
Object value = mc.get(key);
用客户端hashcode获取一个对象:
MemCachedClient mc = new MemCachedClient();
String key = "key";
Integer hash = new Integer(45);
Object value = mc.get(key, hash);
MemCachedClient mc = new MemCachedClient();
String key = "key";
Integer hash = new Integer(45);
Object value = mc.get(key, hash);
从cache 中获取多个对象
MemCachedClient mc = new MemCachedClient();
String[] keys ={ "key", "key1", "key2" };Mapvalues = mc.getMulti(keys);
用客户端hashcode 从cache中获取多个对象
MemCachedClient mc = new MemCachedClient();
String[] keys = { "key", "key1", "key2" };
Integer[] hashes =
{ new Integer(45), new Integer(32), new Integer(44) };
Mapvalues = mc.getMulti(keys, hashes);
清空所有的对象
MemCachedClient mc = new MemCachedClient();
mc.flushAll();
得到服务器memcached的状态信息
MemCachedClient mc = new MemCachedClient();
Map stats = mc.stats();
注意点
1:Failover/Failback
当一个memcached服务器失效的时候客户端默认会failover另一个服务去.
如果失效的服务器 恢复运行,客户端会返回到原来连接的服务器.
如果你不想用这个功能 设置下面的参数
pool.setFailover( false );
pool.setFailback( false );
2:序列化
Boolean
Byte
String
Character
StringBuffer
StringBuilder
Short
Long
Double
Float
Date
java默认的类型没有实现序列化 可以设置
mcc.setPrimitiveAsString( true )替代.
Meetup.com实践过程中得出的一个经验 ,项目中model 对象implement Externalizable 实现序列化,
可以节省cache 对象的大小。从而节省网络带宽和内存空间。
版权声明:本文为博主原创文章,未经博主允许不得转载。