apply ehCache on entities from jar - java

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.

Related

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>

Hibernate Ehcache clustering/replication need understanding

I'm currently losing myself in hibernate understanding. Firstly let me explain, my problem.
We decide to add hibernate shared/clustered cache for a product. We got no problem in testing environnements but since this modification is publish in production we got heavy overload on CPU (at least + 1 CPU use), RAM (+1 to 3 Go) and network (bandwidth *2). This even if I disable hibernate L2 cache and query cache.
EDIT : 60 to 65 % of CPU time is spent in thread.sleep in RMI Synchronization calls.
My technical stacks :
Liferay portal CE 6.1.1 GE2
Ehcache 2.3 (not terracota it seems)
Hibernate 3.X (load from liferay dependancies)
Using liferay build service for most part of services which automatically create hibernate stack.
3 nodes in cluster
Now I will describe What I understand at the moment :
Hibernate L2 cache and query cache permit to save database query by using the result in cache to avoid useless queries
I'm using Ehcache RMI replication to shared caches
I'm noob in hibernate ;)
Let see my hibernate - clustering configurations hibernate-clustered.xml:
<!--
Hibernate will use the defaultCache unless custom configurations are defined
below for individual domain objects, collection, queries, etc.
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="600"
overflowToDisk="false"
>
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts=false,replicateUpdatesViaCopy=false"
propertySeparator=","
/>
<bootstrapCacheLoaderFactory class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />
</defaultCache>
<bootstrapCacheLoaderFactory class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />
</cache>
I search & read for more than an entire day and I continue to have doubt (and probably misunderstanding) on my thinking process. I think it's time to ask for some help !
Firstly, I read a lot about replication and clustering. In my mind these concept are not clearly defined. Is these process the same ? What the different, pro and cons?
I read in some places that ehcache (not terracota ehcache) is not compatible with cluster, what the consequences about using it like i do in small cluster, is it scalable?
What do you think about the issue I experiment? How to explain this overhead ?
Let me know if you need more information.
Thanks!

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.

ehcaching in spring mvc

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.

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.

Categories