memcache缓存

一、概述

1       Memcache是什么

Memcache是danga.com的一个项目,最早是为 LiveJournal 服务的,目前全世界不少人使用这个缓存项目来构建自己大负载的网站,来分担数据库的压力。

它可以应对任意多个连接,使用非阻塞的网络IO。由于它的工作机制是在内存中开辟一块空间,然后建立一个HashTable,Memcached自管理这些HashTable。
  
为什么会有Memcache和memcached两种名称?

其实Memcache是这个项目的名称,而memcached是它服务器端的主程序文件名,

Memcache官方网站:http://www.danga.com/memcached,


2       Memcache工作原理
首先 memcached 是以守护程序方式运行于一个或多个服务器中,随时接受客户端的连接操作,客户端可以由各种语言编写,目前已知的客户端 API 包括 Perl/PHP/Python/Ruby/Java/C#/C 等等。客户端在与 memcached 服务建立连接之后,接下来的事情就是存取对象了,每个被存取的对象都有一个唯一的标识符 key,存取操作均通过这个 key 进行,保存到memcached 中的对象实际上是放置内存中的,并不是保存在 cache 文件中的,这也是为什么 memcached 能够如此高效快速的原因。注意,这些对象并不是持久的,服务停止之后,里边的数据就会丢失。
与许多 cache 工具类似,Memcached 的原理并不复杂。它采用了C/S的模式,在 server 端启动服务进程,在启动时可以指定监听的 ip,自己的端口号,所使用的内存大小等几个关键参数。一旦启动,服务就一直处于可用状态。Memcached 的目前版本是通过C实现,采用了单进程,单线程,异步I/O,基于事件 (event_based) 的服务方式.使用libevent 作为事件通知实现。多个 Server 可以协同工作,但这些 Server 之间是没有任何通讯联系的,每个 Server 只是对自己的数据进行管理。Client 端通过指定 Server 端的 ip 地址(通过域名应该也可以)。需要缓存的对象或数据是以 key->value对的形式保存在Server端。key 的值通过 hash 进行转换,根据 hash 值把 value 传递到对应的具体的某个 Server 上。当需要获取对象数据时,也根据 key 进行。首先对 key 进行 hash,通过获得的值可以确定它被保存在了哪台 Server 上,然后再向该 Server 发出请求。Client 端只需要知道保存 hash(key) 的值在哪台服务器上就可以了。
        其实说到底,memcache 的工作就是在专门的机器的内存里维护一张巨大的 hash 表,来存储经常被读写的一些数组与文件,从而极大的提高网站的运行效率。

二、服务器端安装(Windows)

1)下载memcached服务端memcached-1.2.6-win32-bin.zip,地址:http://code.jellycan.com/memcached/
2)解压缩memcached-1.2.6-win32-bin.zip到指定目录,例如:D:memcached-1.2.6-win32 , 
在终端(即cmd命令行界面),
执行'D:memcached-1.2.6-win32memcached.exe -d install' 安装,
再执行:'D:memcachedmemcached.exe -d start'启动,
或者'memcachedmemcached.exe -l 127.0.0.1 -m 32 -d start',分配32M内存
这样memcache就会作为windows系统服务在每 次开机时启动memcache服务。

修改端口:
可以直接修改注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\memcached Server\下的ImagePath为
"x:\xxx\memcached.exe" -p 端口 -m 内存 -d runservice

三、Java客户端使用Memcache

下载java客户端jar包java_memcached-release_1.6.zip,将java_memcached-release_1.6.zip解压后的目录中的java_memcached-release_1.6.jar文件复制到java项目的lib目录下
public class MemCached {
// 创建全局的唯一实例
protected static MemCachedClient mcc = new MemCachedClient();
protected static MemCached memCached = new MemCached();

// 设置与缓存服务器的连接池
static {
// 服务器列表和其权重
String[] servers = { "127.0.0.1:11211" };
Integer[] weights = { 3 };

// 获取socke连接池的实例对象
SockIOPool pool = SockIOPool.getInstance();

// 设置服务器信息
pool.setServers(servers);
pool.setWeights(weights);


// 设置初始连接数、最小和最大连接数以及最大处理时间
pool.setInitConn(5);
pool.setMinConn(5);
pool.setMaxConn(250);
pool.setMaxIdle(1000 * 60 * 60 * 6);


// 设置主线程的睡眠时间
pool.setMaintSleep(30);


// 设置TCP的参数,连接超时等
pool.setNagle(false);
pool.setSocketTO(3000);
pool.setSocketConnectTO(0);


// 初始化连接池
pool.initialize();


// 压缩设置,超过指定大小(单位为K)的数据都会被压缩
mcc.setCompressEnable(true);
mcc.setCompressThreshold(64 * 1024);
}

/**
* 保护型构造方法,不允许实例化!

*/
protected MemCached() {


}


/**
* 获取唯一实例.

* @return
*/
public static MemCached getInstance() {
return memCached;
}


/**
* 添加一个指定的值到缓存中.

* @param key
* @param value
* @return
*/
public boolean add(String key, Object value) {
return mcc.add(key, value);
}


public boolean add(String key, Object value, Date expiry) {
return mcc.add(key, value, expiry);
}


public boolean replace(String key, Object value) {
return mcc.replace(key, value);
}


public boolean replace(String key, Object value, Date expiry) {
return mcc.replace(key, value, expiry);
}


/**
* 根据指定的关键字获取对象.

* @param key
* @return
*/
public Object get(String key) {
return mcc.get(key);
}


public static void main(String[] args) {
MemCached cache = MemCached.getInstance();
cache.add("hello", 234);
System.out.print("get value : " + cache.get("hello"));
}
}
通过简单的像main方法中操作的一样存入一个变量,然后再取出进行查看,可以看到先调用了add,然后再进行get,运行一次后,234这个值已经存入了memcached的缓存中的了,将main方法中“cache.add("hello", 234);”注释掉后,再运行还是可以看到get到的value也是234,即缓存中已经存在了数据了。




**********************************************************************************************


对基本的数据我们可以操作,对于普通的POJO而言,如果要进行存储的话,那么比如让其实现java.io.Serializable接口,因为 memcached是一个分布式的缓存服务器,多台服务器间进行数据共享需要将对象序列化的,所以必须实现该接口,否则会报错的。
public class User implements Serializable {

private String name;

private int age;


public String getName() {
return name;
}


public void setName(String name) {
this.name = name;
}


public int getAge() {
return age;
}


public void setAge(int age) {
this.age = age;
}
}


在MemCached的main方法中:
public static void main(String[] args) {
MemCached cache = MemCached.getInstance();

User user = new User();
user.setName("nihao");
user.setAge(22);
cache.add("user", user);
User u = (User) cache.get("user");
System.out.print("get name : " + u.getName());
System.out.print("get age : " + u.getAge());
}


首先把User的一个实例放入缓存中,然后再取出来,并进行名称的修改,然后再取这个对象,再看其名称,发现修改的对象并不是缓存中的对象,而是通过序列化过来的一个实例对象,这样就无须担心对原生类的无意修改导致缓存数据失效了。所以这表明从缓存中获取的对象是存入对象的一个副本,对获取对象的修改并不能真正的修改缓存中的数据,而应该使用其提供的replace等方法来进行修改。

四、Spring与Memcache的集成
Spring与Memcache的集成


1. Memcache配置属性文件
memcache.properties文件内容如下:
mcache.server=127.0.0.1:11211
memcache.initConn=20
memcache.minConn=10
memcache.maxConn=50
memcache.maintSleep=3000
memcache.nagle=false
memcache.socketTO=3000






2. 新建配置文件(spring级别)
新建名为spring-memcache.xml的spring配置文件
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-2.5.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:memcache.properties</value>
</list>
</property>
</bean>




<bean class="com.danga.MemCached.SockIOPool" destroy-method="shutDown" factory-method="getInstance" id="memcachedPool" init-method="initialize">

<property name="servers">
<list>
<value>${mcache.server}</value>
</list>
</property>
<property name="initConn">
       <value>${memcache.initConn}</value>
</property>
<property name="minConn">
        <value>${memcache.minConn}</value>
</property>
<property name="maxConn">
        <value>${memcache.maxConn}</value>
</property>
<property name="maintSleep">
        <value>${memcache.maintSleep}</value>
</property>
<property name="nagle">
       <value>${memcache.nagle}</value>
</property>
<property name="socketTO">
       <value>${memcache.socketTO}</value>
</property>
</bean>
 
<bean class="com.danga.MemCached.MemCachedClient" id="memcachedClient">

<property name="compressEnable">
<value>true</value>
</property>
<property name="compressThreshold">
<value>4096</value>
</property>
</bean>


3.Web.xml文件中配置新建的文件
<!-- 配置spring的监听器,加载Spring配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/applicationContext.xml,classpath:/mvc-config.xml</param-value>
</context-param>






调用Memcache
(1)通过web方式调用,
@Controller
@RequestMapping("/memcache")
public class SpringMemcache {


@Autowired
private MemCachedClient memcachedClient;

@RequestMapping("/getCache")
public String welcome(HttpServletRequest request,
HttpServletResponse response) throws MyException {

memcachedClient.set("name", "yunhui");
System.out.println(memcachedClient.get("name"));
return "/page/welcome";
}


}


(2)通过Java Application方式调用:
public class A {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext(
new String[] {"/applicationContext.xml",
"/mvc-config.xml" });

MemCachedClient memcachedClient = (MemCachedClient) ac
.getBean("memcachedClient");
User user = new User();
user.setName("nihao2");
user.setAge(22);
memcachedClient.replace("user", user);
User u = (User) memcachedClient.get("user");
System.out.print("get name : " + u.getName());
System.out.print("get age : " + u.getAge());
}
}






















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值