那些不需要“分布”的,不需要共享的,或者干脆规模小到只有一台服务器的应用,Memcached不会带来任何好处,相反还会拖慢系统效率,因为网络连接同样需要资源。
本章节基于Java来介绍和测试Memcached的负载均衡,在这之前需要下载基于Java的客户端:java_memcached-release_2.6.6.zip,网址是https://github.com/gwhalin/Memcached-Java-Client/downloads,它是比较通用的Memcached客户端框架,依赖的JAR包有:commons-pool-1.5.6.jar、java_memcached-release_2.6.6.jar、slf4j-api-1.6.1.jar、slf4j-simple-1.6.1.jar。
具体的测试过程如下:
1.开启Memcached多个端口
这里仅以开启一台服务器的多个节点来模拟测试环境:
[root@zengxiangtao~]# memcached -d -m 512-c 512-p 11211 -u root -t 10
[root@zengxiangtao~]# memcached -d -m 512-c 512 -p 11212 -u root -t 10
[root@zengxiangtao~]# netstat -ntlp | grep memcached
1.编写测试代码
下面的脚本主要用于插入数据到上面Memcached开启的2个端口中,这里我们插入1000条“key”数据,插入后通过查询数据分布比例来看是否能够负载均衡,分别对2个端口的数据进行查询,看是否达到了负载均衡,通过执行结果可知通过11211端口插入了503条数据,11212端口插入了497条数据,两个端口存数据的比例几乎是50%:50%,是均衡分布的。
import java.util.Date;
import com.danga.MemCached.MemCachedClient;
import com.danga.MemCached.SockIOPool;
public class MemcachedDemo{
protected static MemCachedClient mcc=new MemCachedClient();
public static MemCachedClient getMcc(){
return mcc;
}
protected static MemcachedDemo memCached=new MemcachedDemo();
static{
//指定memcached服务地址
String[]servers={"192.183.3.189:11211","192.183.3.189:11211"};
//指定memcached服务器负载量
Integer[]weights={3,3};
//从连接池获取一个连接实例
SockIOPool pool=SockIOPool.getInstance();
//设置服务器和服务器负载量
pool.setServers(servers);
pool.setWeights(weights);
//设置一些基本的参数,设置初始连接数5,最小连接数5,最大连接数250
pool.setInitConn(5);
pool.setMinConn(5);
pool.setMaxConn(250);
//设置一个连接最大空闲时间6小时
pool.setMaxIdle(1000*60*60*6);
//设置主线程睡眠时间,每隔30秒醒来然后开始维护连接数大小
pool.setMaintSleep(30);
//设置tcp相关的树形,关闭nagle算法,设置读取超时3秒钟set the read timeout to 3 secs,不设置连接超时
pool.setNagle(false);
pool.setSocketTO(3000);
pool.setSocketConnectTO(0);
//开始初始化连接池
pool.initialize();
//压缩设置,超过指定大小(单位为K)的数据都会被压缩
//mcc.setCompressEnable(true);
//如果超过64k压缩数据
//mcc.setCompressThreshold(64*1024);
}
protected MemcachedDemo(){
}
public static MemcachedDemo getInstance(){
return memCached;
}
/**
*add:对Memcahed的add命令的封装仅当缓存中不存在键时,
*add命令才会向缓存中添加一个键值对。如果缓存中已经存在键,
*则之前的值将仍然保持相同,并且您将获得响应NOT_STORED.
*/
public boolean add(String key,Object value){
return mcc.add(key,value);
}
/**
*add:对Memcahed的add命令仅当缓存中不存在键时,
*add命令才会向缓存中添加一个键值对。如果缓存中已经存在键,
*则之前的值将仍然保持相同,并且您将获得响应NOT_STORED.
*/
public boolean add(String key,Object value,Date expiry){
return mcc.add(key,value,expiry);
}
/**
*add:对Memcahed的add命令的封装仅当缓存中不存在键时,
*add命令才会向缓存中添加一个键值对。如果缓存中已经存在键,
*则之前的值将仍然保持相同,并且您将获得响应NOT_STORED.
*/
public boolean replace(String key,Object value){
return mcc.replace(key,value);
}
/**
*replace:对Memcahed的replace命令仅当键已经存在时,
*replace命令才会替换缓存中的键。如果缓存中不存在键,
*那么您将从memcached服务器接受到一条NOT_STORED响应.
*/
public boolean replace(String key,Object value,Date expiry){
return mcc.replace(key,value,expiry);
}
/**
*get:get对Memcahed的get命令的封装命令用于检索
*与之前添加的键值对相关的值.
*/
public Object get(String key){
return mcc.get(key);
}
public static void main(String[]args){
MemcachedDemo cache=MemcachedDemo.getInstance();
//插入数据到指定的服务器
for(int i=0;i<1000;i++){
cache.add("key"+i,"value"+i);
}
//查询对应服务器的数据存储量
//int count=0;
// for(int i=0;i<1000;i++){
// if(cache.get("key"+i)!=null){
// count++;
// }
// }
// System.out.println(count);
}
}
以上的脚本因为每次统计端口数据还需要注释掉插入数据的代码,所以进行了以下的改进,让插入和统计同时进行:
import java.util.Date;
import com.danga.MemCached.MemCachedClient;
import com.danga.MemCached.SockIOPool;
public class MemcachedDemo1{
protected static MemCachedClient mcc=new MemCachedClient();
public static MemCachedClient getMcc(){
return mcc;
}
protected static MemcachedDemo1 memCached=new MemcachedDemo1();
protected MemcachedDemo1(){
}
public static MemcachedDemo1 getInstance(){
return memCached;
}
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);
}
public Object get(String key){
return mcc.get(key);
}
public static void main(String[]args){
MemcachedDemo1 cache=MemcachedDemo1.getInstance();
cache.setServers(new String[]{"192.183.3.189:11211","192.183.3.189:11212"});
for(int i=0;i<2000;i++){
cache.add("key"+i,"value"+i);
}
int count1=0;
cache.setServers(new String[]{"192.183.3.189:11211"});
for(int i=0;i<2000;i++){
if(cache.get("key"+i)!=null){
count1++;
}
}
System.out.println("11211"+count1);
int count2=0;
cache.setServers(new String[]{"192.183.3.189:11212"});
for(int i=0;i<2000;i++){
if(cache.get("key"+i)!=null){
count2++;
}
}
System.out.println("11212"+count2);
}
public void setServers(String[]servers){
Integer[]weights={3,3};
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);
pool.setNagle(false);
pool.setSocketTO(3000);
pool.setSocketConnectTO(0);
pool.initialize();
}
}
如有兴趣,可以对以上的代码进行修改,测试一下节点分布在不同服务器上时负载均衡的情况—多个端口同时同步。