一、安装memcached
Memcached本身不支持分布式,需要客户端实现分布式:
2.先安装libevent:
3.测试libevent是否安装成功:
看到libevent,成功
4.安装memcached,同时需要安装中指定libevent的安装位置:
安装成功。
5.开启memcached
6. 测试是否安装成功
设置完之后可以拿回出来
http://www.cnblogs.com/jeffwongishandsome/archive/2011/11/06/2238265.html
二、在java中使用memcached
Memcached本身不支持分布式,需要客户端实现分布式:
Memcached需要把相应的jar包放到Tomcat的lib文件中,下载地址:
1.安装Memcached
如果你是用Ubuntu,直接
sudo apt-get install memcached
就可以了,我用的是Ubuntu的13.04版本。当然,这一般来说不是最新的版本,源更新没有官网下载的那么快,所以你也可以下载相应的tar.gz文件
安装Memcached需要下载两个文件,一个是Memcached,另外一个是libevent,因为Memcached的工作机制是基于libevent,所以需要安装。这是安装Memcached必须的文件
libevent官网:
http://libevent.org/
memcached官网:
http://www.memcached.org/
版本:v1.4.20
2.先安装libevent:
# tar -zxvf libevent-2.0.21-stable.tar.gz
# cd libevent-2.0.21-stable
# ./configure –prefix=/usr
# make
# make install
3.测试libevent是否安装成功:
# ls -al /usr/lib | grep libevent
看到libevent,成功
4.安装memcached,同时需要安装中指定libevent的安装位置:
# cd /tmp
# tar -zxvf memcached-1.4.20.tar.gz
# cd memcached-1.4.20
# ./configure –with-libevent=/usr
# make
# make install
如果中间出现报错,请仔细检查错误信息,按照错误信息来配置或者增加相应的库或者路径。
安装完成后会把memcached放到 /usr/local/bin/memcached
安装完成后会把memcached放到 /usr/local/bin/memcached
可以使用whereis memcached来查看是否安装成功
安装成功。
5.开启memcached
# memcached -d -m 512 -p 12000 -u root -l localhost -c 256 -P /var/run/memcached.pid
-d 以守护进程开启 -m 分配512MB内存 -p 端口号为12000 -l IP为localhost,可以指定任意IP(如192.168.1.100) -最大连接数256(默认1024)6. 测试是否安装成功
# telnet localhost 12000
输入指定的ip和端口
因为Memcached就是一个巨大的hash表,所以当然是存储和显示键对值
set key1 0 60 8
richlu
上面就是设置了一个key1的key,flags值为0,60s过期,8个字节,value为richlu的值
存储命令的格式:
1
2
|
<command name> <key> <flags> <exptime> <bytes>
<data block>
|
参数说明如下:
<command name> | set/add/replace |
<key> | 查找关键字 |
<flags> | 客户机使用它存储关于键值对的额外信息 |
<exptime> | 该数据的存活时间,0表示永远 |
<bytes> | 存储字节数 |
<data block> | 存储的数据块(可直接理解为key-value结构中的value) |
get key1功
总的测试就是:
telnet localhost 12000
set key1 0 60 8
richlu
get key1
quit
这是详细说明Memcached的常用命令参考:
http://www.cnblogs.com/jeffwongishandsome/archive/2011/11/06/2238265.html
二、在java中使用memcached
在这里我使用的是memcached client for java。另外两种方式是XMemcached和spymecached,这里不做详细介绍,有兴趣的自行查找。
首先需要一个jar包 使用memcached的jar包是:java_memcached-release_2.5.3.jar
会用git的人就用git吧,不会用的话就下载zip文件,解压后用ant来构造jar包吧
测试代码:
至此,我们应该算是能够真正使用Memcached
三、一致性哈希算法
获取hashCode和hash散列值
测试代码:
package com.rich.test;
import com.meetup.memcached.MemcachedClient;
import com.meetup.memcached.SockIOPool;
public class MemcacheTest {
protected static MemcachedClient mcc = new MemcachedClient();
//设置缓存服务器列表,当使用分布式缓存时,可以指定多个缓存服务器
static {
String[] servers =
{
"localhost:12000",
// "localhost:12111",
};
//创建一个SockIOPool实例
SockIOPool pool = SockIOPool.getInstance();
pool.setServers(servers);
pool.setNagle(false);
pool.setSocketTO(3000);
pool.setSocketConnectTO(0);
pool.initialize();
}
public static void main(String[] args) {
mcc.set("foo", "This is a test String");
String bar = mcc.get("foo").toString();
System.out.println(">>>" + bar);
}
}
另外两种方式可以参考:http://jiaxiaoyuan1204.blog.163.com/blog/static/65553152010520112614157/至此,我们应该算是能够真正使用Memcached
三、一致性哈希算法
memcached本身是集中式的缓存系统,要搞多节点分布,只能通过客户端实现。
memcached的分布算法一般有两种选择:
1、hash模余算法:
根据hash(key)的结果,模连接数的余数决定存储到哪个节点(键的整数哈希值,根据服务器个数取余来选定服务器节点),也就是hash(key)% sessions.size(),这个余数计算的方法简单,数据的分散性也相当优秀。
但也有其缺点。那就是当添加或移除服务器时,缓存重组的代价相当巨大。添加/删除服务器后(特别是某台服务器down机之后),余数就会产生巨变,这样就无法保证获取时计算的服务器节点与保存时相同,从而影响缓存的命中率——造成原有的缓存数据将大规模失效。
2、一致性hash(Consistent Hashing)
一致性hash(Consistent Hashing)如下所示:首先求出memcached服务器(节点)的哈希值,并将其配置到0~2^32的圆(continuum)上。然后用同样的方法 求出存储数据的键的哈希值,并映射到圆上。然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过232仍然找不到服务器, 就会保存到第一台memcached服务器上。
//不太懂一致性hash中虚拟节点的用法
答:虚拟节点是为了能让服务器节点能够均匀分布在圆上,有利于负载均衡。其实现是复制服务器节点,增加服务器节点的个数。
获取hashCode和hash散列值
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
public class ConsistencyHash {
private TreeMap<Long,Object> nodes = null;
//真实服务器节点信息
private List<Object> shards = new ArrayList();
//设置虚拟节点数目
private int VIRTUAL_NUM = 4;
/**
* 初始化一致环
*/
public void init() {
shards.add("192.168.0.0-服务器0");
shards.add("192.168.0.1-服务器1");
shards.add("192.168.0.2-服务器2");
shards.add("192.168.0.3-服务器3");
shards.add("192.168.0.4-服务器4");
nodes = new TreeMap<Long,Object>();
for(int i=0; i<shards.size(); i++) {
Object shardInfo = shards.get(i);
for(int j=0; j<VIRTUAL_NUM; j++) {
nodes.put(hash(computeMd5("SHARD-" + i + "-NODE-" + j),j), shardInfo);
}
}
}
/**
* 根据key的hash值取得服务器节点信息
* @param hash
* @return
*/
public Object getShardInfo(long hash) {
Long key = hash;
SortedMap<Long, Object> tailMap=nodes.tailMap(key);
if(tailMap.isEmpty()) {
key = nodes.firstKey();
} else {
key = tailMap.firstKey();
}
return nodes.get(key);
}
/**
* 打印圆环节点数据
*/
public void printMap() {
System.out.println(nodes);
}
/**
* 根据2^32把节点分布到圆环上面。
* @param digest
* @param nTime
* @return
*/
public long hash(byte[] digest, int nTime) {
long rv = ((long) (digest[3+nTime*4] & 0xFF) << 24)
| ((long) (digest[2+nTime*4] & 0xFF) << 16)
| ((long) (digest[1+nTime*4] & 0xFF) << 8)
| (digest[0+nTime*4] & 0xFF);
return rv & 0xffffffffL; /* Truncate to 32-bits */
}
/**
* Get the md5 of the given key.
* 计算MD5值
*/
public byte[] computeMd5(String k) {
MessageDigest md5;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("MD5 not supported", e);
}
md5.reset();
byte[] keyBytes = null;
try {
keyBytes = k.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Unknown string :" + k, e);
}
md5.update(keyBytes);
return md5.digest();
}
public static void main(String[] args) {
Random ran = new Random();
ConsistencyHash hash = new ConsistencyHash();
hash.init();
hash.printMap();
//循环50次,是为了取50个数来测试效果,当然也可以用其他任何的数据来测试
for(int i=0; i<50; i++) {
System.out.println(hash.getShardInfo(hash.hash(hash.computeMd5(String.valueOf(i)),ran.nextInt(hash.VIRTUAL_NUM))));
}
}
}
以上是memcached的散列实现,当然我们只要调用它的jar包,即java_memcached-release_2.5.3.jar包,按照上面的使用方法就已经实现了一致性hash了。
关于Memcached client for java的api可以参考:
http://blog.csdn.net/qqiabc521/article/details/6438429