您的位置:首页 > 数据库 > Memcache

Windows下java memcached 使用

2015-07-09 11:50 676 查看

一,Memcached介绍

memcached是被广泛使用的分布式缓存技术,使用它的目的是,通过它缓存数据库查询结果,减少数据库访问次数,提高动态Web应用的速度。

memcached作为分布式缓存服务器,具有如下的特点:

(1)协议简单:

memcached的服务器和客户端使用的通信协议是简单的基于文本行的协议,因此我们可以通过telnet也能在memcached服务器上保存/获取数据,如下:





(2)基于libevent的事件处理:

libevent是个程序库,memcached通过libevent能在linux、BSD等操作系统上发挥其高性能的特性。

(3)内置内存存储方式:

为了提高性能,memcached将数据保存在其内置的内存存储空间里,同样也是因为如此,所以当memcached重启、重启操作系统等操作会导致memcached存储的数据丢失。

另外,当内容的容量达到指定的值后,memcached会使用LRU算法自动删除不使用的缓存,以释放空间。

(4)memcached不互相通信的分布式:

经常说到memcached是分布式的缓存技术,但是它的分布式不是指服务器端的分布式,因为服务器端并没有分布式的功能。它的分布式是通过客户端来实现的,见下图



二,Windows下memcached的使用

1, 用到的jar包



其中Memcached-Java-Client-3.0.0.jar为memcached客户端,jar和源码下载地址http://search.maven.org/

2, 部分代码

public class MemcachedTest {

protected static MemCachedClient mcc = new MemCachedClient();
protected static MemcachedTest memcachedTest = new MemcachedTest();

//设置与memcached服务器的连接信息
static{
/// 服务器列表和其权重
String [] servers  = {"127.0.0.1:11211","192.168.0.101:11211"};
Integer [] weights = {5,5};

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

pool.setServers(servers);
pool.setWeights(weights);

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

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

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

pool.setHashingAlg(SockIOPool.CONSISTENT_HASH);

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

}

/**
* 保护型构造方法,不允许实例化!
*
*/
protected MemcachedTest() {

}

/**
* 获取唯一实例.
*
* @return
*/
public static MemcachedTest getInstance() {
return memcachedTest;
}

/**
* 添加数据
* @param key
* @param value
* @return
*/
public boolean add(String key, String value){
return mcc.add(key, value);
}

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

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

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

public Object get(String key){
return mcc.get(key);
}

public Object flush(){
return mcc.flushAll();
}

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
MemcachedTest mt = MemcachedTest.getInstance();
mt.flush();
for (int i = 0; i < 10; i ++){
mt.add("hello"+ i, "world" + i);
}
for(int i = 0; i < 10; i ++){
System.out.println("the value of key Hello" + i +" is: " + mt.get("hello" + i));
}
}

}


首先,我们需要一个memcachedClient对象,该对象实现将数据添加到memcached服务器或者从服务器读取数据。然后初始化一个SockIOPool对象,该对象用来维护一个到memcached服务器的持续的连接池,连接池必须在使用前初始化。

3, memcached Client源码解读

在将数据添加到服务器这个过程,主要涉及到了客户端的下面的几个类:

MemCachedClient:生成客户端的入口

AscIIClient: memcachedClient的子类,负责具体的client的实例化

SchoonerSockIOPool

SockIOPool

(1) 初始化一个memcached client对象

protected static MemCachedClient mcc = new MemCachedClient();

查看client的源码发现它会通过解析参数,生成一个子类AscIIClient的对象。

/**
* Creates a new instance of MemCachedClient.
*/
public MemCachedClient() {
this(null, true, false);
}

/**
* Create memcached client.
*
* @param poolName
*            name of SockIOPool
* @param isTCP
*            use tcp protocol
* @param binaryProtocal
*            use binary protocol.
*/
public MemCachedClient(String poolName, boolean isTcp, boolean binaryProtocal) {
if (binaryProtocal)
client = new BinaryClient(poolName);
else
client = isTcp ? new AscIIClient(poolName) : new AscIIUDPClient(poolName);
}


(2)在子类AscIIClient中,定义了一个pool的实例如下:

// pool instance
private SchoonerSockIOPool pool;


根据上面第一点,在生成memcached client实例时,其实实际上生成的AscIIClient的实例,如下:

/**
* Creates a new instance of MemCachedClient accepting a passed in pool
* name.
*
* @param poolName
*            name of SockIOPool
* @param binaryProtocal
*            whether use binary protocol.
*/
public AscIIClient(String poolName) {
super((MemCachedClient) null);
this.poolName = poolName;
init();
}


其中init()方法主要是完成一个默认的(default)client的初始化。

/**
* Initializes client object to defaults.
*
* This enables compression and sets compression threshhold to 15 KB.
*/
private void init() {
this.sanitizeKeys = true;
this.primitiveAsString = false;
this.compressEnable = false;
this.compressThreshold = COMPRESS_THRESH;
this.defaultEncoding = "UTF-8";
this.poolName = (this.poolName == null) ? "default" : this.poolName;

// get a pool instance to work with for the life of this instance
this.pool = SchoonerSockIOPool.getInstance(poolName);
}


(3)SockIOPool和SchoonerSockIOPool的关系:

在SockIOPool中,定义了一个SchoonerSockIOPool的实例,在初始化SockIOPool的时候,同时会获取一个SchoonerSockIOPool的对象。

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


/**
* Single argument version of factory used for back compat. Simply creates a
* pool named "default".
*
* @return instance of SockIOPool
*/
public static SockIOPool getInstance() {
SockIOPool whalinSockIOPool = new SockIOPool();
whalinSockIOPool.schoonerSockIOPool = SchoonerSockIOPool.getInstance("default");
return whalinSockIOPool;
}


(4) 通过SchoonerSockIOPool.getInstance方法获取一个SchoonerSockIOPool的实例时,程序会先检查连接池里面是否有名称为“default”的pool,若有,则取处理返回; 若无,生成名称为“default”的pool,并将该pool放置到连接池里面。

/**
* Factory to create/retrieve new pools given a unique poolName.
*
* @param poolName
*            unique name of the pool
* @return instance of SockIOPool
*/
public static SchoonerSockIOPool getInstance(String poolName) {
SchoonerSockIOPool pool;

synchronized (pools) {
if (!pools.containsKey(poolName)) {
pool = new SchoonerSockIOPool(true);
pools.putIfAbsent(poolName, pool);
}
}

return pools.get(poolName);
}


未完待续……

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: