ehcaching in spring mvc - java

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.

Related

apply ehCache on entities from jar

I'm using Spring Boot version 2.0 for an application. Here we have used one third-party jar file which contains lots of entities. For improving the performance of an application, we really needs to do second level cache on those jar contained entities. Since we are using Hibernate in our application, we preferred EhCache provider to implement second level cache.
Most of the websites provide examples with annotation #Cacheable that is not usable in our application since we are using jar file entities that contains class files only that is not editable. so, it would really help a lot if someone provides the code for cache those jar file entities using xml and how to configure those entities in ehCacheManager.
Versions
Hibernate v5.x +
ehCache v2.x +
Spring Boot v2.x +
You can use XML Configuration for ehcache, here is a small example
Create a file called ehcache.xml inside src/main/resources
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
monitoring="autodetect" dynamicConfig="true">
<diskStore path="java.io.tmpdir/ehcache" />
<defaultCache maxElementsInMemory="1000" eternal="false"
timeToIdleSeconds="3" timeToLiveSeconds="120" overflowToDisk="true" />
<cache
name="your.entity.in.jar.Entity"
maxElementsInMemory="100" eternal="false" timeToIdleSeconds="3"
timeToLiveSeconds="120" overflowToDisk="false" />
</ehcache>
Visit the ehcache site for more details
https://www.ehcache.org/documentation/2.8/configuration/configuration.html
In case you cannot annotate entities with #Cacheable you can set the SharedCacheMode to ALL
This answer explains how to setup the 2nd level cache and in your case you should change the mode from ENABLE_SELECTIVE to ALL. This other answer should help too.
Finally, I have made it work by enabling the below way.
Persistence.xml:
<persistence>
//few lines
<shared-cache-mode>ALL</shared-cache-mode>
</persistence>
eh-cache.xml:
<defaultCache name="default" maxElementsInMemory="500"
eternal="false" timeToIdleSeconds="6000" timeToLiveSeconds="12000"
overflowToDisk="false" diskPersistent="false"
memoryStoreEvictionPolicy="LRU" />
In Configuration file enabled, ehcache region factory with second level cache as true.
Cache is working fine only on single table queries without joins, without inner queries. Does anyone help me to make it work for join queries and inner queries as well.?
Notes
annotations not possible since we deals with class files
#Cacheable or #Cache on top of collection property on the entity class is not possible since we are dealing with class files (using entity class from jars).
eg:
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "TABLE_NAME" ,schema ="SCHEMA_NAME")
public class SampleEntity {
#Cacheable
#org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) ***//not possible here since we deals with class files***
#OneToMany
private Collection<Bar> bars;
}
Already jpa annotations only used in the entity class files and only cache is missing which we need to configure without disturbing the class files.

EhCache 3.x: for a certain entity class, limit quantity of cached instances, possible?

How can I configure EhCache 3.5 (xml-config, ehcache.xml) to allow only 100 cached instances for:
org.company.Foo? Basically, I have a dozen of entities with separate caching limits wanted.
I've read some sources where they state this is possible, like this one source
This syntax doesn't work for versions 3.x (and I doubt it is the correct config for 2.x too)
<ehcache>
<cache name="org.company.Foo" maxElementsInMemory="100" />
</ehcache>
The official documentation is silent (or I missed it somehow, but scrutinized pretty thoroughly) on this topic for versions 2.x as well as for versions 3.x
If not possible, what is the preferred idiom for configuring EhCache?
Thank you.
P.S. I am using EhCache 3.5 with Hibernate 5.3 and able to monitor the cache state via VisualVM console through MBeans plugin.
The correct config would be like this:
<config
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:jsr107='http://www.ehcache.org/v3/jsr107'
xmlns='http://www.ehcache.org/v3'
xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd">
<service>
<jsr107:defaults enable-management="true" enable-statistics="true"/>
</service>
<cache alias="org.company.Foo">
<heap>1000</heap>
</cache>

How to sync Ehcache data between spring web application running among different tomcat instances?

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.

Spring cache abstraction - distributed environment

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.

running multiple instances of ehcache on the same machine with a single config

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.

Categories