Wicket Cluster Session Storage, Page Storage, Data Storage

I am dealing with custom implementations of wicket session storage, data storage, and page storage. I have cu cluster wicket and make it work in the following situations:

< p>There are 2 nodes in the cluster, node 1 fails, and the user should be able to continue the process without paying attention. These pages are in good condition and have a large number of Ajax requests. Now I store the wicket session in the self on rmi In defining storage, I am trying to extend DiskPageStore. The new challenge is the SessionEntry inner class, which is still held by ConcurrentMap.

My question is: Has anyone done this before? Do you have any suggestions on how to do this?

My suggestion is to forget DiskPageStore and SessionEntry in your case. The ConcurrentMap you mentioned is in Stored locally in the heap. Once one of the nodes fails, its ConcurrentMap cannot be accessed, and Wicket resources referenced from ConcurrentMap cannot be released.

So, in a cluster environment, you Wicket page storage needs to be clustered. The page version can expire according to a specific policy, or it can be deliberately deleted when the corresponding session expires.

I have enabled Apache Wicket used in enterprise web applications in production Web session and data storage cluster, and it has been running well. The software I use is:

> JDK 1.8.0_60
> Apache Tomcat 8.0.33(Tomcat 7 works too)
> Wicket 6.16 (versions 6.22.0 and 7.2.0 should also work)
> Apache Ignite 1.7.0
>Load Balancer: Crossroads
> Ubuntu 14.04.1

This The idea is to use Apache Ignite for network session clustering, and it is very simple to follow the instructions of Web Session Clustering.

Once I cluster the network sessions together, then I put the data store (page store included) in In the Ignite distributed data grid, I also disabled Wicket application-wide caching (to ensure that all data is clustered). Please check the documentation on Wicket’s page store to learn how to configure data storage.

Alternatively, you should be able to use Wicket HttpSessionDataStore to put the data store into the session. When the session is clustered, the data store is automatically clustered. But this method is not suitable for me to be compatible with Apache Ignite. So I use my own IDataStore Interface implementation, it will store data into the Ignite distributed data grid. Please refer to the implementation below.

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 igniteCache;

public IgniteDataSt ore(IDataStoreEvictionStrategy evictionStrategy) {
this.evictionStrategy = evictionStrategy;

CacheConfiguration cacheCfg = new CacheConfiguration("wicket-data-store");< br /> cacheCfg.setCacheMode(CacheMode.PARTITIONED);
cacheCfg.setBackups(1);

cacheCfg.setMemoryMode(CacheMemoryMode.OFFHEAP_VALUES);
cacheCfg.setOffHeapMaxMemory(2 * 1024L * 1024L * 1024L); // 2 Gigabytes.

cacheCfg.setEvictionPolicy(new LruEvictionPolicy(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 i d) {
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(sessio nId, 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;
}
}

I hope I can help you .

I am dealing with custom implementation of wicket session storage, data storage, page storage. I have cu cluster wicket and make it work in the following situations:

There are 2 nodes in the cluster, node 1 fails, and users should be able to continue the process without paying attention. These pages are in good condition and have a large number of ajax requests. Now I store the wicket session In the custom storage on rmi, I am trying to extend DiskPageStore. The new challenge is the SessionEntry inner class, which is still held by ConcurrentMap.

My question is: Has anyone done this before? Do you have any suggestions on how to do this?

My suggestion is to forget DiskPageStore and SessionEntry in your case. The ConcurrentMap you mentioned is saved locally in the heap. Once one of the nodes fails , You cannot access its ConcurrentMap, and you cannot release Wicket resources referenced from ConcurrentMap.

Therefore, in a cluster environment, you need to cluster Wicket page storage. The page version can be based on The specific policy expires and can also be deliberately deleted when the corresponding session expires.

I have enabled web sessions and data storage clusters for Apache Wicket used in enterprise web applications in production, and it has been running Good. The software I use is:

> JDK 1.8.0_60
> Apache Tomcat 8.0.33(Tomcat 7 works too)
> Wicket 6.16(version 6.22.0 and 7.2.0 Should also work)
> Apache Ignite 1.7.0
>Load balancer: Crossroads
> Ubuntu 14.04.1

The idea is to use Apache Ignite for network session clustering, and It’s very simple to follow the instructions of Web Session Clustering.

Once I clustered the web sessions together, then I put the data storage (page storage included) into the Ignite distributed data grid, and at the same time I disabled Wicket application-wide caching (to ensure that all data is clustered). Please check the documentation on Wicket’s page store to learn how to configure data storage.

Alternatively, you should be able to use Wicket HttpSessionDataStore to store data Into the session. When the session is clustered, the data store will automatically be clustered. But this method is not suitable for me to be compatible with Apache Ignite. So I use my own IDataStore interface implementation, which puts the data store into the Ignite distributed Data grid. Please see the implementation below.

import java.util.concurrent.TimeUnit;
import javax.cache.expiry.Duration;
import javax.cache.expiry.TouchedExpiryPolicy;
import org.ap ache.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 igniteCache;

public IgniteDataStore(IDataStoreEvictionStrategy evictionStrategy ) {
this.evictionStrategy = evictionStrategy;

CacheConfiguration cacheCfg = new CacheConfiguration("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(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(sessio nId, 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;< br /> }

@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();
igniteC ache.put(sessionId, pageTable);
return pageTable;
}
}

I hope I can help you.

Leave a Comment

Your email address will not be published.