I would like to use the spring cache abstraction in my distributed web application.
My web application runs on 3 different tomcats with a load balancer.
Now, My problem is how exactly can I #Evict cache in all tomcats when another tomcat preforms an update?
Does spring supports this kind of thing?
Thanks!
If it's EHCache that you've told Spring to use, then EHCache supports replication across multiple cache instances across different physical servers. I've had some success with the RMI Replicated Caching using multicast discovery. Evicting from one cache will automatically replicate across the other caches - and likewise when adding to a cache.
In terms of the Spring config, you'll need to set up the various config elements and beans:
<cache:annotation-driven />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="cacheManager" />
</bean>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:/ehcache.xml"/>
</bean>
The rest of the configuration is done in the ehcache.xml file. An example replicated cache from ehcache.xml may look something like this:
<cache name="example"
maxElementsInMemory="1000"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="0"
timeToLiveSeconds="600">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
properties="bootstrapAsynchronously=true, maximumChunkSizeBytes=5000000"/>
</cache>
And then you'll need to add the replication settings to the ehcache.xml which may look like this:
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.2,
multicastGroupPort=4455, timeToLive=1" />
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=localhost, port=40001, socketTimeoutMillis=2000" />
There are other ways to configure replication in EHCache as described in the documentation but the RMI method described above is relatively simple and has worked well for me.
You can try using Clustered caching, like Hazelcast. Ehcache also support clustered caching through Terracota server.
Let's say, you have 3 application nodes, in a load balanced environment. If you use Hazelcast, each application node will act as an cache node of hazelcast, and together they will give you an abstraction of a single Cache server. So whenever you update an entity in a node, the other nodes will get notify instantly, and update it's cache, if necessary. This way, you also won't have to evict your cached object.
Configuring this is also very easy, looks something likes this
<tcp-ip enabled="true">
<member-list>
<member>machine1</member>
<member>machine2</member>
<member>machine3:5799</member>
</member-list>
</tcp-ip>
For further information, try reading this article here.
Related
Now, I am working with spring mvc and hazel cast.
Everything is working well with my application.
For better performance, we would like to use caching method.
We can't use EhCache because we have 2 application in same server with single database.
So, we shifted to Hazelcast and we already configure and it is working.
We got what we want but the problem is hazelcast looking for other server and other server can join our server in caching process.
That is the problem.
We would like to use hazelcast for only one server and no incoming request and outgoing request to join on multicast.
We only want to share data only in our one server.
But we can't find the right configuration for it.
Our current config is as shown below:
In Java Config
Config config = new Config("instance");
NetworkConfig network = config.getNetworkConfig();
JoinConfig join = network.getJoin();
join.getMulticastConfig().setEnabled(false);
join.getTcpIpConfig().setEnabled(false);
In spring-application-context.xml
<cache:annotation-driven cache-manager="cacheManager" />
<bean id="cacheManager" class="com.hazelcast.spring.cache.HazelcastCacheManager">
<constructor-arg ref="instance"/>
</bean>
<hz:hazelcast id="instance">
<hz:config>
<hz:group name="dev" password="password"/>
</hz:config>
</hz:hazelcast>
Caching is working well with the above codes but it join multiple server.
Please, help me to configure it for only one server, no external join.
Thanks
Multicast is the only discovery mechanism enabled by default, so turning it off should be all that's required to stop this server joining others.
In spring-application-context.xml try
<hz:hazelcast id="instance">
<hz:config>
<hz:group name="dev" password="password"/>
<hz:network port="5701" port-auto-increment="false">
<hz:join>
<hz:multicast enabled="false"/>
</hz:join>
</hz:network>
</hz:config>
</hz:hazelcast>
The Java config looks good too, but I don't see where it's used.
As proof also, change the group name to something other than "dev". "dev" is the default, so if you use a different name temporarily and you see the new name in the logs, you know your configuration is being used.
I have a Spring Web application wich uses EhCache for data caching.
Ehcache holds few Java.Util.Map, that is used through out the application view pages. When a record (say some business JAVA POJO object) is created by the user from front end screen, that record will be inserted into the database and subsequently, Maps held by the EhCache is updated.
Later, we deployed this web application in multiple, that is, 3 tomcat instances. Application is accessible via the Apache HTTP Load Balancer.
Problem we are facing is, when user inserts a record into the database, EhCache is updated only in the application that run on a tomcat instance which got the request. As we have 3 tomcat instances, the application running on other 2 tomcat instances does not have updated EhCache data. This affects the user from viewing the updated data immediately from the screen.
Could anyone please advise how to resolve this issue. How to sync the EhCache data between the Spring web application that run on multiple tomcat instances.
FYKI, this is my first web application in my career and begineer towards the Data Caching concepts.
PLEASE ADVISE ME THE METHODS OF SOLVING THIS ISSUE?
Let me share how I configured the EhCache in my spring web application as simple,
The below is configured in spring-servlet.xml
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache" />
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
p:config-location="classpath:ehcache.xml" p:shared="true"/>
And from the Java business class
public class PortfolioUserDetailsServiceImpl implements PortfolioUserDetailsService {
private Logger logger = LoggerFactory
.getLogger(PortfolioUserDetailsServiceImpl.class);
private UserDao userDao;
#Autowired
private CacheManager cacheManager;
private Ehcache userRoleCache;
#PostConstruct
public void init() {
// Load our widgets cache:
userRoleCache = cacheManager.getEhcache("userRoleCache");
// Create an EHCache Element to hold the widget
Element element = new Element("getAllRoles", userDao.getAllRoles());
// Add the element to the cache
userRoleCache.put(element);
}
#PreDestroy
public void destory() {
logger.info("INVENTORYSERVICEIMPL destroy method called");
}
Here is my ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="PortfolioCache" updateCheck="false">
<defaultCache maxElementsInMemory="10000" eternal="false"
timeToIdleSeconds="0" timeToLiveSeconds="0" overflowToDisk="true"
diskPersistent="false" diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU" />
<cache name="userRoleCache" maxElementsInMemory="100" eternal="false"
timeToIdleSeconds="0" timeToLiveSeconds="0" memoryStoreEvictionPolicy="LFU">
</cache>
<diskStore path="java.io.tmpdir" />
</ehcache>
I think the Best Method is a using "Terracotta Distributed Ehcache"
you can refer to following links :
http://terracotta.org/documentation/enterprise-ehcache/get-started
http://ehcache.org/documentation/2.6/get-started/about-distributed-cache
Your main issue when having multiple application servers is with regards to cache consistency.
When a cache entry is updated in tomcat 1, the update needs to be propagated to the other servers.
If your application domain supports it, consider having small time to leave and cope with a few stale reads,
Or your domain may be mostly read and few writes, in that case a custom cross server eviction system could be considered,
If these are not an option, then indeed you need to go for a clustered cache.
In this case you can indeed go for clustered Ehcache. I would not recommend a replicated cache because it will still expose a window of inconsistency. And of course other caching providers offer clustering options.
As per Infinispan documentation the following settings make up setting infinispan as a L2 Cache provider for Entities
<property name="hibernate.cache.use_second_level_cache" value="true" />
<property name="hibernate.cache.use_query_cache" value="true" />
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.infinispan.InfinispanRegionFactory"/>
Then further one can annotate Entities with #javax.persistence.Cacheable to make them candidate for L2 cache.
My question is how to make this a remote cache ?
Infinispan 2LC implementation for remote cache does not exist. You could maybe configure the embedded caches used for Infinispan 2LC with a remote cache store which talks to one or multiple Infinispan Servers. Please note that this has not been tested and there's no guarantees that it'll work as expected due to the peculiarities and the optimizations done by the embedded Infinispan 2LC implementation.
I am using ehcache for caching in Spring mvc. Consider the case where a controller to provide data a number of times through various methods to connect to the database If we use cache to cache all of the services have the same cache name or not?
example:
#RequestMapping(value="/test",method=RequestMethod.GET)
public String mycontroller(){
...
List1= Service.get(Id);
Info = Service.getInfo(Id);
messages = Service.allMessage(Id);
...
}
and also if the server is reset, cached data will be lost?
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhcacheCacheManager" p:cache-manager="ehcache"/>
<!-- Ehcache library setup -->
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="/WEB-INF/ehcache.xml"/>
and ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<defaultCache
maxElementsInMemory="500" eternal="true" overflowToDisk="false" memoryStoreEvictionPolicy="LFU"/>
<cache name="contactCache" maxElementsInMemory="500" eternal="true" overflowToDisk="false"
memoryStoreEvictionPolicy="LFU"/>
<cache name="cachname"
maxElementsInMemory="100"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"/>
Generally speaking you should use multiple cache names (and thus multiple caches), one or more per Service class.
Also, in most configurations of EhCache, your cached data will be lost upon application restart. However if you consult the documentation, you will find that you can have the cache become persistent across restarts, if desired.
I would suggest you using single cache for storing all services data because cache can store multiple entries of key-value types which serves one of the basic purpose of cache.
It is easy to maintain cache's in case only few number of services needs to be cached. But creating cache's if services are multiple is not preferrable.
im trying to set up a replicated ehcache that can run both over a local network and on the same machine. my current config looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<diskStore path="java.io.tmpdir"/>
<!-- clustering -->
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1, multicastGroupPort=4446, multicastPacketTimeToLive=255"
propertySeparator=","/>
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostname=localhost, port=40001, socketTimeoutMillis=2000"
propertySeparator=","/>
<cache name="demo-cache"
maxEntriesLocalHeap="0"
maxEntriesLocalDisk="0"
eternal="true"
overflowToDisk="true"
maxBytesLocalHeap="10M"
diskPersistent="false"
diskSpoolBufferSizeMB="5"
clearOnFlush="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true, replicateUpdatesViaCopy=true, replicateRemovals=true "/>
</cache>
this works across different machines, but does not work with multiple instances on the same machine.
i know that playing around with the peer listener factory port (40001, 40002 etc) will probbaly work, but im hoping that there's a configuration that will "just work" in both scenarios.
I know this is old topic but I also had similar problem. In such case I used configuration like below:
<cacheManagerPeerListenerFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory" properties="" />
short answer is i cant. the jgroups support in ehcache 2.5 doesnt work and with RMI each node needs its own port.
what i eventually did was create the conf from the xml, parse the port out of the properties field for the peer listener factory and run a loop that creates ServerSockets until it finds a free port (meaning the ServerSocket constructor doesnt throw an exception) and uses that.
its ugly but it works
Try with hostname=localhost y port=0 in cacheManagerPeerListenerFactory. It should work.
If you set up 0 for port, RMICacheManagerPeerListenerFactory will allocate differents random ports intead of the same.