We are trying to use EhCache as a distributed cache in our application.
EhCache instance are embedded in our server and we used a terracota cluster.
All our server (and ehcache) instances successfully connect to this tc.
We successfully inserts, update and get into each of our caches.
But we cannot iterates over any cache.
Maybe we have configured our caches in the wrong way, but it seems that the iterator methods are not yet implemented (in org.ehcache.clustered.client.internal.store.ClusteredStore):
#Override
public Iterator<Cache.Entry<K, ValueHolder<V>>> iterator() {
// TODO: Make appropriate ServerStoreProxy call
throw new UnsupportedOperationException("Implement me");
}
Our cache configuration looks like the following:
<service>
<tc:cluster>
<tc:connection url="terracotta://10.23.69.20:9510/clustered"/>
<tc:server-side-config auto-create="true">
<tc:default-resource from="default-resource"/>
</tc:server-side-config>
</tc:cluster>
</service>
<cache-template name="CacheTemplate">
<resources>
<tc:clustered-dedicated unit="MB">16</tc:clustered-dedicated>
</resources>
<tc:clustered-store consistency="strong"/>
</cache-template>
<cache alias="CacheDaemon" uses-template="CacheTemplate">
<key-type>java.lang.String</key-type>
<value-type>com.server.cache.DaemonInstance</value-type>
</cache>
<cache alias="CacheProperty" uses-template="CacheTemplate">
<key-type>java.lang.String</key-type>
<value-type>java.lang.String</value-type>
</cache>
I don't found any other way, even getting the key list.
So did we made a mistake in the cache configuration ?
Or is it that the EhCache distributed mode is totally incompatible with this method (and so we won't use EhCache).
Related
I have a class that performs some read operations from a service XXX. These read operations will eventually perform DB reads and I want to optimize on those calls by caching the results of each method in the class for a specified custom key per method.
Class a {
public Output1 func1(Arguments1 ...) {
...
}
public Output2 func2(Arguments2 ...) {
...
}
public Output3 func3(Arguments3 ...) {
...
}
public Output4 func4(Arguments4 ...) {
...
}
}
I am thinking of using Spring caching(#Cacheable annotation) for caching results of each of these methods.
However, I want cache invalidation to happen automatically by some mechanism(ttl etc). Is that possible in Spring caching ? I understand that we have a #CacheEvict annotation but I want that eviction to happen automatically.
Any help would be appreciated.
According to the Spring documentation (section 36.8) :
How can I set the TTL/TTI/Eviction policy/XXX feature?
Directly through your cache provider. The cache abstraction is...
well, an abstraction not a cache implementation. The solution you are
using might support various data policies and different topologies
which other solutions do not (take for example the JDK
ConcurrentHashMap) - exposing that in the cache abstraction would be
useless simply because there would no backing support. Such
functionality should be controlled directly through the backing cache,
when configuring it or through its native API.#
This mean that Spring does not directly expose API to set Time To Live , but instead relays on the caching provider implementation to set this. This mean that you need to either set Time to live through the exposed Cache Manager, if the caching provider allows dynamic setup of these attributes. Or alternatively you should configure yourself the cache region that the Spring is using with the #Cacheable annotation.
In order to find the name of the cache region that the #Cacheable is exposing. You can use a JMX console to browse the available cache regions in your application.
If you are using EHCache for example once you know the cache region you can provide xml configuration like this:
<cache name="myCache"
maxEntriesLocalDisk="10000" eternal="false" timeToIdleSeconds="3600"
timeToLiveSeconds="0" memoryStoreEvictionPolicy="LFU">
</cache>
Again I repeat all configuration is Caching provider specific and Spring does not expose an interface when dealing with it.
REMARK: The default cache provider that is configured by Spring if no cache provider defined is ConcurrentHashMap. It does not have support for Time To Live. In order to get this functionality you have to switch to a different cache provider(for example EHCache).
Setup:
play framework 2.4.0
built-in ehcache
java
I have followed the manual at https://www.playframework.com/documentation/2.4.0/JavaCache and to separate caches and use different configs (cache sizes, lifetimes etc) I configure in application.conf:
play.cache.bindCaches = ["mycache1-cache","mycache2-cache"]
Then, to configure them, I created the usual ehcache.xml file
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd" updateCheck="false">
<defaultCache
maxBytesLocalHeap="256000000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
maxElementsOnDisk="10000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
<cache name="mycache1-cache"
maxBytesLocalHeap="256000000"
eternal="false"
timeToIdleSeconds="86400"
timeToLiveSeconds="86400"
overflowToDisk="true"
maxElementsOnDisk="1000000"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="1200"
memoryStoreEvictionPolicy="LRU"
/>
</ehcache>
It works when I only keep the defaultCache, but as soon as I add the custom cache, play throws with:
ProvisionException: Unable to provision, see the following errors: 1)
Error in custom provider, net.sf.ehcache.ObjectExistsException: Cache
mycache1-cache already exists
However, if I only define the cache in ehcache.xml but not in application.conf, play does not know about it and throws.
I have also faced the same issue a month ago and tried to search over internet and below solution that works for me. You can also try to do same.
/** Bind named caches using configuration in ehcache.xml. Define a named cache in ehcache.xml and Ehcache will automatically instantiate the cache at runtime. However,this cache is unknown to the Play cache plugin and is not accessible using {#code #NamedCache}. You must bind a reference to the named cache using {#link CacheModule#bindCustomCache(String)}. Do not add the named cache to {#code play.cache.bindCaches} in configuration. Caches bound in this manner are programmatically added by the Play cache plugin at runtime. The cache plugin will always copy settings from the default cache, limiting the usefulness of named caches. **/
public class CacheModule extends AbstractModule {
#Override
protected void configure() {
bindCustomCache("tenants");
bindCustomCache("user-agent");
bindCustomCache("geo-ip");
bindCustomCache("full-contact");
}
/**
* Bind a named cache that is defined in ehcache.xml.
*
* #param name The name of the cache.
*/
private void bindCustomCache(String name) {
bind(CacheApi.class)
.annotatedWith(new NamedCacheImpl(name))
.toProvider(new Provider<CacheApi>() {
#Inject
CacheManager cacheManager;
#Override
public CacheApi get() {
Cache cache = cacheManager.getCache(name);
if (cache == null) {
throw new RuntimeException("Cache named '" + name + "' must be defined in ehcache.xml");
}
return new DefaultCacheApi(new EhCacheApi(cache));
}
})
.asEagerSingleton();
}
}
I create my named caches in ehcache.xml and just have to add a one line bindCustomCache() to the configure method.
You will also need to set play.cache.createBoundCaches = false in application.conf.
I use ehcache (not replicated or distributed) in my application and as I know it can be accessed only from the same JVM but all the applications in the same JVM (e.g. deployed in a app server) can get values from the cache. Am I right?
What I want is that only my application can get the cache and its values. Is it possible somehow? I checked the XML config file but I haven't found any configuration to control this. Or should I set something when I get the cache from CacheManager?
It is how I get the cache in code:
private static final String LOCAL_CACHE_NAME = "LOCAL_PROTNEUT_STORE";
private Cache getCache() {
// the name of the ehcache should be able to be configured in the general config XML
URL url = getClass().getResource("/protneut-local-ehcache.xml");
CacheManager manager = CacheManager.create(url);
Cache cache = manager.getCache(LOCAL_CACHE_NAME);
return cache;
}
The config file:
<ehcache>
<cache name="LOCAL_PROTNEUT_STORE" maxElementsInMemory="500" eternal="true" memoryStoreEvictionPolicy="LRU" />
</ehcache>
Is it possible to control the access at all?
Thanks for the help!
Regards,
V.
In general applications don't have access to each other as they are loaded with separe classpaths (you can read more about it here) so you shouldn't worry about it.
You would have to make extra effort to make simple cache manager avialable in all applications (like make it available via JNDI or put it in shared lib)
I am trying to get Hazelcast 3.0.2 working with Spring abstraction however it seems the TTL functionality is not working.
I have configured my spring context in the following way
<cache:annotation-driven cache-manager="cacheManager" mode="proxy" proxy-target-class="true" />
<bean id="cacheManager" class="com.hazelcast.spring.cache.HazelcastCacheManager">
<constructor-arg ref="hzInstance" />
</bean>
<hz:hazelcast id="hzInstance">
<hz:config>
<hz:group name="instance" password="password" />
<hz:properties>
<hz:property name="hazelcast.merge.first.run.delay.seconds">5</hz:property>
<hz:property name="hazelcast.merge.next.run.delay.seconds">5</hz:property>
<hz:property name="hazelcast.logging.type">slf4j</hz:property>
<hz:property name="hazelcast.jmx">true</hz:property>
<hz:property name="hazelcast.jmx.detailed">true</hz:property>
</hz:properties>
<hz:network port="8995" port-auto-increment="true">
<hz:join>
<hz:tcp-ip enabled="true">
<hz:interface>10.0.5.5</hz:interface>
<hz:interface>10.0.5.7</hz:interface>
</hz:tcp-ip>
</hz:join>
</hz:network>
<hz:map name="somecache"
backup-count="1"
max-size="0"
eviction-percentage="30"
read-backup-data="false"
time-to-live-seconds="120"
eviction-policy="NONE"
merge-policy="hz.ADD_NEW_ENTRY" />
</hz:config>
</hz:hazelcast>
I then made a simple test class having the following method
#Cacheable("somecache")
public boolean insertDataIntoCache(String data) {
logger.info("Inserting data = '{}' into cache",data);
return true;
}
I also made some method to print some information from every map Hazelcast finds and also the entires inside. Inserting the data and caching seems to work fine however the entry never expires even though I set a TTL of 120 seconds.
When I write the data from the cache it shows me that there is one map called "somecache" and that map has a TTL of 120 seconds but when I loop through the entries, it finds all the ones I inserted with a expirationTime of 0. I am not what is supposed to be the behaviour of hazelcast (maybe a map ttl takes precedence over an entry ttl) but in any case it will just not expire.
Is anybody aware of any issues with 3.0.2 and spring cache? I should also mention that I have other applications in the same application server running an older version of Hazelcast however they have their own separate config and my test application seems to be keeping to itself and not conflicting with anything.
Any input is appreciated.
EDIT 1:
It seems to work if I downgrade to using HZ 2.6.3 so it looks like there is a bug somewhere in hazelcast 3 regarding TTL
I just stumbled on the same thing and it seems that it has been fixed about a month ago: https://github.com/hazelcast/hazelcast/commit/602ce5835a7cc5e495b8e75aa3d4192db34d8b1a#diff-d20dd943d2216ab106807892ead44871
Basically TTL was overridden when you use Hazelcast Spring integration.
I have following method which returns data from cache.
Customer customer = customerDao.findByName("Carl");
It returns just one Customer object with name="Carl". When I make following change:
customer.setName("Ron");
and then I call the method again
Customer customer = customerDao.findByName("Carl");
It returns null. I dont make any persist or update operations and the cached object is directly changed.
I tried to use copyOnRead attribute in ehcache config but it doesnt help.
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<!-- default configuration -->
<defaultCache maxElementsInMemory="1000000"
eternal="true" overflowToDisk="false" copyOnRead="true" />
</ehcache>
Is there any way how to force ehcache to copy objects from cache?
Thank you