apache + tomcat集群 要考虑session同步 还要考虑缓存同步 在设计的阶段就该考虑到集群的问题,否则真是有解决不完的问题接踵而来,该实现序列化的要实现,单例模式、静态变量、线程同步、定时器什么的,使用的时候就需要慎重考虑,否则到了从单机到集群的时候将会非常痛苦。
session同步tomcat可以搞定,缓存同步目前资料较多的是用oscache和ehcache
以下记录是搜集整理的一些关于oscache分布式缓存的相关资料:
首先oscache本身是没有实现集群的功能,需要利用第三方支持,此处只记录我实际应用的 oscache + jgroups
1、下载oscache所需jar包,官网:http://www.opensymphony.com/oscache/ 下载地址:http://java.net/downloads/oscache/
(我用的版本是oscache-2.4.1.jar,是当前最新的。关于oscache的使用就不多写了,这里主要记录集群相关。)
2、下载jgroups所需jar包,官网:http://www.jgroups.org/ 下载地址:http://sourceforge.net/projects/javagroups/files/JGroups/
(我用的版本是jgroups-2.11.0.GA.jar,我没有看GA和Final后缀的区别,但是Final的不行,少类,所以就用GA的吧。)
3、修改oscache.properties,如果之前没有,创建一个,内容基本不用改动即可。
cache.event.listeners=com.opensymphony.oscache.plugins.clustersupport.JavaGroupsBroadcastingListenerImpl
cache.memory=true
cache.blocking=true
cache.capacity=100000
cache.algorithm=com.opensymphony.oscache.base.algorithm.UnlimitedCache
cache.cluster.properties=UDP(mcast_addr=231.12.21.132;mcast_port=45566;ip_ttl=32;mcast_send_buf_size=150000;mcast_recv_buf_size=80000):PING(timeout=2000;num_initial_members=3):MERGE2(min_interval=5000;max_interval=10000):FD_SOCK:VERIFY_SUSPECT(timeout=1500):pbcast.NAKACK(gc_lag=50;retransmit_timeout=300,600,1200,2400,4800):pbcast.STABLE(desired_avg_gossip=20000):UNICAST(timeout=5000):FRAG(frag_size=8096;down_thread=false;up_thread=false):pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;print_local_addr=true)
cache.cluster.multicast.ip=231.12.21.132
4、oscache并没有实现缓存同步,只提供了相应的通知,所以要创建一个实现类来实现,上面配置的类是创建的实现类,包名.类名是可变更的,对应上配置就行 以下是实现类及相关常量类和序列信息类:
com.opensymphony.oscache.plugins.clustersupport.JavaGroupsBroadcastingListenerImpl
com.opensymphony.oscache.CacheConstants
com.opensymphony.oscache.event.SerialCacheEvent
package com.opensymphony.oscache.plugins.clustersupport;
import com.opensymphony.oscache.CacheConstants;
import com.opensymphony.oscache.base.events.CacheEntryEvent;
import com.opensymphony.oscache.event.SerialCacheEvent;
/**
* oscache集群监听器,继承自jgroup的监听器,根据需要重写相应的函数来实现通知和同步更新。
* @author slzs
* Nov 29, 2012 9:14:00 AM
* each engineer has a duty to keep the code elegant
*/
public class JavaGroupsBroadcastingListenerImpl extends JavaGroupsBroadcastingListener {
/**
* 处理集群通知,接收来自某个节点发来的通知,并进行相应的同步处理
* overriding
* @see com.opensymphony.oscache.plugins.clustersupport.AbstractBroadcastingListener#handleClusterNotification(com.opensymphony.oscache.plugins.clustersupport.ClusterNotification)
* @author: slzs
* Nov 29, 2012 9:16:28 AM
* @param message
* each engineer has a duty to keep the code elegant
*/
public void handleClusterNotification(ClusterNotification message) {
switch (message.getType()) {
case CacheConstants.CLUSTER_ENTRY_ADD:
System.out.println("集群新增:" + message.getData());
if (message.getData() instanceof SerialCacheEvent) {
SerialCacheEvent event = (SerialCacheEvent) message.getData();
cache.putInCache(event.getKey(), event.getEntry().getContent(), null, null, CLUSTER_ORIGIN);
}
break;
case CacheConstants.CLUSTER_ENTRY_UPDATE:
System.out.println("集群更新:" + message.getData());
if (message.getData() instanceof SerialCacheEvent) {
SerialCacheEvent event = (SerialCacheEvent) message.getData();
cache.putInCache(event.getKey(), event.getEntry().getContent(), null, null, CLUSTER_ORIGIN);
}
break;
case CacheConstants.CLUSTER_ENTRY_DELETE:
System.out.println("集群删除:" + message.getData());
if (message.getData() instanceof SerialCacheEvent) {
SerialCacheEvent event = (SerialCacheEvent) message.getData();
cache.removeEntry(event.getKey());
}
break;
}
}
/**
* 新增缓存后通知其它子节点
* overriding
* @see com.opensymphony.oscache.plugins.clustersupport.AbstractBroadcastingListener#cacheEntryAdded(com.opensymphony.oscache.base.events.CacheEntryEvent)
* @author: slzs
* Nov 29, 2012 9:17:29 AM
* @param event
* each engineer has a duty to keep the code elegant
*/
@Override
public void cacheEntryAdded(CacheEntryEvent event) {
super.cacheEntryAdded(event);
if (!CLUSTER_ORIGIN.equals(event.getOrigin())) {
sendNotification(new ClusterNotification(CacheConstants.CLUSTER_ENTRY_ADD, new SerialCacheEvent(event.getMap(), event.getEntry(), CLUSTER_ORIGIN)));
}
}
/**
* 移除缓存后通知其它子节点
* overriding
* @see com.opensymphony.oscache.plugins.clustersupport.AbstractBroadcastingListener#cacheEntryAdded(com.opensymphony.oscache.base.events.CacheEntryEvent)
* @author: slzs
* Nov 29, 2012 9:17:29 AM
* @param event
* each engineer has a duty to keep the code elegant
*/
@Override
public void cacheEntryRemoved(CacheEntryEvent event) {
super.cacheEntryRemoved(event);
if (!CLUSTER_ORIGIN.equals(event.getOrigin())) {
sendNotification(new ClusterNotification(CacheConstants.CLUSTER_ENTRY_DELETE, new SerialCacheEvent(event.getMap(), event.getEntry(), CLUSTER_ORIGIN)));
}
}
/**
* 更新缓存后通知其它子节点
* overriding
* @see com.opensymphony.oscache.plugins.clustersupport.AbstractBroadcastingListener#cacheEntryAdded(com.opensymphony.oscache.base.events.CacheEntryEvent)
* @author: slzs
* Nov 29, 2012 9:17:29 AM
* @param event
* each engineer has a duty to keep the code elegant
*/
@Override
public void cacheEntryUpdated(CacheEntryEvent event) {
super.cacheEntryUpdated(event);
if (!CLUSTER_ORIGIN.equals(event.getOrigin())) {
sendNotification(new ClusterNotification(CacheConstants.CLUSTER_ENTRY_UPDATE, new SerialCacheEvent(event.getMap(), event.getEntry(), CLUSTER_ORIGIN)));
}
}
}
package com.opensymphony.oscache;
/**
* oscache分布式缓存通知所需部分常量
* @author slzs
* Nov 28, 2012 1:39:20 PM
* note each engineer has a duty to keep the code elegant
*/
public class CacheConstants {
/**
* 添加缓存对象操作
*/
public final static int ACTION_ADD_OBJ = 1;
/**
* 更新缓存对象操作
*/
public final static int ACTION_UPDATE_OBJ = 2;
/**
* 删除缓存对象操作
*/
public final static int ACTION_DELETE_OBJ = 3;
/**
* 刷新缓存对象
*/
public final static int ACTION_FLUSH_OBJ = 4;
/**
* 集群entry add处理
*/
public final static int CLUSTER_ENTRY_ADD = 20;
/**
* 集群entry update处理
*/
public final static int CLUSTER_ENTRY_UPDATE = 21;
/**
* 集群entry delete处理
*/
public final static int CLUSTER_ENTRY_DELETE = 22;
}
package com.opensymphony.oscache.event;
import java.io.Serializable;
import com.opensymphony.oscache.base.Cache;
import com.opensymphony.oscache.base.CacheEntry;
import com.opensymphony.oscache.base.events.CacheEvent;
/**
* 序列信息类
* @author slzs
* Nov 29, 2012 9:37:17 AM
* each engineer has a duty to keep the code elegant
*/
@SuppressWarnings("serial")
public class SerialCacheEvent extends CacheEvent implements Serializable {
private Cache map = null;
private CacheEntry entry = null;
public SerialCacheEvent(Cache map, CacheEntry entry) {
this(map, entry, null);
}
public SerialCacheEvent(Cache map, CacheEntry entry, String origin) {
super(origin);
this.map = map;
this.entry = entry;
}
public CacheEntry getEntry() {
return entry;
}
public String getKey() {
return entry.getKey();
}
public Cache getMap() {
return map;
}
public String toString() {
return "key=" + entry.getKey();
}
}
5、配上jgroup的日志,log4j.properties 里加入 log4j.logger.org.jgroups.blocks=DEBUG
完成了