我正在处理wicket会话存储,数据存储,页面存储的自定义实现。我有cu簇wicket并使其在以下情况下工作:
集群中有2个节点,节点1发生故障,用户应该能够在不注意的情况下继续流程,页面状态良好,并且有很多ajax请求。现在我将wicket会话存储在rmi上的自定义存储中,并且我试图扩展DiskPageStore。新的挑战是SessionEntry内部类,它仍然由ConcurrentMap持有。
我的问题是:有没有人这样做过?你对如何做到这一点有什么建议吗?
答案 0 :(得分:5)
我的建议是忘记你的情况下的DiskPageStore和SessionEntry。您提到的ConcurrentMap在本地保存在堆中。一旦其中一个节点发生故障,就无法访问其ConcurrentMap,并且无法释放从ConcurrentMap引用的Wicket资源。
因此,在群集环境中,您需要对Wicket页面存储进行群集。页面版本可以根据特定策略过期,也可以在相应会话到期时故意删除。
我为生产中的企业Web应用程序中使用的Apache Wicket启用了Web会话和数据存储集群,并且它一直运行良好。我使用的软件是:
这个想法是使用Apache Ignite进行网络会话群集,并且遵循Web Session Clustering的说明非常简单。
我将网络会话聚集后,然后将数据存储(已包含页面存储)放入Ignite分布式数据网格中,同时禁用Wicket应用程序范围缓存(以确保所有数据都是聚集的)。请查看Wicket's page store上的文档,了解如何配置数据存储。
或者,您应该能够使用Wicket HttpSessionDataStore将数据存储放入会话中。会话进行群集时,数据存储会自动进行群集。但是这种方法对我来说并不适合与Apache Ignite兼容。所以我使用自己的IDataStore接口实现,它将数据存储放入Ignite分布式数据网格中。请参阅下面的实施。
import java.util.concurrent.TimeUnit;
import javax.cache.expiry.Duration;
import javax.cache.expiry.TouchedExpiryPolicy;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.Ignition;
import org.apache.ignite.cache.CacheMemoryMode;
import org.apache.ignite.cache.CacheMode;
import org.apache.ignite.cache.eviction.lru.LruEvictionPolicy;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.wicket.pageStore.IDataStore;
import org.apache.wicket.pageStore.memory.IDataStoreEvictionStrategy;
import org.apache.wicket.pageStore.memory.PageTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class IgniteDataStore implements IDataStore {
private static final Logger log = LoggerFactory.getLogger(IgniteDataStore.class);
private final IDataStoreEvictionStrategy evictionStrategy;
private Ignite ignite;
IgniteCache<String, PageTable> igniteCache;
public IgniteDataStore(IDataStoreEvictionStrategy evictionStrategy) {
this.evictionStrategy = evictionStrategy;
CacheConfiguration<String, PageTable> cacheCfg = new CacheConfiguration<String, PageTable>("wicket-data-store");
cacheCfg.setCacheMode(CacheMode.PARTITIONED);
cacheCfg.setBackups(1);
cacheCfg.setMemoryMode(CacheMemoryMode.OFFHEAP_VALUES);
cacheCfg.setOffHeapMaxMemory(2 * 1024L * 1024L * 1024L); // 2 Gigabytes.
cacheCfg.setEvictionPolicy(new LruEvictionPolicy<String, PageTable>(10000));
cacheCfg.setExpiryPolicyFactory(TouchedExpiryPolicy.factoryOf(new Duration(TimeUnit.SECONDS, 14400)));
log.info("IgniteDataStore timeout is set to 14400 seconds.");
ignite = Ignition.ignite();
igniteCache = ignite.getOrCreateCache(cacheCfg);
}
@Override
public synchronized byte[] getData(String sessionId, int id) {
PageTable pageTable = getPageTable(sessionId, false);
byte[] pageAsBytes = null;
if (pageTable != null) {
pageAsBytes = pageTable.getPage(id);
}
return pageAsBytes;
}
@Override
public synchronized void removeData(String sessionId, int id) {
PageTable pageTable = getPageTable(sessionId, false);
if (pageTable != null) {
pageTable.removePage(id);
}
}
@Override
public synchronized void removeData(String sessionId) {
PageTable pageTable = getPageTable(sessionId, false);
if (pageTable != null) {
pageTable.clear();
}
igniteCache.remove(sessionId);
}
@Override
public synchronized void storeData(String sessionId, int id, byte[] data) {
PageTable pageTable = getPageTable(sessionId, true);
if (pageTable != null) {
pageTable.storePage(id, data);
evictionStrategy.evict(pageTable);
igniteCache.put(sessionId, pageTable);
} else {
log.error("Cannot store the data for page with id '{}' in session with id '{}'", id, sessionId);
}
}
@Override
public synchronized void destroy() {
igniteCache.clear();
}
@Override
public boolean isReplicated() {
return true;
}
@Override
public boolean canBeAsynchronous() {
return false;
}
private PageTable getPageTable(String sessionId, boolean create) {
if (igniteCache.containsKey(sessionId)) {
return igniteCache.get(sessionId);
}
if (!create) {
return null;
}
PageTable pageTable = new PageTable();
igniteCache.put(sessionId, pageTable);
return pageTable;
}
}
希望它有所帮助。