Eh Cache User Guide
Eh Cache User Guide
Ehcache
v. 2.4
User Guide
......................................................................................................................................
Terracotta, Inc. 2011-03-04
Table of Contents i
Table of Contents
.......................................................................................................................................
1 Table of Contents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . i
2 Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
3 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
4 Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
5 Dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
6 Cache Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
7 Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
8 Storage Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
9 Cache Consistency Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
10 Cache Eviction Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
11 Big Memory:Off-Heap Store . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
12 JDBC Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
13 Code Samples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
14 Class loading and Class Loaders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
15 Tuning Garbage Collection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
16 Cache Decorators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
17 Hibernate Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
18 Web Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
19 Using ColdFusion with Ehcache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
20 Cache Topologies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
21 Distributed Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
22 Replicated Caching With RMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
23 Replicated Caching With JGroups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
24 Replicated Caching With JMS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
25 Shutting Down Ehcache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
26 Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
26 Remote Network replication debugging: RMI Replicated Caches . . . . . 120
26 JMX Management And Monitoring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
26 JTA And Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
26 Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
26 Ehcache Monitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
26 Bulk Loading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
26 CacheManager Event Listeners . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
26 Cache Event Listeners . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
26 Cache Exception Handlers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
26 Cache Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
26 Cache Loaders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
26 Write-through and write-behind caching with CacheWriters . . . . . . . . . . . 172
1 Preface
.......................................................................................................................................
1.1 Preface
This is a book about Ehcache, a widely used open source Java cache. Ehcache has grown in size and
scope since it was introduced in October 2003. As people used it they often noticed it was missing
a feature they wanted. Over time, the features that were repeatedly asked for, and make sense for a
Cache, have been added.
Ehcache is now used for Hibernate caching, data access object caching, security credential caching,
web caching, SOAP and RESTful server caching, application persistence and distributed caching.
In August 2009, Ehcache was acquired by Terracotta, Inc. and has been continously enhanced since
then.
1.1.1 Version
This book is for Ehcache version 2.4.1.
1.1.2 Audience
The intended audience for this book is developers who use ehcache. It should be able to be used to
start from scratch, get up and running quickly, and also be useful for the more complex options.
Ehcache is about performance and load reduction of underlying resources. Another natural audience is
performance specialists.
It is also intended for application and enterprise architects. Some of the features of ehcache, such
as distributed caching and Java EE caching, are alternatives to be considered along with other ways
of solving those problems. This book discusses the trade-offs in Ehcache's approach to help make a
decision about appropriateness of use.
1.1.3 Acknowledgements
Ehcache has had many contributions in the form of forum discussions, feature requests, bug reports,
patches and code commits.
Rather than try and list the many hundreds of people who have contributed to Ehcache in some way it
is better to link to the web site where contributions are acknowledged in the following ways:
• Bug reports and features requests appear in the changes report here:
• Patch contributors generally end up with an author tag in the source they contributed to.
• Team members appear on the team list page here:
2 Introduction
.......................................................................................................................................
2.1 Introduction
Ehcache is a cache library. Before getting into ehcache, it is worth stepping back and thinking about
caching generally.
The Long Tail is itself a vernacular term for a Power Law probability distribution. They don't just
appear in ecommerce, but throughout nature. One form of a Power Law distribution is the Pareto
distribution, commonly know as the 80:20 rule.
This phenomenon is useful for caching. If 20% of objects are used 80% of the time and a way can be
found to reduce the cost of obtaining that 20%, then the system performance will improve.
H H H H
... ... ... ...
The cache hit ratios for the system as a whole are as follows:
Entry
Lifespan Hit Ratio Hit Ratio Hit Ratio Hit Ratio
in Hits 1 Server 2 Servers 3 Servers 4 Servers
2 1/2 0/2 0/2 0/2
4 3/4 2/4 1/4 0/4
10 9/10 8/10 7/10 6/10
20 19/20 18/20 17/20 16/10
50 49/50 48/50 47/20 46/50
The efficiency of a cluster of standalone caches is generally:
(Lifespan in requests - Number of Standalone Caches) / Lifespan in requests
Where the lifespan is large relative to the number of standalone caches, cache efficiency is not much
affected.
However when the lifespan is short, cache efficiency is dramatically affected.
(To solve this problem, Ehcache supports distributed caching, where an entry put in a local cache is
also propagated to other servers in the cluster.)
3 Getting Started
.......................................................................................................................................
3.1.2 Hibernate
4 Dependencies
.......................................................................................................................................
5 Cache Concepts
.......................................................................................................................................
5.1.1 Definitions
• cache-hit: When a data element is requested of the cache and the element exists for the given
key, it is referrred to as a cache hit (or simply 'hit').
• cache-miss: When a data element is requested of the cache and the element does not exist for the
given key, it is referred to as a cache miss (or simply 'miss').
• system-of-record: The core premise of caching assumes that there is a source of truth for the
data. This is often referred to as a system-of-record (SOR). The cache acts as a local copy of
data retrieved from or stored to the system-of-record.
• SOR: See system-of-record.
5.1.2.1 CacheManager
The CacheManager comprises Caches which in turn comprise Elements.
Creation of, access to and removal of caches is controlled by the CacheManager.
5.CacheManager Creation Modes
CacheManager supports two creation modes: singleton and instance.
5.Singleton Mode
Ehcache-1.1 supported only one CacheManager instance which was a singleton. CacheManager can
still be used in this way using the static factory methods.
5.Instance Mode
From ehcache-1.2, CacheManager has constructors which mirror the various static create methods.
This enables multiple CacheManagers to be created and used concurrently. Each CacheManager
requires its own configuration.
If the Caches under management use only the MemoryStore, there are no special considerations.
If Caches use the DiskStore, the diskStore path specified in each CacheManager configuration
should be unique. When a new CacheManager is created, a check is made that there are no other
CacheManagers using the same diskStore path. If there are, a CacheException is thrown. If a
CacheManager is part of a cluster, there will also be listener ports which must be unique.
5.Mixed Singleton and Instance Mode
If an application creates instances of CacheManager using a constructor, and also calls a static create
method, there will exist a singleton instance of CacheManager which will be returned each time the
create method is called together with any other instances created via constructor. The two types will
coexist peacefully.
5.1.2.2 Ehcache
All caches implement the Ehcache interface. A cache has a name and attributes. Each cache contains
Elements.
5.1.2.3 Element
An element is an atomic entry in a cache. It has a key, a value and a record of accesses. Elements are
put into and removed from caches. They can also expire and be removed by the Cache, depending on
the Cache settings.
As of ehcache-1.2 there is an API for Objects in addition to the one for Serializable. Non-serializable
Objects can use all parts of Ehcache except for DiskStore and replication. If an attempt is made to
persist or replicate them they are discarded without error and with a DEBUG level log message.
The APIs are identical except for the return methods from Element. Two new methods on Element:
getObjectValue and getKeyValue are the only API differences between the Serializable and Object
APIs. This makes it very easy to start with caching Objects and then change your Objects to
Seralizable to participate in the extra features when needed. Also a large number of Java classes are
simply not Serializable.
5.1.3.1 cache-aside
Here, application code uses the cache directly.
This means that application code which accesses the system-of-record (SOR) should consult the
cache first, and if the cache contains the data, then return the data directly from the cache, bypassing
the SOR.
Otherwise, the application code must fetch the data from the system-of-record, store the data in the
cache, and then return it.
When data is written, the cache must be updated with the system-of-record.
This results in code that often looks like the following pseudo-code:
public class MyDataAccessClass
{
private final Ehcache cache;
public MyDataAccessClass(Ehcache cache)
{
this.cache = cache;
}
/* read some data, check cache first, otherwise read from sor */
public V readSomeData(K key)
{
Element element;
if ((element = cache.get(key)) != null) {
return element.getValue();
}
// note here you should decide whether your cache
// will cache 'nulls' or not
if (value = readDataFromDataStore(key)) != null) {
cache.put(new Element(key, value));
}
return value;
}
/* write some data, write to sor, then update cache */
public void writeSomeData(K key, V value)
{
writeDataToDataStore(key, value);
cache.put(new Element(key, value);
}
}
5.1.3.2 cache-as-sor
The cache-as-sor pattern implies using the cache as though it were the primary system-of-record
(SOR). The pattern delegates SOR reading and writing activies to the cache, so that application code
is absolved of this responsibility.
To implement the cache-as-sor pattern, use a combination of the following read and write patterns:
• read-through
• write-through or write-behind
Advantages of using the cache-as-sor pattern are:
• less cluttered application code (improved maintainability)
• easily choose between write-through or write-behind strategies on a per-cache basis (use only
configuration)
• allow the cache to solve the "thundering-herd" problem
Disadvantages are:
• less directly visible code-path
5.1.3.3 read-through
The read-through pattern mimics the structure of the cache-aside pattern when reading data. The
difference is that you must implement the CacheEntryFactory interface to instruct the cache
how to read objects on a cache miss, and you must wrap the Ehcache instance with an instance of
SelfPopulatingCache.
Compare the appearance of the read-through pattern code to the code provided in the cache-aside
pattern. (The full example is provided at the end of this document that includes a read-through and
write-through implementation).
5.1.3.4 write-through
The write-through pattern mimics the structure of the cache-aside pattern when writing data. The
difference is that you must implement the CacheWriter interface and configure the cache for write-
through or write-behind.
A write-through cache writes data to the system-of-record in the same thread of execution, therefore
in the common scenario of using a database transaction in context of the thread, the write to the
database is covered by the transaction in scope.
More details (including configuration settings) can be found in the User Guide chapter on Write-
through and Write-behind Caching.
5.1.3.5 write-behind
The write-behind pattern changes the timing of the write to the system-of-record. Rather than writing
to the System of Record in the same thread of execution, write-behind queues the data for write at a
later time.
The consequences of the change from write-through to write-behind are that the data write using
write-behind will occur outside of the scope of the transaction.
This often-times means that a new transaction must be created to commit the data to the system-of-
record that is separate from the main transaction.
More details (including configuration settings) can be found in the User Guide chapter on Write-
through and Write-behind Caching.
*/
private class MyCacheWriter implements CacheWriter
public CacheWriter clone(Ehcache cache) throws CloneNotSupportedException;
{
throw new CloneNotSupportedException();
}
public void init() { }
void dispose() throws CacheException { }
void write(Element element) throws CacheException;
{
writeDataToDataStore(element.getKey(), element.getValue());
}
void writeAll(Collection<Element> elements) throws CacheException
{
for (Element element : elements) {
write(element);
}
}
void delete(CacheEntry entry) throws CacheException
{
deleteDataFromDataStore(element.getKey());
}
void deleteAll(Collection<CacheEntry> entries) throws CacheException
{
for (Element element : elements) {
delete(element);
}
}
}
}
6 Configuration
.......................................................................................................................................
6.1.3.1 net.sf.ehcache.disabled
Setting this System Property to true disables caching in ehcache. If disabled no elements will be
added to a cache. i.e. puts are silently discarded.
e.g. java -Dnet.sf.ehcache.disabled=true in the Java command line.
6.1.3.2 net.sf.ehcache.use.classic.lru
Set this System property to true to use the older LruMemoryStore implementation when LRU is
selected as the eviction policy.
This is provided for ease of migration.
e.g. java -Dnet.sf.ehcache.use.classic.lru=true in the Java command line.
6.1.4 ehcache.xsd
Ehcache configuration files must be comply with the Ehcache XML schema, ehcache.xsd.
It can be downloaded from http://ehcache.org/ehcache.xsd.
6.1.5 ehcache-failsafe.xml
If the CacheManager default constructor or factory method is called, Ehcache looks for a file called
ehcache.xml in the top level of the classpath. Failing that it looks for ehcache-failsafe.xml in the
classpath. ehcache-failsafe.xml is packaged in the Ehcache jar and should always be found.
ehcache-failsafe.xml provides an extremely simple default configuration to enable users to get started
before they create their own ehcache.xml.
If it used Ehcache will emit a warning, reminding the user to set up a proper configuration.
The meaning of the elements and attributes are explained in the section on ehcache.xml.
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
</ehcache>
6.1.6.2 By Configuration
The outer ehcache element takes an updateCheck attribute, which is set to false as in the following
example.
-->
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="false" monitoring="autodetect"
dynamicConfig="true">
7 Storage Options
.......................................................................................................................................
For each get call on the element the number of hits is updated. When a put call is made for a new
element (and assuming that the max limit is reached for the memory store) the element with least
number of hits, the Less Frequently Used element, is evicted.
• First In First Out (FIFO)
Elements are evicted in the same order as they come in. When a put call is made for a new
element (and assuming that the max limit is reached for the memory store) the element that was
placed first (First-In) in the store is the candidate for eviction (First-Out).
For all the eviction policies there are also putQuiet and getQuiet methods which do not
update the last used timestamp.
When there is a get or a getQuiet on an element, it is checked for expiry. If expired, it is
removed and null is returned.
Note that at any point in time there will usually be some expired elements in the cache. Memory
sizing of an application must always take into account the maximum size of each cache. There is
a convenience method which can provide an estimate of the size in bytes of the MemoryStore.
See calculateInMemorySize(). It returns the serialized size of the cache. Do not use this method
in production. It is very slow. It is only meant to provide a rough estimate.
The alternative would have been to have an expiry thread. This is a trade-off between lower
memory use and short locking periods and cpu utilisation. The design is in favour of the latter.
For those concerned with memory use, simply reduce the maxElementsInMemory.
• Only Serializable cache keys and values can be placed in the store, similar to DiskStore.
• Serialization and deserialization take place on putting and getting from the store. This means that
the off-heap store is slower in an absolute sense (around 10 times slower than the MemoryStore),
but this theoretical difference disappears due to two effects:
• the MemoryStore holds the hottest subset of data from the off-heap store, already in
deserialized form
• when the GC involved with larger heaps is taken into account, the off-heap store is faster on
average
7.1.3 DiskStore
The DiskStore provides a disk spooling facility.
7.1.3.4 Storage
7.Files
The disk store creates a data file for each cache on startup called " cache_name.data". If the
DiskStore is configured to be persistent, an index file called " cache name.index" is created on
flushing of the DiskStore either explicitly using Cache.flush or on CacheManager shutdown.
7.Storage Location
Files are created in the directory specified by the diskStore configuration element. The diskStore
configuration for the ehcache-failsafe.xml and bundled sample configuration file ehcache.xml is
"java.io.tmpdir", which causes files to be created in the system's temporary directory.
7. diskStore Element
The diskStore element is has one attribute called path. --- diskStore path="java.io.tmpdir"/ ---
Legal values for the path attibute are legal file system paths. e.g.for Unix
/home/application/cache
The following system properties are also legal, in which case they are translated:
• user.home - User's home directory
• user.dir - User's current working directory
• java.io.tmpdir - Default temp file path
• ehcache.disk.store.dir - A system property you would normally specify on the command line e.g.
java -Dehcache.disk.store.dir=/u01/myapp/diskdir ...
Subdirectories can be specified below the system property e.g.
java.io.tmpdir/one
becomes, on a Unix system,
/tmp/one
7.1.3.5 Expiry
One thread per cache is used to remove expired elements. The optional attribute
diskExpiryThreadIntervalSeconds sets the interval between runs of the expiry thread.
Warning: setting this to a low value is not recommended. It can cause excessive DiskStore locking
and high cpu utilisation. The default value is 120 seconds.
7.1.3.6 Eviction
If the maxElementsOnDisk attribute is set, elements will be evicted from the DiskStore when
it exceeds that amount. The LFU algorithm is used for these evictions. It is not configurable to use
another algorithm.
7.1.3.8 Safety
DiskStores are thread safe.
7.1.3.9 Persistence
DiskStore persistence is controlled by the diskPersistent configuration element. If false or omitted,
DiskStores will not persist between CacheManager restarts. The data file for each cache will be
deleted, if it exists, both on shutdown and startup. No data from a previous instance CacheManager
is available.
If diskPersistent is true, the data file, and an index file, are saved. Cache Elements are available to a
new CacheManager. This CacheManager may be in the same VM instance, or a new one.
The data file is updated continuously during operation of the Disk Store if overflowToDisk is true.
Otherwise it is not updated until either cache.flush() is called or the cache is disposed.
In all cases the index file is only written when dispose is called on the DiskStore. This happens
when the CacheManager is shut down, a Cache is disposed, or the VM is being shut down. It is
recommended that the CacheManager shutdown() method be used. See Virtual Machine Shutdown
Considerations for guidance on how to safely shut the Virtual Machine down.
When a DiskStore is persisted, the following steps take place:
• An attempt is made to read the index file. If it does not exist or cannot be read successfully, due
to disk corruption, upgrade of ehcache, change in JDK version etc, then the data file is deleted
and the DiskStore starts with no Elements in it.
• If the index file is read successfully, the free list and element list are loaded into memory. Once
this is done, the index file contents are removed. This way, if there is a dirty shutdown, when
restarted, Ehcache will delete the dirt index and data files.
• The DiskStore starts. All data is available.
• The expiry thread starts. It will delete Elements which have expired.
These actions favour safety over persistence. Ehcache is a cache, not a database. If a file gets dirty,
all data is deleted. Once started there is further checking for corruption. When a get is done, if the
Element cannot be successfully derserialized, it is deleted, and null is returned. These measures
prevent corrupt and inconsistent data being returned.
• Fragmentation
Expiring an element frees its space on the file. This space is available for reuse by new elements.
The element is also removed from the in-memory index of elements.
• Serialization
Writes to and from the disk use ObjectInputStream and the Java serialization mechanism.
This is not required for the MemoryStore. As a result the DiskStore can never be as fast as the
MemoryStore.
Serialization speed is affected by the size of the objects being serialized and their type. It has
been found in the ElementTest test that:
• The serialization time for a Java object being a large Map of String arrays was 126ms,
where the a serialized size was 349,225 bytes.
• The serialization time for a byte[] was 7ms, where the serialized size was 310,232 bytes
Byte arrays are 20 times faster to serialize. Make use of byte arrays to increase DiskStore
performance.
• RAMFS
One option to speed up disk stores is to use a RAM file system. On some operating systems there
are a plethora of file systems to choose from. For example, the Disk Cache has been successfully
used with Linux' RAMFS file system. This file system simply consists of memory. Linux
presents it as a file system. The Disk Cache treats it like a normal disk - it is just way faster. With
this type of file system, object serialization becomes the limiting factor to performance.
Assuming that 1GB of heap is needed for the rest of the app, they will set their Java config as follows:
java -Xms1G -Xmx1G -XX:maxDirectMemorySize=7G
And their Ehcache config as
<cache
maxElementsInMemory=100
overflowToOffHeap="true"
maxMemoryOffHeap="7G"
... />
Those who want best possible performance for a hot set of data while still reducing overall application
repsonse time variance will likely want a combination of on-heap and off-heap. The heap will be used
for the hot set, the offheap for the rest. So, for example if the hot set is 1M items (or 1GB) of the 7GB
data. They will set their Java config as follows
java -Xms2G -Xmx2G -XX:maxDirectMemorySize=6G
And their Ehcache config as
<cache
maxElementsInMemory=1M
overflowToOffHeap="true"
maxMemoryOffHeap="6G"
...>
This configuration will compare VERY favorably against the alternative of keeping the less-hot set in
a database (100x slower) or caching on local disk (20x slower).
Where pauses are not a problem, the whole data set can be kept on heap:
<cache
maxElementsInMemory=1
overflowToOffHeap="false"
...>
Where latency isn't an issue overflow to disk can be used:
cache maxElementsInMemory=1M overflowToOffDisk="true" ... ---
And when using the Offheap Store, frequently accessed elements can be held in heap in derserialized
form if an Onheap (configured with maxElementsInMemory) store is used
synchronous (by configuration using synchronous=true). The write stays in the Transaction
Buffer until an acknowledgement from the TSA has been received.
• Consistenct hashing is used to identify which stripe in the TSA to write to. The client maintains
knowledge of which replica is the Active server using a election protocol. The write is done to
the Active server. The Active server has knowledge of the tcconfig and knows to replicate the
change to the passive. The write is then written to the Passive. The passive then acknowledges
the write to the Active, the Active then acknowledges the write to the Ehcache node. Once
received, the write is removed from the Transaction Buffer.
2 Before the write is done, a write lock is obtained from the Terracotta Server (storage system).
The write lock is granted only after all read locks have been surrendered.
3 The write is done to an in-process Transaction Buffer. Within the Java process the write is
thread-safe. Any local threads in Ehcache A will have immediate visibility of the change.
4 Once the change has hit the Transaction Buffer which is a LinkedBlockingQueue, a notify
occurs, and the Transaction Buffer initiates sending the write (update) to the Terracotta
Server Array (storage system). This write may be asynchronous (default) or synchronous (by
configuration using synchronous=true).
5 The Terracotta Server is generally configured with multiple replicas forming a Mirror Group.
Within the mirror group there is an Active server, and one or more Passive servers. The write
is to the Active server. The Active server does not acknowledge the write until it has written it
to each of the passive servers in the Mirror Group. It then sends back an acknowledgement to
Ehcache A which then deletes the write from the Transaction Buffer.
6 A read or write request from Ehcache A is immediately available because a read lock is
automatically granted when a write lock has already been acquired. A read or write request in
Ehcache B or C requires the acquisition of a read or write lock respectively which will block
until step 5 has occurred, and in addition, if you have a stale copy locally it is updated first.
When the lock is granted the write is present in all replicas. Because Ehcache also maintains
copies of Elements in-process in potentially each node, if any of Ehcache A, B or C have a copy
they are also updated before Step 5 completes.
Note: This analysis assumes that if the nonstop is being used, it is configured with the default of
Exception, so that on a clusterOffline event no cache operations happen locally. (Nonstop allows
fine-grained tradeoffs to be made in the event of a network partition, including dropping consistency)
Terracotta BigMemory is an add-on to Enterprise Ehcache that permits caches to use an additional
type of memory store outside the object heap.
This off-heap store, which is not subject to Java GC, is 100 times faster than the DiskStore and allows
very large caches to be created (we have tested this up to 350GB).
Because off-heap data is stored in bytes, there are two implications:
• Only Serializable cache keys and values can be placed in the store, similar to DiskStore.
• Serialization and deserialization take place on putting and getting from the store. This means that
the off-heap store is slower in an absolute sense (around 10 times slower than the MemoryStore),
but this theoretical difference disappears due to two effects:
• the MemoryStore holds the hottest subset of data from the off-heap store, already in
deserialized form
• when the GC involved with larger heaps is taken into account, the off-heap store is faster on
average
10.1.1 Configuration
10.overflowToOffHeap
Values may be true or false.
When set to true, enables the cache to utilize off-heap memory storage to improve performance.
Off-heap memory is not subject to Java GC cycles and has a size limit set by the Java property
MaxDirectMemorySize. The default value is false.
10.maxMemoryOffHeap
Sets the amount of off-heap memory available to the cache. This attribute's values are given as
numberk|K|m|M|g|G|t|T for kilobytes (k|K), megabytes (m|M), gigabytes (g|G), or terabytes (t|T).
For example, maxMemoryOffHeap="2g" allots 2 gigabytes to off-heap memory. In effect only if
overflowToOffHeap is true.
The minimum amount that can be allocated is 128MB. There is no maximum.
Note that it is recommended to set maxElementsInMemory to at least 100 elements when using an
off-heap store, otherwise performance will be seriously degraded, and a warning will be logged.
10.Programmatic Configuration
The equivalent cache can be created using the following programmatic configuration:
public Cache createOffHeapCache() {
CacheConfiguration config = new CacheConfiguration("sample-offheap-
cache", 10000)
.overflowToOffHeap(true).maxMemoryOffHeap("1G");
Cache cache = new Cache(config);
manager.addCache(cache);
return cache;
}
10.1.2.1 -XX:+UseLargePages
This is a JVM flag which is meant to improve performance of memory-hungry applications. In
testing, this option gives a 5% speed improvement with a 1Gb off-heap cache.
See http://andrigoss.blogspot.com/2008/02/jvm-performance-tuning.html for a discussion.
10.1.2.2 Increasing the maximum serialized size of an Element that can be stored in the OffHeapStore
Firstly, the MemoryStore and the DiskStore do not have any limits.
By default, the OffHeapStore has a 4MB limit for classes with high quality hashcodes, and 256KB
for those with pathologically bad hashcodes. The built-in classes such as the java.lang.Number
subclasses such as Long, Integer etc and and String have high quality hashcodes.
You can increase the size by setting a system property
net.sf.ehcache.offheap.cache_name.config.idealMaxSegmentSize to the size you require.
e.g. net.sf.ehcache.offheap.com.company.domain.State.config.idealMaxSegmentSize=30M
10.1.2.4 -XX:UseCompressedOops
This setting applies to the HotSpot JVM. It's use should be considered to make the most efficient use
of memory in 64 bit mode. See http://wikis.sun.com/display/HotSpotInternals/CompressedOops for
details.
This chart shows the largest observed full GC duration which occurred during the performance run.
Most non-batch applications have maximum response time SLAs. As can be seen in the chart, as data
sizes grow the full GC gets worse and worse for cache held on heap, whereas off-heap remains a low
constant.
The off-heap store will therefore enable applications with maximum response time SLAs to reliably
meet those SLAs.
10.1.4.2 Latency
This chart shows the maximum observed latency while perfomring either a cache.put() or a
cache.get(). It is very similar to the Full GC chart because the reason the on-heap latencies blow
out is full GCs, where all threads in the test app get frozen.
Once again the off-heap store can be observed to have a flat, low maximum latency, because any full
GCs are tiny, and the cache has excellent concurrency properties.
This chart shows the off-heap mean latency in microseconds. It can be observed to be flat from 2GB
up to 40GB. Further in-house testing shows that the it remains flat up to the limits we have tested to
which is currently 350GB.
Lower latencies are observed at smaller data set sizes because we use a maxElementsInMemory
setting which approximates to 200MB of on-heap store. On-heap, excluding GC effects is faster than
off-heap because there is no deserialization on gets. At lower data sizes there is a higher probability
that the small on-heap store will be hit, which is reflected in the lower average latencies.
10.1.4.3 Throughput
This chart shows the cache operations per second achieved with off-heap. It is the inverse of average
latency and shows much the same thing. Once the effect of the on-heap store becomes marginal,
throughput remains constant, regardless of cache size. Once again we have verified this constancy up
to 350GB.
Note that much larger throughputs than those shown in this chart are achievable. Throughput is
affected by:
10.1.5 Storage
generally manageable up to this size, there is not much point in using the OffHeapStore, as it will
simply be slower.
If you are suffering GC issues with a 32 bit JVM, then OffHeapStore can help. There are a few points
to keep in mind.
• Everything has to fit in 4GB of addressable space. If you allocate 2GB of heap (with -Xmx2g)
then you have at most 2GB left for your off-heap caches.
• Don't expect to be able to use all of the 4GB of addressable space for yourself. The JVM process
requires some of it for its code and shared libraries plus any extra Operating System overhead.
• If you allocate a 3GB heap with -Xmx as well as 2047MB of off-heap memory the virtual
machine certainly won't complain at startup but when it's time to grow the heap you will get an
OutOfMemoryError.
• If you use both -Xms3G and -Xmx3G with 2047MB of off-heap memory the virtual machine
will start but then complain as soon as the OffHeapStore tries to allocate the off-heap buffers.
• Some APIs, such as java.util.zip.ZipFile on Sun 1.5 JVMs, may mmap files in memory. This will
also use up process space and may trigger an OutOfMemoryError.
For these reasons we issue a warning to the log when OffHeapStore is used with 32 bit JVMs.
10.1.10 FAQ
10.1.10.1 The DiskStore Access stripes configuration no longer has effect. Why?
This has been reimplemented for Ehcache Enterprise and will get added back into the core in the
future.
10.1.10.3 Why do I see performance slow down and speed up in a cyclical pattern when I am filling a
cache?
This is due to repartitioning in the OffHeapStore which is normal. Once the cache is fully filled the
performance slow-downs cease.
10.1.10.4 What is the maximum serialized size of an object when using OffHeapStore?
Firstly, the MemoryStore and the DiskStore do not have any limits.
By default, the OffHeapStore has a 4MB limit for classes with high quality hashcodes, and 256KB
for those with pathologically bad hashcodes. The built-in classes such as the java.lang.Number
subclasses such as Long, Integer etc and and String have high quality hashcodes.
You can increase the size by setting the system property
net.sf.ehcache.offheap.cache_name.config.idealMaxSegmentSize to the size you require.
e.g. net.sf.ehcache.offheap.com.company.domain.State.config.idealMaxSegmentSize=30M
11 JDBC Caching
.......................................................................................................................................
It implements a standard pattern of creating an abstract GenericDao implementation which all Dao
implementations will extend.
It also uses Spring's SimpleJdbcTemplate to make the job of accessing the database easier.
Finally, to make Ehcache easier to work with in Spring, it implements a wrapper that holds the cache
name.
11.EhcacheWrapper.java
The wrapper implementation. Holds the name so caches can be named.
public class EhCacheWrapper<K, V> implements CacheWrapper<K, V>
{
private final String cacheName;
private final CacheManager cacheManager;
public EhCacheWrapper(final String cacheName, final CacheManager cacheManager)
{
this.cacheName = cacheName;
this.cacheManager = cacheManager;
}
public void put(final K key, final V value)
{
getCache().put(new Element(key, value));
}
public V get(final K key, CacheEntryAdapter<V> adapter)
{
Element element = getCache().get(key);
if (element != null) {
return (V) element.getValue();
}
return null;
}
public Ehcache getCache()
{
return cacheManager.getEhcache(cacheName);
}
}
11.GenericDao.java
The Generic Dao. It implements most of the work.
public abstract class GenericDao<K, V extends BaseEntity> implements Dao<K, V>
{
11.PetDaoImpl.java
The Pet Dao implementation, really it doesn't need to do anything unless specific methods not
available via GenericDao are cacheable.
public class PetDaoImpl extends GenericDao<Integer, Pet> implements PetDao
{
/** ... **/
}
We need to configure the JdbcTemplate, Datasource, CacheManager, PetDao, and the Pet cache using
the spring configuration file.
11.application.xml
The Spring configuration file.
<!-- datasource and friends -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.FasterLazyConnectionDat
<property name="targetDataSource" ref="dataSourceTarget"/>
</bean>
<bean id="dataSourceTarget" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
12 Code Samples
.......................................................................................................................................
12.2 Recipes
Recipe Description
Web Page and Fragment Caching How to use inluded Servlet Filters to Cache Web Page
and Web Page Fragments
Configure a Grails App for Clustering How to configure a Grails Application for clustered
Hibernate 2nd Level Cache
Data Freshness and Expiration How to maintain cache "freshness" by configuring TTL
and data expiration properly
Enable Terracotta Programmatically How to enable Terracotta support for Ehcache
programmatically
WAN Replication 3 Strategies for configuring WAN replication
Caching Empty Values Why caching empty values can be desirable to deflect
load from the database
Database Read Overload When many readers simultaneously request the
same data element it is called the "Thundering Herd"
problem. How to prevent it in a single jvm or clustered
configuration
Database Write Overload Writing to the Database is a Bottleneck. Configure
write-behind to offload database writes.
Caching methods with Spring Annotations Adding caching to methods using Ehcache
Annotations for Spring project
Cache Wrapper A simple class to make accessing Ehcache easier for
simple use cases
singletonManager.removeCache("sampleCache1");
12.3.3.7 JTA
A cache will automatically participate in the ongoing UserTransaction when configured in
transactionalMode XA. This can be done programmatically:
//Create a CacheManager using defaults
CacheManager manager = CacheManager.create();
//Create a Cache specifying its configuration.
Cache xaCache = new Cache(
new CacheConfiguration("test", 1000)
.overflowToDisk(true)
.eternal(false)
.transactionalMode(CacheConfiguration.TransactionalMode.XA)
.terracotta(new TerracottaConfiguration().clustered(true)));
manager.addCache(xaCache);
Or in your CacheManager's configuration file :
<cache name="xaCache"
maxElementsInMemory="500"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="1"
transactionalMode="xa">
<terracotta clustered="true"/>
</cache>
Please note that XA Transactional caches are supported for standalone Ehcache and also when
clustered with Terracotta, but with the replicating cluster architectures such as RMI|JMS|JGroups as
there is no locking in those architectures.
The Cache can then be used without any special requirement. Changes will only become visible to
others, once the transaction has been committed.
Ehcache cache = cacheManager.getEhcache("xaCache");
transactionManager.begin();
try {
Element e = cache.get(key);
Object result = complexeService.doStuff(element.getValue());
// This put will be rolled back should complexeService.doMoreStuff throw an Except
cache.put(new Element(key, result));
// Any changes to result in that call, will be visible to others when the Transact
complexeService.doMoreStuff(result);
transactionManager.commit();
} catch (Exception e) {
transactionManager.rollback();
}
}
/**
* Gets a fallback <code>ClassLoader</
code> that all classes in ehcache, and extensions,
* should use for classloading. This is used if the context class loader does not work.
* @return the <code>ClassLoaderUtil.class.getClassLoader();</code>
*/
public static ClassLoader getFallbackClassLoader() {
return ClassLoaderUtil.class.getClassLoader();
}
If this does not work for some reason a CacheException is thrown with a detailed error message.
• Thread.currentThread().getContextClassLoader().getResource("/ehcache.xml")
• ConfigurationFactory.class.getResource("/ehcache.xml")
• ConfigurationFactory.class.getResource("/ehcache-failsafe.xml")
Ehcache uses the first configuration found.
Note the use of "/ehcache.xml" which requires that ehcache.xml be placed at the root of the classpath,
i.e. not in any package.
• Thread.currentThread().getContextClassLoader()
• The classloader that defined the CacheManager initially
15 Cache Decorators
.......................................................................................................................................
15.1.1.1 Programmatically
Cache decorators are created as follows:
BlockingCache newBlockingCache = new BlockingCache(cache);
The class must implement Ehcache.
15.1.1.2 By Configuration
Cache decorators can be configured directly in ehcache.xml. The decorators will be
created and added to the CacheManager. It accepts the name of a concrete class that
extends net.sf.ehcache.constructs.CacheDecoratorFactory The properties will be parsed
according to the delimiter (default is comma ',') and passed to the concrete factory's
createDecoratedEhcache(Ehcache cache, Properties properties) method along with
the reference to the owning cache.
It is configured as per the following example:
<cacheDecoratorFactory
class="com.company.SomethingCacheDecoratorFactory"
properties="property1=36 ..." />
Note that from version 2.2, decorators can be configured against the defaultCache. This is very
useful for frameworks like Hibernate that add caches based on the defaultCache.
* <p/>
* This method adds the decorated cache assuming it has a different name. If another
* with the same name already exists, it will throw {@link ObjectExistsException}. F
* cache with another decorated cache having same name, please use
* {@link #replaceCacheWithDecoratedCache(Ehcache, Ehcache)}
* <p/>
* Note that any overridden Ehcache methods by the decorator will take on new behavi
* Casting is only required for new methods that the decorator introduces. For more
* known Gang of Four Decorator pattern.
*
* @param decoratedCache
* @throws ObjectExistsException
* if another cache with the same name already exists.
*/
public void addDecoratedCache(Ehcache decoratedCache) throws ObjectExistsException {
15.1.3.1 BlockingCache
A blocking decorator for an Ehcache, backed by a @link Ehcache.
It allows concurrent read access to elements already in the cache. If the element is null, other reads
will block until an element with the same key is put into the cache.
This is useful for constructing read-through or self-populating caches.
BlockingCache is used by CachingFilter.
15.1.3.2 SelfPopulatingCache
A selfpopulating decorator for Ehcache that creates entries on demand.
Clients of the cache simply call it without needing knowledge of whether the entry exists in the cache.
If null the entry is created.
The cache is designed to be refreshed. Refreshes operate on the backing cache, and do not degrade
performance of get calls.
SelfPopulatingCache extends BlockingCache. Multiple threads attempting to access a null element
will block until the first thread completes. If refresh is being called the threads do not block - they
return the stale data.
This is very useful for engineering highly scalable systems.
16 Hibernate Caching
.......................................................................................................................................
16.1.1 Overview
Ehcache easily integrates with the Hibernate Object/Relational persistence and query service. Gavin
King, the maintainer of Hibernate, is also a committer to the Ehcache project. This ensures Ehcache
will remain a first class cache for Hibernate.
Configuring Ehcache for Hibernate is simple. The basic steps are:
• Download and install Ehcache into your project
• Configure Ehcache as a cache provider in your project's Hibernate configuration.
• Configure second level caching in your project's Hibernate configuration.
• Configure Hibernate caching for each entity, collection, or query you wish to cache.
• Configure ehcache.xml as necessary for each entity, collection, or query configured for caching.
For more information regarding cache configuration in Hibernate see the Hibernate documentation.
16.1.3 Maven
If you are a maven user, you'll need to configure or add the following repository to your build
(pom.xml):
<repository>
<id>terracotta-releases</id>
<url>http://www.terracotta.org/download/reflector/releases</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>false</enabled></snapshots>
</repository>
Then, you will need to configure or add the the ehcache core module defined by the following
dependencies to your build (pom.xml):
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.3.1</version>
</dependency>
If you are configuring Hibernate and Ehcache for Terracotta clustering, you will also need to add the
following dependencies to your build (pom.xml):
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-terracotta</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.terracotta</groupId>
<artifactId>terracotta-toolkit-1.1-runtime</artifactId>
<version>2.0.0</version>
</dependency>
You may also want to turn on the Hibernate query cache. This is done by setting the following
property in your hibernate config:
<property name="hibernate.cache.use_query_cache">true</property>
16.1.6 Optional
The following settings or actions are optional.
dynamic-update="false"
dynamic-insert="false"
>
...
</class>
</hibernate-mapping>
To enable caching, add the following element.
<cache usage="read-write|nonstrict-read-write|read-only" />
e.g.
<hibernate-mapping>
<class
name="com.somecompany.someproject.domain.Country"
table="ut_Countries"
dynamic-update="false"
dynamic-insert="false"
>
<cache usage="read-write" />
...
</class>
</hibernate-mapping>
This can also be achieved using the @Cache annotation, e.g.
@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Country {
...
}
16.read-only
Caches data that is never updated.
16.nonstrict-read-write
Caches data that is sometimes updated without ever locking the cache. If concurrent access to an item
is possible, this concurrency strategy makes no guarantee that the item returned from the cache is the
latest version available in the database. Configure your cache timeout accordingly!
16.read-write
Caches data that is sometimes updated while maintaining the semantics of "read committed" isolation
level. If the database is set to "repeatable read", this concurrency strategy almost maintains the
semantics. Repeatable read isolation is compromised in the case of concurrent writes.
Hibernate uses a specific convention for the naming of caches of Domain Objects, Collections, and
Queries.
16.1.9.2 Hibernate
CacheConcurrencyStrategy read-write, nonstrict-read-write and read-only policies apply to Domain
Objects.
16.1.9.3 Collections
Hibernate creates collection caches named after the fully qualified name of the Domain Object
followed by "." followed by the collection field name.
For example, a Country domain object has a set of advancedSearchFacilities. The Hibernate doclet for
the accessor looks like:
/**
* Returns the advanced search facilities that should appear for this country.
* @hibernate.set cascade="all" inverse="true"
* @hibernate.collection-key column="COUNTRY_ID"
* @hibernate.collection-one-to-
many class="com.wotif.jaguar.domain.AdvancedSearchFacility"
* @hibernate.cache usage="read-write"
*/
public Set getAdvancedSearchFacilities() {
return advancedSearchFacilities;
}
You need an additional cache configured for the set. The ehcache.xml configuration looks like:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<cache name="com.somecompany.someproject.domain.Country"
maxElementsInMemory="50"
eternal="false"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
<cache
name="com.somecompany.someproject.domain.Country.advancedSearchFacilities"
maxElementsInMemory="450"
eternal="false"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
</ehcache>
16.1.9.5 Queries
Hibernate allows the caching of query results using two caches.
"net.sf.hibernate.cache.StandardQueryCache" and "net.sf.hibernate.cache.UpdateTimestampsCache"
in versions 2.1 to 3.1 and "org.hibernate.cache.StandardQueryCache" and
"org.hibernate.cache.UpdateTimestampsCache" in version 3.2. are always used.
16.1.9.6 StandardQueryCache
This cache is used if you use a query cache without setting a name. A typical ehcache.xml
configuration is:
<cache
name="org.hibernate.cache.StandardQueryCache"
maxElementsInMemory="5"
eternal="false"
timeToLiveSeconds="120"
overflowToDisk="true"/>
16.1.9.7 UpdateTimestampsCache
Tracks the timestamps of the most recent updates to particular tables. It is important that the cache
timeout of the underlying cache implementation be set to a higher value than the timeouts of any of
the query caches. In fact, it is recommend that the the underlying cache not be configured for expiry at
all.
A typical ehcache.xml configuration is:
<cache
name="org.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="5000"
eternal="true"
overflowToDisk="true"/>
timeToLiveSeconds="86400"
overflowToDisk="true"/>
16.1.10.2 Examinator
Examinator is our complete application that shows many aspects of caching, all using the Terracotta
Server Array.
Check out from https://svn.terracotta.org/svn/forge/projects/exam/ terracotta_community_login
16.1.11.1 Session.load
Session.load will always try to use the cache.
<cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.jgroups
.JGroupsCacheManagerPeerProviderFactory"
properties="connect=UDP(mcast_addr=231.12.21.132;mcast_port=45566;ip_ttl=32;
mcast_send_buf_size=150000;mcast_recv_buf_size=80000):
PING(timeout=2000;num_initial_members=6):
MERGE2(min_interval=5000;max_interval=10000):
FD_SOCK:VERIFY_SUSPECT(timeout=1500):
pbcast.NAKACK(gc_lag=10;retransmit_timeout=3000):
UNICAST(timeout=5000):
pbcast.STABLE(desired_avg_gossip=20000):
FRAG:
pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;
shun=false;print_local_addr=true)"
propertySeparator="::"
/>
<cache
name="com.somecompany.someproject.domain.Country"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"
properties="replicateAsynchronously=true, replicatePuts=true,
replicateUpdates=true, replicateUpdatesViaCopy=false,
replicateRemovals=true" />
</cache>
</ehcache>
properties="replicateAsynchronously=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=true,
replicateRemovals=true,
asynchronousReplicationIntervalMillis=1000"
propertySeparator=","/>
</cache>
</ehcache>
16.1.15 FAQ
16.1.15.2 What is the relationship between the Hibernate and Ehcache projects?
Gavin King and Greg Luck cooperated to create Ehcache and include it in Hibernate. Since 2009 Greg
Luck has been a committer on the Hibernate project so as to ensure Ehcache remains a first-class 2nd
level cache for Hibernate.
16.1.15.3 Does Ehcache support the new Hibernate 3.3 2nd level caching SPI?
Yes. Ehcache 2.0 supports this new API.
16.1.15.7 Can you use Identity mode with the Terracotta Server Array
You cannot use identity mode clustered cache with Hibernate. If the cache is exclusively used
by Hibernate we will convert identity mode caches to serialization mode. If the cache cannot be
determined to be exclusively used by Hibernate (i.e. generated from a singleton cache manager) then
an exception will be thrown indicating the misconfigured cache. Serialization mode is in any case the
default for Terracotta clustered caches.
17 Web Caching
.......................................................................................................................................
17.1.1 SimplePageCachingFilter
This is a simple caching filter suitable for caching compressable HTTP responses such as HTML,
XML or JSON.
It uses a Singleton CacheManager created with the default factory method. Override to use a different
CacheManager
It is suitable for:
• complete responses i.e. not fragments.
• A content type suitable for gzipping. e.g. text or text/html
For fragments see the SimplePageFragmentCachingFilter.
17.1.2 Keys
Pages are cached based on their key. The key for this cache is the URI followed by the query string.
An example is /admin/SomePage.jsp?id=1234&name=Beagle.
This key technique is suitable for a wide range of uses. It is independent of hostname and port
number, so will work well in situations where there are multiple domains which get the same content,
or where users access based on different port numbers.
A problem can occur with tracking software, where unique ids are inserted into request
query strings. Because each request generates a unique key, there will never be a
cache hit. For these situations it is better to parse the request parameters and override
calculateKey(javax.servlet.http.HttpServletRequest) with an implementation that
takes account of only the significant ones.
17.1.5 Gzipping
Significant network efficiencies, and page loading speedups, can be gained by gzipping responses.
Whether a response can be gzipped depends on:
• Whether the user agent can accept GZIP encoding. This feature is part of HTTP1.1. If a browser
accepts GZIP encoding it will advertise this by including in its HTTP header: All common
browsers except IE 5.2 on Macintosh are capable of accepting gzip encoding. Most search engine
robots do not accept gzip encoding.
• Whether the user agent has advertised its acceptance of gzip encoding. This is on a per request
basis. If they will accept a gzip response to their request they must include the following in the
HTTP request header:
Accept-Encoding: gzip
Responses are automatically gzipped and stored that way in the cache. For requests which do not
accept gzip encoding the page is retrieved from the cache, ungzipped and returned to the user
agent. The ungzipping is high performance.
17.1.7 Init-Params
The following init-params are supported:
• cacheName - the name in ehcache.xml used by the filter.
• blockingTimeoutMillis - the time, in milliseconds, to wait for the filter chain to return with
a response on a cache miss. This is useful to fail fast in the event of an infrastructure failure.
• varyHeader - set to true to set Vary:Accept-Encoding in the response when doing Gzip. This
header is needed to support HTTP proxies however it is off by default.
<init-param>
<param-name>varyHeader</param-name>
<param-value>true</param-value>
</init-param>
17.1.8 Re-entrance
Care should be taken not to define a filter chain such that the same CachingFilter class is
reentered. The CachingFilter uses the BlockingCache. It blocks until the thread which
did a get which results in a null does a put. If reentry happens a second get happens before the
first put. The second get could wait indefinitely. This situation is monitored and if it happens, an
IllegalStateException will be thrown.
17.1.9 SimplePageFragmentCachingFilter
The SimplePageFragmentCachingFilter does everyting that SimplePageCachingFilter does, except
it never gzips, so the fragments can be combined. There is variant of this filter which sets browser
caching headers, because that is only applicable to the entire page.
<param-name>cacheName</param-name>
<param-value>CachedPage2Cache</param-value>
</init-param>
</filter>
<!-- This is a filter chain. They are executed in the order below.
Do not change the order. -->
<filter-mapping>
<filter-name>CachePage1CachingFilter</filter-name>
<url-pattern>/CachedPage.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>SimplePageFragmentCachingFilter</filter-name>
<url-pattern>/include/Footer.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>SimplePageFragmentCachingFilter</filter-name>
<url-pattern>/fragment/CachedFragment.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>SimpleCachingHeadersPageCachingFilter</filter-name>
<url-pattern>/CachedPage2.jsp</url-pattern>
</filter-mapping>
An ehcache.xml configuration file, matching the above would then be:
<Ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../main/config/ehcache.xsd">
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="5"
timeToLiveSeconds="10"
overflowToDisk="true"
/>
<!-- Page and Page Fragment Caches -->
<cache name="CachePage1CachingFilter"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="10000"
timeToLiveSeconds="10000"
overflowToDisk="true">
</cache>
<cache name="CachedPage2Cache"
maxElementsInMemory="10"
eternal="false"
timeToLiveSeconds="3600"
overflowToDisk="true">
</cache>
<cache name="SimplePageFragmentCachingFilter"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="10000"
timeToLiveSeconds="10000"
overflowToDisk="true">
</cache>
<cache name="SimpleCachingHeadersTimeoutPageCachingFilter"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="10000"
timeToLiveSeconds="10000"
overflowToDisk="true">
</cache>
</ehcache>
17.1.11.1 FilterNonReentrantException
Thrown when it is detected that a caching filter's doFilter method is reentered by the same thread.
Reentrant calls will block indefinitely because the first request has not yet unblocked the cache.
Nasty.
17.1.11.2 AlreadyGzippedException
The web package performs gzipping operations. One cause of problems on web browsers is getting
content that is double or triple gzipped. They will either get gobblydeegook or a blank page. This
exception is thrown when a gzip is attempted on already gzipped content.
17.1.11.3 ResponseHeadersNotModifiableException
A gzip encoding header needs to be added for gzipped content. The HttpServletResponse#setHeader()
method is used for that purpose. If the header had already been set, the new value normally overwrites
the previous one. In some cases according to the servlet specification, setHeader silently fails. Two
scenarios where this happens are:
18.1.4 Switching from a local cache to a distributed cache with ColdFusion 9.0.1
1. Download the Terracotta kit. For the quickest results, use Terracotta 3.2.1. Download
it here: http://www.terracotta.org/dl/oss-download-destination?name=terracotta-3.2.1-
installer.jar&bucket=tcdistributions&file=terracotta-3.2.1-installer.jar
Install the kit with 'java -jar terracotta-3.2.1-installer.jar'. We will refer to the directory you installed
it into as TCHOME. Similarly, we will refer to the location of ColdFusion as CFHOME. These
instructions assume you are working with a standalone server install of ColdFusion, if working with a
EAR/WAR install you will need to modify the steps accordingly (file locations may vary, additional
steps may be need to rebuild the EAR/WAR).
Before integrating the distributed cache with ColdFusion, you may want to follow the simple self-
contained tutorial which uses one of the samples in the kit to demonstrate distributed caching: http://
www.terracotta.org/start/distributed-cache-tutorial
2. Copy TCHOME/ehcache/ehcache-terracotta-2.0.0.jar into CFHOME/lib
3. Edit the CFHOME/lib/ehcache.xml to add the necessary two lines of config to turn on distributed
caching
<terracottaConfig url="localhost:9510"/>
<defaultCache
...
>
<terracotta clustered="true" />
</defaultCache>
4. Edit jvm.config (typically in CFHOME/runtime/bin) properties to ensure that coldfusion.classPath
(set with -Dcoldfusion.classPath= in java.args) DOES NOT include any relative paths (ie ../ ) -
ie replace the relative paths with full paths [This is to work around a known issue in ehcache-
terracotta-2.0.0.jar].
5. Start the Terracotta server
$TCHOME/bin/start-tc-server.sh
start-tc-server.bat
Note: In production, you would run your servers on a set of separate machines for fault tolerance and
performance.
6. Start ColdFusion, access your application, and see the distributed cache in action.
7. This is just the tip of the iceberg & you'll probably have lots of questions. Drop us an email to
[email protected] to let us know how you got on, and if you have questions you'd like answers
to.
<cfelse>
<strong>Cache Miss</strong>
<!-- object not found in cache, go ahead create it -->
<cfset myBook = StructNew()>
<cfset a = StructInsert(myBook, "cacheTime", LSTimeFormat(Now(), 'hh:mm:sstt'),
<cfset a = StructInsert(myBook, "title", "EhCache Book", 1)>
<cfset a = StructInsert(myBook, "author", "Greg Luck", 1)>
<cfset a = StructInsert(myBook, "ISBN", "ABCD123456", 1)>
<CFOBJECT type="JAVA" class="net.sf.ehcache.Element" name="myBookElement">
<cfset myBookElement.init("myBook", myBook)>
<cfset cache.put(myBookElement)>
</cfif>
<cfoutput>
Cache time: #myBook["cacheTime"]#<br />
Title: #myBook["title"]#<br />
Author: #myBook["author"]#<br />
ISBN: #myBook["ISBN"]#
</cfoutput>
19 Cache Topologies
.......................................................................................................................................
• Cache Drift--if each application instance maintains its own cache, updates made to one cache
will not appear in the other instances. This also happens to web session data. A distributed or
replicated cache ensures that all of the cache instances are kept in sync with each other.
• Database Bottlenecks--In a single-instance application, a cache effectively shields a database
from the overhead of redundant queries. However, in a distributed application environment,
each instance much load and keep its own cache fresh. The overhead of loading and refreshing
multiple caches leads to database bottlenecks as more application instances are added. A
distributed or replicated cache eliminates the per-instance overhead of loading and refreshing
multiple caches from a database.
• RMI
• JGroups
• JMS
• Cache Server
Each of the is covered in its own chapter.
One solution is to replicate data between the caches to keep them consistent, or coherent. Typical
operations which Applicable operations include:
• put
• update (put which overwrites an existing entry)
• remove
Update supports updateViaCopy or updateViaInvalidate. The latter sends the a remove message out to
the cache cluster, so that other caches remove the Element, thus preserving coherency. It is typically a
lower cost option than a copy.
20 Distributed Caching
.......................................................................................................................................
20.1.1 Architecture
Ehcache distributed with TSA is different to the other distribution mechanisms. They all replicate
data, with 100% of data held in each node. Scaling is thus limited to how much can be comfortably
held in each node. Replication is also not JTA transactional or guaranteed coherent.
With TSA the data is split between an Ehcache node, which is the L1 Cache and the TSA, which
is the L2 Cache. As with the other replication mechanisms the L1 can hold as much data as is
comfortable. All the rest lies in the L2. In Ehcache EX, each CacheManager can have only one
logical TSA (there can be multiple redundant TSAs for HA). In Ehcache FX, the TSAs are striped for
unlimited scale.
Data is held in-process in the Ehcache L1 for rapid access, however the data is also always in the
TSA. So the cache is unaffected by termination of an Ehcache node. When the node comes back up it
reconnects to the TSA L2 and as it uses data fills its local L1. There is thus no notion of a bootstrap as
there is with the other distribution mechanisms.
}
The above example looks for sampleTerracottaCache.
In ehcache.xml, we need to uncomment or add the following line:
<terracottaConfig url="localhost:9510"/>
which tells Ehcache to load the Terracotta server config from localhost port 9510. Note: You must
have a Terracotta 3.1.1 or higher server running locally for this example.
Next we want to enable Terracotta clustering for the cache named sampleTerracottaCache.
Uncomment or add the following in ehcache.xml.
<cache name="sampleTerracottaCache"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="1800"
overflowToDisk="false">
<terracotta/>
</cache>
That's it!
• CacheManager Configuration
• Terracotta Server Configuration
• Enabling Terracotta clustering per cache
• name
an optional name for the CacheManager. The name is optional and primarily used for
documentation or to distinguish Terracotta clustered cache state. With Terracotta clustered
caches, a combination of CacheManager name and cache name uniquely identify a particular
cache store in the Terracotta clustered memory.
The name will show up in the Developer Consoles.
• updateCheck
an optional boolean flag specifying whether this CacheManager should check for new versions
of Ehcache over the Internet. If not specified, updateCheck="true".
• monitoring
an optional setting that determines whether the CacheManager should automatically register the
SampledCacheMBean with the system MBean server. Currently, this monitoring is only useful
when using Terracotta and thus the "autodetect" value will detect the presence of Terracotta and
register the MBean. Other allowed values are "on" and "off". The default is "autodetect".
<Ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="true" monitoring="autodetect">
<logs>app/logs-%i</logs>
</clients>
</tc-config>
</terracottaConfig>
When set to true, clustered caches use Terracotta SYNCHRONOUS WRITE locks.
Asynchronous writes(synchronousWrites="false") maximize performance byallowing clients
to proceed without waiting for a "transaction received" acknowledgement from the server.
Synchronous writes (synchronousWrites="true") maximizes data safety by requiring that a client
receive server acknowledgement of a transaction before that client can proceed. If coherence
mode is disabled using configuration (coherent="false") or through the coherence API, only
asynchronous writes can occur (synchronousWrites="true" is ignored). By default this value is
false (i.e. clustered caches use normal Terracotta WRITE locks).
The simplest way to enable clustering is to add:
<terracotta/>
To indicate the cache should not be clustered (or remove the terracotta element altogether):
<terracotta clustered="false"/>
To indicate the cache should be clustered using identity mode:
<terracotta clustered="true" valueMode="identity"/>
Following is an example Terracotta clustered cache named sampleTerracottaCache.
<cache name="sampleTerracottaCache"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="1800"
overflowToDisk="false">
<terracotta/>
</cache>
be used to materialize the cache values on each get(). This feature has utility in OSGi environments as
well where a common cache service might be shared between bundles
Another subtle issue concerns mutable value objects in a clustered cache. Consider this simple code
which shows a Cache that contains a mutable value type (Foo):
class Foo {
int field;
}
Foo foo = (Foo) c.get("key").getValue();
foo.field++;
// foo instance is never re-put() to the cache
// ...
If the Foo instance is never re-put() to the Cache your local cache is no longer consistent with the
cluster (it is locally modified only). Enabling copyOnRead eliminates this possibility since the only
way to affect cache values is to call mutator methods on the Cache.
It is worth noting that there is a performance penalty to copyOnRead since values are deserialized on
every get().
• String getScheme() Returns a scheme name for the cluster information. Currently
TERRACOTTA is the only scheme supported.
• Collection<ClusterNode> getNodes() Returns information on all the nodes in the
cluster, including ID, hostname, and IP address.
• boolean addTopologyListener(ClusterTopologyListener listener) Adds a
cluster-events listener. Returns true if the listener is already active.
• boolean removeTopologyListener(ClusterTopologyListener) Removes a cluster-
events listener. Returns true if the listener is already inactive.
The interface net.sf.ehcache.cluster.ClusterNode provides methods for obtaining
information on specific cluster nodes.
public interface ClusterNode {
/**
* Get a unique (per cluster) identifier for this node.
*
* @return Unique per cluster identifier
*/
String getId();
/**
* Get the host name of the node
*
* @return Host name of node
*/
String getHostname();
/**
* Get the IP address of the node
*
* @return IP address of node
*/
String getIp();
}
20.1.8.1 Maven
Terracotta has a Maven plugin available which makes this very simple.
20.Setting up for Integration Testing
<pluginRepositories>
<pluginRepository>
<id>terracotta-snapshots</id>
<url>http://www.terracotta.org/download/reflector/maven2</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<plugin>
<groupId>org.terracotta.maven.plugins</groupId>
<artifactId>tc-maven-plugin</artifactId>
<version>1.5.1</version>
<executions>
<execution>
<id>run-integration</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run-integration</goal>
</goals>
</execution>
<execution>
<id>terminate-integration</id>
<phase>post-integration-test</phase>
<goals>
<goal>terminate-integration</goal>
</goals>
</execution>
</executions>
</plugin>
20.Interactive Testing
To start Terracotta:
mvn tc:start
To stop Terracotta:
mvn tc:stop
See http://forge.terracotta.org/releases/projects/tc-maven-plugin/ for a complete reference.
20.1.9 FAQ
20.1.9.1 I get a net.sf.ehcache.CacheException: Terracotta cache classes are not available, you are
missing jar(s) most likely
You need to include the ehcache-terracotta jar in your classpath.
20.1.9.2 When I start ehcache I get "WARN - Can't connect to server[localhost:9510:s1]. Retrying..."
You have not configured a Terracotta server for Ehcache to connect to.
20.1.9.4 I have TTL/TTI not configured or set to 0 (eternal) and have created Elements with a specific TTL
which is being ignored. Why?
There is a high cost in checking individual elements for eviction in the Terracotta
server. To incur that cost and have your Element TTL/TTIs recognised in this case set
ehcache.storageStrategy.dcv2.perElementTTITTL.enabled = true" in system properties.
20.1.9.5 I have set maxElementsOnDisk to a fixed number, but my Terracotta L2 keeps growing.
maxElementsOnDisk was inadvertenly ignored in the new DCV2 implementation. This was logged as
a bug: https://jira.terracotta.org/jira/browse/EHCTERR-1 and is fixed in Terracotta 3.5.
• skips any elements that are in any L1, on the basis that they have been recently used
• evicts any expired elements
• evicts enough non-expired elements to make n.
20.1.9.9 What Stores are available and how are they configured?
The Terracotta server provides an additional store, generally referred to as the Level 2 or L2 store.
The MemoryStore in JVM in the local node is referred to as the L1 Store.
maxElementsInMemory - the maximum number of elements in the local L1 store.
maxElementsOnDisk - is overridden when using Terracotta to provide the L2 size. The L2 size is
effectively the maximum cache size.
overflowToDisk normally controls whether to overflow to the DiskStore. This is ignored when using
Terracotta - the DiskStore is never used. When the store gets full, elements will always overflow to
the Terracotta L2 Store running on the server. The L2 can be further configured with the tcconfig.
20.1.9.14 If updates to a database bypass the Terracotta clustered application, then how is that coherent?
It isn't. This is a problem with using a database as an integration point. Integration via a message
queue, with a Terracotta clustered application acting as a message queue listener and updating the
database avoids this. As would The application receiving a REST or SOAP call and writing to the
database.
AQ can have DB trigger put in a poll. Or AQ can push it up.
20.1.9.16 What are the JMX statistics available in the Terracotta Developer Console?
SampledCache and SampledCacheManager MBeans are made available in the Terracotta Developer
Console.
These are time based gauges, based on once per second measurements. These are different to the JMX
MBeans available through the ManagementService.
20.1.9.19 What happens when an L1 (i.e. an Ehcache node) disconnects from the L2 (i.e. the Terracotta
Server Array)?
• The L1 receives an operations disabled event. Then spawns a thread with a timer waiting for an
operations-enabled event. How long to wait depends on heart beating settings. 65 seconds should
work for the default assuming l2.l1.reconnect is enabled with 5s timeout.
• If in this time there is no Operations-Enabled event, then the L1 can conclude that it is
disconnected and flip a Boolean in the application, which instructs incoming requests to not
access the Terracotta Shared space.
Note that existing threads doing I/O against the TC server (whether for data or for locks) are
stuck.
• If the application desires timeouts then you have to employ a proxy collection - e.g. a wrapper
around a Queue or Map, (in DSO) - where the Queue APIs are proxied through to a thread
pool - so that you can try/join out in "timeout" seconds and throw a timeout to the application.
This is however somewhat messy - since the application threads may receive a timeout, but the
"terracotta transaction" may still make it through to the L2.
Since version 1.2, Ehcache has provided replicated caching using RMI.
An RMI implementation is desirable because:
• a PeerProvider
• a CacheManagerPeerListener
The for each cache that will be replicated, you then need to add one of the RMI
cacheEventListener types to propagate messages.
You can also optionally configure a cache to bootstrap from other caches in the cluster.
multicast datagrams. You can also use it to set up one way replications of data, by having server2
know about server1 but not vice versa.
To set manual peer discovery, specify the properties attribute of
cacheManagerPeerProviderFactory as follows: peerDiscovery=manual rmiUrls=//server:port/
cacheName, ...
The rmiUrls is a list of the cache peers of the server being configured. Do not include the server being
configured in the list.
21.Example
Suppose you have two servers in a cluster. You wish to distribute sampleCache11 and
sampleCache12. Following is the configuration required for each server:
Configuration for server1
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server2:40001/sampleCache11|//server2:40001/sampleCache12"/>
Configuration for server2
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server1:40001/sampleCache11|//server1:40001/sampleCache12"/>
• class - a fully qualified factory class name * properties - comma separated properties having
meaning only to the factory.
Ehcache comes with a built-in RMI-based distribution system. The listener
component is RMICacheManagerPeerListener which is configured using
RMICacheManagerPeerListenerFactory. It is configured as per the following example:
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=localhost, port=40001,
socketTimeoutMillis=2000"/>
Valid properties are:
• hostName (optional) - the hostName of the host the listener is running on. Specify where the host
is multihomed and you want to control the interface over which cluster messages are received.
The hostname is checked for reachability during CacheManager initialisation.
If the hostName is unreachable, the CacheManager will refuse to start and an CacheException
will be thrown indicating connection was refused.
If unspecified, the hostname will use InetAddress.getLocalHost().getHostAddress(),
which corresponds to the default host network interface.
Warning: Explicitly setting this to localhost refers to the local loopback of 127.0.0.1, which is
not network visible and will cause no replications to be received from remote hosts. You should
only use this setting when multiple CacheManagers are on the same machine.
• port (mandatory) - the port the listener listens on.
• socketTimeoutMillis (optional) - the number of seconds client sockets will wait when sending
messages to this listener until they give up. By default this is 2000ms.
• replicatePuts=true | false - whether new elements placed in a cache are replicated to others.
Defaults to true.
• replicateUpdates=true | false - whether new elements which override an element already existing
with the same key are replicated. Defaults to true.
• replicateRemovals=true - whether element removals are replicated. Defaults to true.
• replicateAsynchronously=true | false - whether replications are asyncrhonous (true) or
synchronous (false). Defaults to true.
• replicateUpdatesViaCopy=true | false - whether the new elements are copied to other caches
(true), or whether a remove message is sent. Defaults to true.
To reduce typing if you want default behaviour, which is replicate everything in asynchronous mode,
you can leave off the RMICacheReplicatorFactory properties as per the following example:
<!-- Sample cache named sampleCache4. All missing RMICacheReplicatorFactory properti
default to true -->
<cache name="sampleCache4"
maxElementsInMemory="10"
eternal="true"
overflowToDisk="false"
memoryStoreEvictionPolicy="LFU">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
</cache>
22.1.3 Configuration
There are two things to configure:
• The JGroupsCacheManagerPeerProviderFactory which is done once per CacheManager and
therefore once per ehcache.xml file.
• The JGroupsCacheReplicatorFactory which is added to each cache's configuration.
The main configuration happens in the JGroupsCacheManagerPeerProviderFactory connect
sub-property. A connect property is passed directly to the JGroups channel and therefore all the
protocol stacks and options available in JGroups can be set.
Suppose you have 2 servers host1 and host2, then the configuration is:
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory"
properties="connect=TCP(start_port=7800):
TCPPING(initial_hosts=host1[7800],host2[7800];port_range=10;timeout=3000;
num_initial_members=3;up_thread=true;down_thread=true):
VERIFY_SUSPECT(timeout=1500;down_thread=false;up_thread=false):
pbcast.NAKACK(down_thread=true;up_thread=true;gc_lag=100;retransmit_timeout=3000
pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;
print_local_addr=false;down_thread=true;up_thread=true)"
propertySeparator="::" />
• replicateUpdatesViaCopy=true | false - whether the new elements are copied to other caches
(true), or whether a remove message is sent. Defaults to true.
• asynchronousReplicationIntervalMillis default 1000ms Time between updates when replication
is asynchroneous
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"
properties="replicateAsynchronously=true, replicatePuts=true,
replicateUpdates=true, replicateUpdatesViaCopy=false,
replicateRemovals=true" />
</cache>
If this fails to replicate, try to get the example programs from JGroups to run:
http://www.jgroups.org/javagroupsnew/docs/manual/html/ch02.html#d0e451
and
http://www.jgroups.org/javagroupsnew/docs/manual/html/ch02.html#ItDoesntWork
Once you have figured out the connection string that works in your network for JGroups, you can
directly paste it in the connect property of JGroupsCacheManagerPeerProviderFactory.
• replication between cache nodes using a replication topic, in accordance with ehcache's standard
replication mechanism
• pushing of data directly to cache nodes from external topic publishers, in any language. This is
done by sending the data to the replication topic, where it automatically picked up by the cache
subscribers.
• a JMSCacheLoader, which sends cache load requests to a queue. Either an Ehcache cluster node,
or an external queue receiver can respond.
23.1.1.1 Configuration
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.jms.JMSCacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=true,
replicateRemovals=true,
asynchronousReplicationIntervalMillis=1000"
propertySeparator=","/>
</cache>
"<applause/>\n" +
"</oldjoke>";
TextMessage message = publisherSession.createTextMessage(value);
message.setStringProperty(ACTION_PROPERTY, "PUT");
message.setStringProperty(CACHE_NAME_PROPERTY, "sampleCacheAsync");
message.setStringProperty(MIME_TYPE_PROPERTY, "application/xml");
message.setStringProperty(KEY_PROPERTY, "1234");
Topic topic = publisherSession.createTopic("EhcacheTopicDest");
TopicPublisher publisher = publisherSession.createPublisher(topic);
publisher.send(message);
connection.stop();
Ehcache will create an Element in cache "sampleCacheAsync" with key "1234" and a value of type
MimeTypeByteArray.
On a get from the cache the MimeTypeByteArray will be returned. It is an Ehcache value object from
which a mimeType and byte[] can be retrieved. The mimeType will be "application/xml". The byte[]
will contain the XML String encoded in bytes, using the platform's default charset.
23.PUT arbitrary bytes into an Ehcache JMS Cluster
byte[] bytes = new byte[]{0x34, (byte) 0xe3, (byte) 0x88};
TopicConnection connection = getMQConnection();
connection.start();
TopicSession publisherSession = connection.createTopicSession(false,
Session.AUTO_ACKNOWLEDGE);
BytesMessage message = publisherSession.createBytesMessage();
message.writeBytes(bytes);
message.setStringProperty(ACTION_PROPERTY, "PUT");
message.setStringProperty(CACHE_NAME_PROPERTY, "sampleCacheAsync");
message.setStringProperty(MIME_TYPE_PROPERTY, "application/octet-stream");
message.setStringProperty(KEY_PROPERTY, "1234");
Topic topic = publisherSession.createTopic("EhcacheTopicDest");
TopicPublisher publisher = publisherSession.createPublisher(topic);
publisher.send(message);
Ehcache will create an Element in cache "sampleCacheAsync" with key "1234" in and a value of type
MimeTypeByteArray.
On a get from the cache the MimeTypeByteArray will be returned. It is an Ehcache value object from
which a mimeType and byte[] can be retrieved. The mimeType will be "application/octet-stream".
The byte[] will contain the original bytes.
23.REMOVE
TopicConnection connection = getMQConnection();
connection.start();
TopicSession publisherSession = connection.createTopicSession(false, Session.AUTO_ACKNOW
ObjectMessage message = publisherSession.createObjectMessage();
message.setStringProperty(ACTION_PROPERTY, "REMOVE");
message.setStringProperty(CACHE_NAME_PROPERTY, "sampleCacheAsync");
message.setStringProperty(KEY_PROPERTY, "1234");
Topic topic = publisherSession.createTopic("EhcacheTopicDest");
TopicPublisher publisher = publisherSession.createPublisher(topic);
publisher.send(message);
Ehcache will remove the Element with key "1234" from cache "sampleCacheAsync" from the cluster.
23.REMOVE_ALL
TopicConnection connection = getMQConnection();
connection.start();
TopicSession publisherSession = connection.createTopicSession(false,
Session.AUTO_ACKNOWLEDGE);
ObjectMessage message = publisherSession.createObjectMessage();
message.setStringProperty(ACTION_PROPERTY, "REMOVE_ALL");
message.setStringProperty(CACHE_NAME_PROPERTY, "sampleCacheAsync");
Topic topic = publisherSession.createTopic("EhcacheTopicDest");
TopicPublisher publisher = publisherSession.createPublisher(topic);
publisher.send(message);
connection.stop();
Ehcache will remove all Elements from cache "sampleCacheAsync" in the cluster.
• initialContextFactoryName (mandatory) - the name of the factory used to create the message
queue initial context.
• providerURL (mandatory) - the JNDI configuration information for the service provider to use.
• getQueueConnectionFactoryBindingName (mandatory) - the JNDI binding name for the
QueueConnectionFactory
• getQueueBindingName (mandatory) - the JNDI binding name for the queue name used to do
make requests.
properties="initialContextFactoryName=com.sun.jndi.fscontext.RefFSContextFactory
providerURL=file:///tmp,
replicationTopicConnectionFactoryBindingName=MyConnectionFactory,
replicationTopicBindingName=ehcache,
getQueueConnectionFactoryBindingName=queueConnectionFactory,
getQueueBindingName=ehcacheGetQueue,
timeoutMillis=10000,
userName=test,
password=test"/>
</cache>
23.1.4.2 Active MQ
This open source message queue is tested in integration tests. It works perfectly other than having a
problem with temporary reply queues which prevents the use of JMSCacheLoader. JMSCacheLoader
is not used during replication.
23.1.4.3 Oracle AQ
Versions up to an including 0.4 do not work, due to Oracle not supporting the unified API (send) for
topics.
• http://www.nabble.com/Memory-Leak-Using-Temporary-Queues-td11218217.html#a11218217
• http://issues.apache.org/activemq/browse/AMQ-1255
The JMSCacheLoader uses temporary reply queues when loading. The Active MQ issue is
readily reproduced in Ehcache integration testing. Accordingly, use of the JMSCacheLoader with
ActiveMQ is not recommended. Open MQ tests fine.
Active MQ works fine for replication.
24.1.1 ServletContextListener
Ehcache proivdes a ServletContextListener that shutsdown CacheManager. Use this when you want to
shutdown Ehcache automatically when the web application is shutdown.
To receive notification events, this class must be configured in the deployment descriptor for the web
application.
To do so, add the following to web.xml in your web application:
<listener>
<listener-class>net.sf.ehcache.constructs.web.ShutdownListener</
listener-class>
</listener>
24.1.2.3 When a shutdown hook will run, and when it will not
The shutdown hook runs when:
• a program exists normally. e.g. System.exit() is called, or the last non-daemon thread exits
• the Virtual Machine is terminated. e.g. CTRL-C. This corresponds to kill -SIGTERM pid or
kill -15 pid on Unix systems.
The shutdown hook will not run when:
25 Logging
.......................................................................................................................................
25.1 Logging
26.1.1 Introduction
The ehcache-1.x-remote-debugger.jar} can be used to debug replicated cache operations. When
started with the same configuration as the cluster, it will join the cluster and then report cluster events
for the cache of interest. By providing a window into the cluster it can help to identify the cause of
cluster problems.
26.1.2 Packaging
From version 1.5 it is packaged in its own distribution tarball along with a maven module.
It is provided as an executable jar.
26.1.3 Limitations
This version of the debugger has been tested only with the default RMI based replication.
26.1.4 Usage
It is invoked as follows:
java -classpath [add your application jars here]
-jar ehcache-debugger-1.5.0.jar ehcache.xml sampleCache1
path_to_ehcache.xml [cacheToMonitor]
Note: Add to the classpath any libraries your project uses in addition to these above, otherwise RMI
will attempt to load them remotely which requires specific security policy settings that surprise most
people.
It takes one or two arguments:
• the first argument, which is mandatory, is the Ehcache configuration file e.g. app/config/
ehcache.xml. This file should be configured to allow Ehcache to joing the cluster. Using one of
the existing ehcache.xml files from the other nodes normally is sufficient.
• the second argument, which is optional, is the name of the cache e.g. distributedCache1
If only the first argument is passed, it will print our a list of caches with replication configured
from the configuration file, which are then available for monitoring.
If the second argument is also provided, the debugger will monitor cache operations received for
the given cache.
This is done by registering a CacheEventListener which prints out each operation.
26.1.4.1 Output
When monitoring a cache it prints a list of caches with replication configured, prints notifications as
they happen, and periodically prints the cache name, size and total events received. See sample output
below which is produced when the RemoteDebuggerTest is run.
Caches with replication configured which are available for monitoring are:
sampleCache19 sampleCache20 sampleCache26 sampleCache42 sampleCache33
sampleCache51 sampleCache40 sampleCache32 sampleCache18 sampleCache25
Only Serializable attributes are available remotely. The following Ehcache MBean attributes are
available remotely:
ManagementService
There is only one method, ManagementService.registerMBeans which is used to initiate JMX
registration of an Ehcache CacheManager's instrumented MBeans.
The ManagementService is a CacheManagerEventListener and is therefore notified of any
new Caches added or disposed and updates the MBeanServer appropriately.
Once initiated the MBeans remain registered in the MBeanServer until the CacheManager shuts
down, at which time the MBeans are deregistered. This behaviour ensures correct behaviour in
application servers where applications are deployed and undeployed.
/**
* This method causes the selected monitoring options to be be registered
* with the provided MBeanServer for caches in the given CacheManager.
* <p/>
* While registering the CacheManager enables traversal to all of the other
* items,
* this requires programmatic traversal. The other options allow entry points closer
* to an item of interest and are more accessible from JMX management tools like JConsol
* Moreover CacheManager and Cache are not serializable, so remote monitoring is not
* possible * for CacheManager or Cache, while CacheStatistics and CacheConfiguration ar
* Finally * CacheManager and Cache enable management operations to be performed.
* <p/>
* Once monitoring is enabled caches will automatically added and removed from the
* MBeanServer * as they are added and disposed of from the CacheManager. When the
* CacheManager itself * shutsdown all registered MBeans will be unregistered.
*
* @param cacheManager the CacheManager to listen to
* @param mBeanServer the MBeanServer to register MBeans to
* @param registerCacheManager Whether to register the CacheManager MBean
* @param registerCaches Whether to register the Cache MBeans
* @param registerCacheConfigurations Whether to register the CacheConfiguration MBeans
* @param registerCacheStatistics Whether to register the CacheStatistics MBeans
*/
public static void registerMBeans(
net.sf.ehcache.CacheManager cacheManager,
MBeanServer mBeanServer,
boolean registerCacheManager,
boolean registerCaches,
boolean registerCacheConfigurations,
boolean registerCacheStatistics) throws CacheException {
You can see cache hit/miss/put rates, change config element values dynamically -- like
maxElementInMemory, TTI, TTL, enable/disable statistics collection etc and various other things.
Please look into the specific interface for more details.
27.1.10 Performance
Collection of cache statistics is not entirely free of overhead. In production systems where monitoring
is not required statistics can be disabled. This can be done either programatically by calling
setStatisticsEnabled(false) on the cache instance, or in configuration by setting the statistics="false"
attribute of the relevant cache configuration element.
From Ehcache 2.1.0 statistics are off by default.
28.1.1 Introduction
Transactions are supported in versions of Ehcache 2.0 and higher.
The 2.3.x or lower releases only support XA. However since ehcache 2.4 support for both Global
Transactions with xa_strict and xa modes, and Local Transactions with local mode has been
added.
• All mutating changes to the cache are transactional including put, remove, putWithWriter,
removeWithWriter and removeAll.
• Mutating changes are not visible to other transactions in the local JVM or across the cluster until
COMMIT has been called.
• Until then, read such as by cache.get(...) by other transactions will return the old copy.
Reads do not block.
28.1.2.1 Transactional modes are a powerful extension of Ehcache allowing you to perform atomic
operations on your caches and potentially other data stores, eg: to keep your cache in sync with your
database.
• local When you want your changes across multiple caches to be performed atomically.
Use this mode when you need to update your caches atomically, ie: have all your changes be
committed or rolled back using a straight simple API. This mode is most useful when a cache
contains data calculated out of other cached data.
• xa
Use this mode when you cache data from other data stores (eg: DBMS, JMS) and want to do it in
an atomic way under the control of the JTA API but don't want to pay the price of full two-phase
commit. In this mode, your cached data can get out of sync with the other resources participating
in the transactions in case of a crash so only use it if you can afford to live with stale data for a
brief period of time.
• xa_strict
Same as xa but use it only if you need strict XA disaster recovery guarantees. In this mode, the
cached data can never get out of sync with the other resources participating in the transactions,
even in case of a crash but you pay a high price in performance to get that extra safety.
28.1.3 Requirements
The objects you are going to store in your transactional cache must:
• implement java.io.Serializable
This is required to store cached objects when the cache is clustered with Terracotta but it's also
required by the copy on read / copy on write mechanism used to implement isolation.
• override equals and hashcode
Those must be overridden as the transactional stores rely on element value comparison, see:
ElementValueComparator and the elementValueComparator configuration setting.
28.1.4 Configuration
Transactions are enabled on a cache by cache basis with the transactionalMode cache attribute.
The allowed values are:
• xa_strict
• xa
• local
• off
The default value is off.
Enabling a cache for xa_strict transactions is shown in the following example:
<cache name="xaCache"
maxElementsInMemory="500"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="1"
transactionalMode="xa_strict">
</cache>
28.1.5.1 Implementation
Global transactions support is implemented at the Store level, through XATransactionStore
and JtaLocalTransactionStore. The former actually decorates the underlying MemoryStore
implementation, augmenting it with transaction isolation and two-phase commit support through an
XAResouce implementation. The latter decorates a LocalTransactionStore-decorated cache to make it
controllable by the standard JTA API instead of the proprietary TransactionController API.
During its initialization, the Cache will lookup the TransactionManager using
the provided TransactionManagerLookup implementation. Then, using the
TransactionManagerLookup.register(XAResouce), the newly created XAResource will be
registered.
The store is automatically configured to copy every Element read from the cache or written to it.
Cache is copy-on-read and copy-on-write.
28.1.6.1 Recovery
At any time after something went wrong, an XAResource may be asked to recover. Data that has
been prepared may either be committed or rolled back during recovery. In accordance with XA, data
that has not yet been prepared is discarded.
The recovery guarantee differs depending on the xa mode.
28.xa Mode
With xa, the cache doesn't get registered as an XAResource with the transaction manager but merely
can follow the flow of a JTA transaction by registering a JTA Synchronization. The cache can end up
inconsistent with the other resources if there is a JVM crash in the mutating node.
In this mode, some inconsistency may occur between a cache and other XA resources (such as
databases) after a crash. However, the cache's data remains consistent because the transaction is still
fully atomic on the cache itself.
28.xa_strict Mode
If xa_strict is used the cache will always respond to the TransactionManager's recover calls with
the list of prepared XIDs of failed transactions. Those transaction branches can then be committed or
rolled back by the transaction manager. This is the standard XA mechanism in strict compliance with
the JTA specification.
28.1.7.3 Examinator
Examinator is our complete application that shows many aspects of caching in one web based Exam
application, all using the Terracotta Server Array.
Check out from http://svn.terracotta.org/svn/forge/projects/exam/
Local Transactions has it's own exceptions that can be thrown, which are all subclasses of
CacheException. They are:
28.1.9.1 Configuration
Local transactions are configured as follows:
<cache name="sampleCache"
...
transactionalMode="local"
</cache>
28.1.10 Performance
• off - no overhead
• xa_strict - 20 times slower
• xa - 3 times slower
• local - 3 times slower
The relative read performance is:
• off - no overhead
• xa_strict - 20 times slower
• xa - 30% slower
• local - 30% slower
Accordingly, xa_strict should only be used where it's full guarantees are required, othewise one of the
other modes should be used.
28.1.11 FAQ
29 Search
.......................................................................................................................................
29.1 Search
29.1.3.1 By Configuration
Caches are made searchable by adding a <searchable/> tag to the ehcachel.xml.
<cache name="cache2" maxElementsInMemory="10000" eternal="true" overflowToDisk="false">
<searchable/>
</cache>
This configuration will scan keys and vales and if they are of supported search types, add them as
attributes called "key" and "value" respectively.
Lots of times keys or values will not be directly searchable and instead you will need to extract
searchable attributes out of them. The following example shows this more typical case. Attribute
Extractors are explained in more detail in the following section.
<cache name="cache3" maxElementsInMemory="10000" eternal="true" overflowToDisk="false">
<searchable>
<searchAttribute name="age" class="net.sf.ehcache.search.TestAttributeExtractor"
>
<searchAttribute name="gender" expression="value.getGender()"/>
</searchable>
</cache>
29.1.3.2 Programmatically
You can create new SearchAttributes and add them to your cache configuration, and then create
your cache.
This example shows how:
CacheConfiguration cacheConfig = new CacheConfiguration("test", -1).eternal(true);
// Create attributes on the stuff we want to be able to search on.
// You can use an expression for getting at the value to be indexed on a cache or you ca
// code your own.
// Expression
SearchAttribute sa = new SearchAttribute();
sa.setExpression("value.getAge()");
sa.setName("age");
cacheConfig.addSearchAttribute(sa);
// Coding your own
sa = new SearchAttribute();
sa.className("org.sharrissf.sample.EhcacheSearchPlaying
$NameAttributeExtractor");
sa.setName("name");
cacheConfig.addSearchAttribute(sa);
sa = new SearchAttribute();
sa.setExpression("value.getGender()");
sa.setName("gender");
cacheConfig.addSearchAttribute(sa);
sa = new SearchAttribute();
sa.setExpression("value.getAddress().getState()");
sa.setName("state");
cacheConfig.addSearchAttribute(sa);
Cache test = new Cache(cacheConfig);
cacheManager.add(test);
• Boolean
• Byte
• Character
• Double
• Float
• Integer
• Long
• Short
• String
• java.util.Date
• java.sql.Date
• Enum
If an attribute cannot be extracted due to not being found or of being the wrong type an
AttributeExtractorException is thrown during the put() in the clustered implementation and on
search execution in the standalone implementation
If a keys and/or value is of a supported search type, they are added automatically as attributes with the
names "key" amd "value".
These well-known attributes have convenience constant attributes made available on the Query class.
So, for example, the attribute for "key" may be referenced in a query by Query.KEY. For even greater
readability it is recommended to statically import so that in this example you would just use KEY.
29.1.4.2 ReflectionAttributeExtractor
The ReflectionAttributeExtractor is a built-in search attribute extractor which uses JavaBean
conventions and also understands a simple form of expression.
Where a JavaBean property is available and it is of a searchable type, it can be simply declared using:
<cache>
<searchable>
<searchAttribute name="age"/>
</searchable>
</cache>
Finally, when things get more complicated, we have an expression language using method/value
dotted expression chains.
The expression chain must start with one of either "key", "value", or "element". From the starting
object a chain of either method calls or field names follows. Method calls and field names can be
freely mixed in the chain.
Some more examples:
<cache>
<searchable>
<searchAttribute name="age" expression="value.person.getAge()"/>
</searchable>
</cache>
<cache>
<searchable>
<searchAttribute name="name" expression="element.toString()"/>
</searchable>
</cache>
The method and field name portions of the expression are case sensitive.
29.1.5.2 Expressions
The Query to be searched for is built up using Expressions.
Expressions include logical operators such as and and or. It also includes comparison operators such
as ge (>=), between and like
addCriteria(...) is used to add a clause to a query. Adding a further clause automatically ands
the clauses
query = cache.createQuery().includeKeys().addCriteria(age.le(65)).add(gender.eq("male"))
Both logical and comparison operators implement the Criteria interface.
To add a criteria with a different logical operator, you need to explicitly nest it within a new logical
operator Criteria Object.
e.g. to check for age = 35 or gender = female, do the following:
query.addCriteria(new Or(age.eq(35),
gender.eq(Gender.FEMALE))
);
More complex compound expressions can be further created with extra nesting.
See the Expression JavaDoc for a complete list.
If a returns a very large result, you can get it in chunks with Results.range().
29.1.6.1 Results
Either all results can be returned using results.all() to get the all in one chunk, or a range of
results using results.range(int start, int count) to achieve paging.
When you are done with the results, it is recommended to call discard(). This allows resources to
be freed. In the distributed implementation with Terracotta, resources may be used to hold results for
paging or return.
To determine what was returned by the query use one of the interrogation methods on Results:
• hasKeys()
• hasValues()
• hasAttributes()
• hasAggregators()
29.1.6.2 Result
Each Element in the cache found with a query will be represented as a Result object. So if a query
finds 350 elements there will be 350 Result objects. An exception to this if no keys or attributes are
included but aggregators are -- In this case there will be exactly one Result present
A Result object can contain:
• the Element key - when includeKeys() was added to the query
• the Element value - when includeValues() was added to the query
• predefined attribute(s) extracted from an Element value - when includeAttribute(...) was
added to the query. To access an attribute from Result, use getAttribute(Attribute<T>
attribute.
• aggregator results
Aggregator results are summaries computed for the search. They are available
Result.getAggregatorResults which returns a list of Aggregators in the same order in which
they were used in the Query.
29.1.6.3 Aggregators
Aggregators are added with query.includeAggregator(<attribute>.<aggregator>).
E.g. to find the sum of the age attribute:
query.includeAggregator(age.sum());
See the Aggregators JavaDoc for a complete list.
• includeValues returns values. Under the covers the index contains a server value reference.
The reference gets returned with the search and Terracotta supplies the matching value. Because
the cache is always updated before the search index it is possible that a value reference may refer
to a value that has been removed from the cache. If this happens the value will be null but the
key and attributes which were supplied by the now stale cache index will be non-null. Because
values in Ehcache are also allowed to be null, you cannot tell whether your value is null because
it has been removed from the cache since the index was last updated or because it is a null value.
29.1.9.3 Recommendations
Because the state of the cache can change between search executions it is recommended to add all of
the Aggregators you want for a query at once so that the returned aggregators are consistent.
Use null guards when accessing a cache with a key returned from a search.
29.1.10 Implementations
• limiting the results with maxResults or using the paging API Results.range(int start,
int length)
• Only including the data you need. Specifically only use includeKeys() and/or
includeAttribute() if those values are actually required for your application logic
• using a built-in Aggregator function when you only need a summary statistic
includeValues rates a special mention. Once a query requiring values is executed we push the
values from the server to the Ehcache CacheManager which requested it in batches for network
efficiency. This is done ahead as soon as possible reducing the risk that Result.getValue()
might have to wait for data over the network.
30 Ehcache Monitor
.......................................................................................................................................
It is recommended to place the Monitor on an Operations server separate to production. The Monitor
acts as an aggregation point for access by end users and for scripted connection from Operations tools
for data feeds and set up of alerts.
30.1.2.1 Probe
To include the probe in your Ehcache application, you need to perform two steps:
1 Add the ehcache-probe- version.jar to your application classpath (or war file). Do this in the
same way you added the core ehcache jar to your application.
If you are Maven based, the probe module is in the Terracotta public repository for easy
integration.
<repository>
<id>terracotta-releases</id>
<url>http://www.terracotta.org/download/reflector/
releases</url>
</repository>
<dependency>
<groupId>org.terracotta</groupId>
<artifactId>ehcache-probe</artifactId>
<version>[version]</version>
</dependency>
2 Configure Ehcache to communicate with the probe by specifying the class name of the probe, the
address (or hostname), the port that the monitor will be running on and whether to do memory
measurement. This is done by adding the following to ehcache.xml:
<cacheManagerPeerListenerFactory
class="org.terracotta.ehcachedx.monitor.probe.ProbePeerListenerFactory"
properties="monitorAddress=localhost, monitorPort=9889, memoryMeasurement=tr
3 Include required SLF4J logging jars.
Ehcache 1.7.1 and above require SLF4J. Earlier versions used commons logging. The probe,
like all new Ehcache modules, uses SLF4J, which is becoming a new standard in open source
projects.
If you are using Ehcache 1.5 to 1.7.0, you will need to add slf4j-api and one concrete logger.
If you are using Ehcache 1.7.1 and above you should not need to do anything because you will
already be using slf4j-api and one concrete logger.
More information on SLF4J is available from http://www.slf4j.org.
4 Ensure that statistics capture in each cache is turned on for the probe to gather statistics.
Statistics were turned off by default from Ehcache 2.1 onwards.
<cache name="sampleCache2"
maxElementsInMemory="1000"
eternal="true"
overflowToDisk="false"
memoryStoreEvictionPolicy="FIFO"
statistics="true"
/>
30.1.2.2 Monitor
Copy the monitor package to a monitoring server.
To start the monitor, run the startup script provided in the bin directory: startup.sh on Unix and
startup.bat on Microsoft Windows. The monitor port selected in this script should match the port
specified in ehcache.xml.
The monitor can be configured, including interface, port and simple security settings, in the etc/
ehcache-monitor.conf.
The monitor connection timeout can also be configured. If the monitor is frequently timing out
while attempting to connect to a node (due to long GC cycles, for example), then the default
timeout value may not be suitable for your environment. You can set the monitor timeout
using the system property ehcachedx.connection.timeout.seconds. For example, -
Dehcachedx.connection.timeout.seconds=60 sets the timeout to 60 seconds.
A more comprehensive security solution can be achieved by configuring the Jetty Server with one ore
more UserRealms as described by Jetty and JAAS. Simply edit etc/jetty.xml to use the appropriate
UserRealm implementation for your needs. To configure the Monitor to authenticate against an
existing LDAP server, first ensure that you have defined and properly registered a LoginConfig,
such as the following example:
MyExistingLDAPLoginConfig {
com.sun.security.auth.module.LdapLoginModule REQUIRED
java.naming.security.authentication="simple"
userProvider="ldap://ldap-host:389"
authIdentity="uid={USERNAME},ou=People,dc=myorg,dc=org"
useSSL=false
bindDn="cn=Manager"
bindCredential="secretBindCredential"
bindAuthenticationType="simple"
debug=true;
};
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN"
"http://jetty.mortbay.org/configure.dtd">
<Configure id="Server" class="org.terracotta.ehcachedx.org.mortbay.jetty.Server">
<Set name="UserRealms">
<Array type="org.terracotta.ehcachedx.org.mortbay.jetty.security.UserRealm">
<Item>
<New class="org.terracotta.ehcachedx.org.mortbay.jetty.plus.jaas.JAASUserR
<Set name="Name">MyArbitraryLDAPRealmName</Set>
<Set name="LoginModuleName">MyExistingLDAPLoginConfig</Set>
</New>
</Item>
</Array>
</Set>
</Configure>
The LoginModuleName you specify as the second constructor parameter to the JAASUserRealm
class must exactly match the name of your LoginModule. The realm name specified as the first
constructor parameter can be an arbitrary value.
Note: the version of Jetty used in the Monitor has been repackaged so be sure to prefix any standard
Jetty class names with org.terracotta.ehcachedx.
If the Jetty Server is found to have been configured with any security realms, the simple user name
and password from ehcache-monitor.conf is ignored.
30.1.4.2 Statistics
This tab shows the statistics being gathered for each cache managed by the selected cache manager.
The Settings button permits you to add additional statistics fields to the display. Note: only displayed
fields are collected and aggregated by the probe. Adding additional display fields will increase the
processing required for probe and the monitor. The selected settings are stored in a preferences cookie
in your browser.
Double-clicking on any cache drills down to the Contents tab for that cache.
30.1.4.3 Configuration
This tab shows the key configuration information for each cache managed by the selected cache
manager.
30.1.4.4 Contents
This tab enables you to look inside the cache, search for elements via their keys and remove
individual or groups of elements from the cache.
The GUI is set to refresh at the same frequency that the probes aggregate their statistic samples which
is every 10 seconds by default. The progress bar at the bottom of the screen indicates the time until
the next refresh.
30.1.4.5 Charts
This tab contains various live charts of cache statistics. It gives you a feel for the trending of the each
statistic, rather than just the latest value.
30.Estimated Memory Use Chart
This chart shows the estimated memory use of the Cache.
Memory is estimated by sampling. The first 15 puts or updates are measured and then every 100th put
or update. Most caches contain objects of similar size. If this is not the case for your cache, then the
estimate will not be accurate.
Measurements are performed by walking the object graph of sampled elements through reflection. In
some cases such as classes not visible to the classloader, the measurement fails and 0 is recorded for
cache size. If you see a chart with 0 memory size values but the cache has data in it, then this is the
cause. For this release, caches distributed via Terracotta server show as 0.
30.1.4.6 API
This tab contains a listing of the API methods. Each is a hyperlink, which may be clicked on. Some
will display data and some will require additional arguments. If additional arguments are required an
error message will be displayed with the details. This tab is meant for interative testing of the API.
$ curl http://localhost:9889/monitor/listProbes?format=xml
30.1.6 Licensing
Unless otherwise indicated, this module is licensed for usage in development.
For details see the license terms in the appropriate LICENSE.txt. To obtain a commercial license for
use in production, please contact [email protected]
30.1.7 Limitations
31 Bulk Loading
.......................................................................................................................................
31.1.1 Uses
Bulk loading is designed to be used for:
• cache warming - where caches need to be filled before bringing an application online
• periodic batch loading - say an overnight batch process that uploads data
31.1.2 API
With bulk loading, the API for putting data into the cache stays the same. Just use cache.put(...)
cache.load(...) or cache.loadAll(...)>>>.
What changes is that there is a special mode that suspends Terracotta's normal coherence guarantees
and provides optimised flushing to the Terracotta Server Array (the L2 cache).
This mode can be enabled programmatically or statically in ehcache.xml. Programmatically, four
methods control coherent behaviour: setNodeCoherence(boolean mode), isNodeCoherent(),
isClusterCoherent() and waitUntilClusterCoherent().
31.1.2.2 isNodeCoherent()
Use this to find out if the node is in coherent mode locally. This does not account for other nodes in
the cluster (if any). The node may be coherent while its incoherent cluster-wide (like some other node
is incoherent)
31.1.2.3 isClusterCoherent()
Reflects whether the cache is in coherent or incoherent mode cluster-wide. Coherent cluster-wide
means that all nodes in the cluster is using the cache in coherent mode. If even one of the nodes is
using the cache in incoherent mode, the cache is incoherent cluster-wide
31.1.2.4 waitUntilClusterCoherent()
Calling this method will block the calling thread until the cache becomes coherent cluster-wide.
waitUntilClusterCoherent
waits until everyone is coherent. Will not return until the entire cluster is coherent.
setNodeCoherence(true | false)
This affects the local node only. The settings in the rest of the cluster are not affected.
Then to put it back call with true parameter.
This method does not return until all the transactions are flushed to the cluster. Only the calling thread
is blocked. This way you know when coherence is restored.
The initial state is from the config.
In a local standalone cache, setNodeCoherence should throw an UnsupportedOperationException.
waitUntilClusterCoherent will also throw an UnsupportedOperationException.
• Configuration
Coherent mode may be set by default in the configuration.
The terracotta element has an attribute coherent which can be true or false. By default it is true.
Ehcache 1.7 introduced a partial implementation of this feature for reads only. That is the
coherentRead. It is still honoured but deprecated.
• This can be dynamically controlled through JMX via the Dev Console.
Writes can also be synchronous or asynchronous. This is controlled by the synchronousWrites.
When you are running in incoherent mode synchronousWrites are ignored - it is always
asynchronous.
31.1.4 FAQ
31.1.4.1 Why does the bulk loading mode only apply to Terracotta clusters?
Ehcache, both standalone and replicated is already very fast and nothing needed to be added.
31.1.4.2 How does bulk load with RMI distributed caching work?
The core updates are very fast. RMI updates are batched by default once per second, so bulk loading
will be efficiently replicated.
31.1.5.3 Why not run in bulk load mode all the time
Terracotta clustering provides coherence, scaling and durability. Some applications will require
coherence, or not for some caches, such as reference data. It is possible to run a cache permanently in
incoherent mode.
In ehcache.xml, set the coherent attribute to false in the terracotta element. The terracotta element is
a sub-element of cache, so this can be configured per cache.
31.1.6 Download
The bulk loading feature is in the ehcache-core module but only provides a performance improvement
to Terracotta clusters (as bulk loading to Ehcache standalone is very fast already)
Download here.
For a full distribution enabling connection to the Terracotta Server array download here.
32.1.1 Configuration
One CacheManagerEventListenerFactory and hence one CacheManagerEventListener can be
specified per CacheManager instance.
The factory is configured as below:
<cacheManagerEventListenerFactory class="" properties=""/>
The entry specifies a CacheManagerEventListenerFactory which will be used to create a
CacheManagerPeerProvider, which is notified when Caches are added or removed from the
CacheManager.
The attributes of CacheManagerEventListenerFactory are:
• class - a fully qualified factory class name
• properties - comma separated properties having meaning only to the factory.
Callbacks to listener methods are synchronous and unsynchronized. It is the responsibility of the
implementer to safely handle the potential performance and thread safety issues depending on
what their listener is doing.
If no class is specified, or there is no cacheManagerEventListenerFactory element, no listener is
created. There is no default.
*/
public abstract class CacheManagerEventListenerFactory {
/**
* Create a <code>CacheEventListener</code>
*
* @param properties implementation specific properties. These are configured as com
* separated name value pairs in ehcache.xml. Properties may be nu
* @return a constructed CacheManagerEventListener
*/
public abstract CacheManagerEventListener
createCacheManagerEventListener(Properties properties);
}
The factory creates a concrete implementation of CacheManagerEventListener, which is reproduced
below:
/**
* Allows implementers to register callback methods that will be executed when a
* <code>CacheManager</code> event occurs.
* The events include:
* <ol>
* <li>adding a <code>Cache</code>
* <li>removing a <code>Cache</code>
* </ol>
* <p/>
* Callbacks to these methods are synchronous and unsynchronized. It is the responsibili
* the implementer to safely handle the potential performance and thread safety issues
* depending on what their listener is doing.
* @author Greg Luck
* @version $Id: cachemanager_event_listeners.apt 3744 2011-03-04 02:58:18Z gluck $
* @since 1.2
* @see CacheEventListener
*/
public interface CacheManagerEventListener {
/**
* Called immediately after a cache has been added and activated.
* <p/>
* Note that the CacheManager calls this method from a synchronized method. Any attempt
* call a synchronized method on CacheManager from this method will cause a deadlock.
* <p/>
* Note that activation will also cause a CacheEventListener status change notification
* from {@link net.sf.ehcache.Status#STATUS_UNINITIALISED} to
* {@link net.sf.ehcache.Status#STATUS_ALIVE}. Care should be taken on processing that
* notification because:
* <ul>
* <li>the cache will not yet be accessible from the CacheManager.
* <li>the addCaches methods whih cause this notification are synchronized on the
* CacheManager. An attempt to call {@link net.sf.ehcache.CacheManager#getCache(String)}
* will cause a deadlock.
* </ul>
* The calling method will block until this method returns.
* <p/>
* @param cacheName the name of the <code>Cache</
code> the operation relates to
* @see CacheEventListener
*/
void notifyCacheAdded(String cacheName);
/**
* Called immediately after a cache has been disposed and removed. The calling method wi
* block until this method returns.
* <p/>
* Note that the CacheManager calls this method from a synchronized method. Any attempt
* call a synchronized method on CacheManager from this method will cause a deadlock.
* <p/>
* Note that a {@link CacheEventListener} status changed will also be triggered. Any
* attempt from that notification to access CacheManager will also result in a deadlock.
* @param cacheName the name of the <code>Cache</
code> the operation relates to
*/
void notifyCacheRemoved(String cacheName);
}
The implementations need to be placed in the classpath accessible to ehcache. Ehcache uses the
ClassLoader returned by Thread.currentThread().getContextClassLoader() to load
classes.
33.1.1 Configuration
Cache event listeners are configured per cache. Each cache can have multiple listeners.
Each listener is configured by adding a cacheEventListenerFactory element as follows:
<cache ...>
<cacheEventListenerFactory class="" properties="" listenFor=""/>
...
</cache>
The entry specifies a CacheManagerEventListenerFactory which is used to create a
CachePeerProvider, which then receives notifications.
The attributes of CacheManagerEventListenerFactory are:
* Called immediately after an element has been removed. The remove method will block un
* this method returns.
* <p/>
* Ehcache does not chech for
* <p/>
* As the {@link net.sf.ehcache.Element} has been removed, only what was the key of the
* element is known.
* <p/>
*
* @param cache the cache emitting the notification
* @param element just deleted
*/
void notifyElementRemoved(final Ehcache cache, final Element element) throws CacheExcept
/**
* Called immediately after an element has been put into the cache. The
* {@link net.sf.ehcache.Cache#put(net.sf.ehcache.Element)} method
* will block until this method returns.
* <p/>
* Implementers may wish to have access to the Element's fields, including value, so the
* element is provided. Implementers should be careful not to modify the element. The
* effect of any modifications is undefined.
*
* @param cache the cache emitting the notification
* @param element the element which was just put into the cache.
*/
void notifyElementPut(final Ehcache cache, final Element element) throws CacheException;
/**
* Called immediately after an element has been put into the cache and the element alrea
* existed in the cache. This is thus an update.
* <p/>
* The {@link net.sf.ehcache.Cache#put(net.sf.ehcache.Element)} method
* will block until this method returns.
* <p/>
* Implementers may wish to have access to the Element's fields, including value, so the
* element is provided. Implementers should be careful not to modify the element. The
* effect of any modifications is undefined.
*
* @param cache the cache emitting the notification
* @param element the element which was just put into the cache.
*/
void notifyElementUpdated(final Ehcache cache, final Element element) throws CacheExcept
/**
* Called immediately after an element is <i>found</i> to be expired. The
* {@link net.sf.ehcache.Cache#remove(Object)} method will block until this method retur
* <p/>
* As the {@link Element} has been expired, only what was the key of the element is know
* <p/>
* Elements are checked for expiry in Ehcache at the following times:
* <ul>
* <li>When a get request is made
* <li>When an element is spooled to the diskStore in accordance with a MemoryStore
* eviction policy
* <li>In the DiskStore when the expiry thread runs, which by default is
* {@link net.sf.ehcache.Cache#DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS}
* </ul>
* If an element is found to be expired, it is deleted and this method is notified.
*
* @param cache the cache emitting the notification
* @param element the element that has just expired
* <p/>
* Deadlock Warning: expiry will often come from the <code>DiskStore</
code>
* expiry thread. It holds a lock to the DiskStorea the time the
* notification is sent. If the implementation of this method calls into a
* synchronized <code>Cache</
code> method and that subsequently calls into
* DiskStore a deadlock will result. Accordingly implementers of this method
* should not call back into Cache.
*/
void notifyElementExpired(final Ehcache cache, final Element element);
/**
* Give the replicator a chance to cleanup and free resources when no longer needed
*/
void dispose();
/**
* Creates a clone of this listener. This method will only be called by Ehcache before a
* cache is initialized.
* <p/>
* This may not be possible for listeners after they have been initialized. Implementati
* should throw CloneNotSupportedException if they do not support clone.
* @return a clone
* @throws CloneNotSupportedException if the listener could not be cloned.
*/
public Object clone() throws CloneNotSupportedException;
}
The implementations need to be placed in the classpath accessible to Ehcache.
See the chapter on Classloading for details on how classloading of these classes will be done.
33.1.3 FAQ
35 Cache Extensions
.......................................................................................................................................
* cache is initialized.
* <p/>
* Implementations should throw CloneNotSupportedException if they do not support clone
* but that will stop them from being used with defaultCache.
*
* @return a clone
* @throws CloneNotSupportedException if the extension could not be cloned.
*/
public CacheExtension clone(Ehcache cache) throws CloneNotSupportedException;
/**
* @return the status of the extension
*/
public Status getStatus();
}
The implementations need to be placed in the classpath accessible to ehcache.
See the chapter on Classloading for details on how class loading of these classes will be done.
36 Cache Loaders
.......................................................................................................................................
* <p/>
* There is one factory method for JSR107 Cache Loaders and one for Ehcache ones. The Eh
* loader is a sub interface of the JSR107 Cache Loader.
* <p/>
* Note that both the JCache and Ehcache APIs also allow the CacheLoader to be set
* programmatically.
* @author Greg Luck
* @version $Id: cache_loaders.apt 3744 2011-03-04 02:58:18Z gluck $
*/
public abstract class CacheLoaderFactory {
/**
* Creates a CacheLoader using the JSR107 creational mechanism.
* This method is called from {@link net.sf.ehcache.jcache.JCacheFactory}
*
* @param environment the same environment passed into
* {@link net.sf.ehcache.jcache.JCacheFactory}.
* This factory can extract any properties it needs from the environment.
* @return a constructed CacheLoader
*/
public abstract net.sf.jsr107cache.CacheLoader createCacheLoader(Map environment);
/**
* Creates a CacheLoader using the Ehcache configuration mechanism at the time
* the associated cache is created.
*
* @param properties implementation specific properties. These are configured as comma
* separated name value pairs in ehcache.xml
* @return a constructed CacheLoader
*/
public abstract net.sf.ehcache.loader.CacheLoader createCacheLoader(Properties propertie
/**
* @param cache the cache this extension should hold a reference to,
* and to whose lifecycle it should be bound.
* @param properties implementation specific properties configured as delimiter
* separated name value pairs in ehcache.xml
* @return a constructed CacheLoader
*/
public abstract CacheLoader createCacheLoader(Ehcache cache, Properties properties);
}
The factory creates a concrete implementation of the CacheLoader interface, which is reproduced
below.
A CacheLoader is bound to the lifecycle of a cache, so that init() is called during cache
initialization, and dispose() is called on disposal of a cache.
/**
* Extends JCache CacheLoader with load methods that take an argument in addition to a k
* @author Greg Luck
* @version $Id: cache_loaders.apt 3744 2011-03-04 02:58:18Z gluck $
*/
public interface CacheLoader extends net.sf.jsr107cache.CacheLoader {
/**
* Load using both a key and an argument.
* <p/>
* JCache will call through to the load(key) method, rather than this method,
*/
void dispose() throws net.sf.ehcache.CacheException;
/**
* @return the status of the extension
*/
public Status getStatus();
}
The implementations need to be placed in the classpath accessible to ehcache.
See the chapter on Classloading for details on how classloading of these classes will be done.
A read against the database will result in incorrect data being loaded.
37.Expiry
Even if all of the dataset can fit in the cache, it could be evicted if Elements expire. Accordingly, both
timeToLive and timeToIdle should be set to eternal ("0") to prevent this from happening.
37.1.5 Configuration
There are many configuration options. See the CacheWriterConfiguration for properties that
may be set and their effect.
Below is an example of how to configure the cache writer in XML:
<cache name="cacheName" eternal="false" maxElementsInMemory="1000" overflowToDisk="false
<cacheWriter writeMode="write_behind" maxWriteDelay="8" rateLimitPerSecond="5"
writeCoalescing="true" writeBatching="true" writeBatchSize="20"
retryAttempts="2" retryAttemptDelaySeconds="2">
<cacheWriterFactory class="com.company.MyCacheWriterFactory"
properties="just.some.property=test; another.property=test2"
>
</cacheWriter>
</cache>
Further examples:
<cache name="writeThroughCache1" eternal="false" maxElementsInMemory="1000" overflowToDi
>
<cache name="writeThroughCache2" eternal="false" maxElementsInMemory="1000" overflowToDi
<cacheWriter/>
</cache>
<cache name="writeThroughCache3" eternal="false" maxElementsInMemory="1000" overflowToDi
<cacheWriter writeMode="write_through" notifyListenersOnException="true" maxWriteDelay
rateLimitPerSecond="10" writeCoalescing="true" writeBatching="true" write
retryAttempts="20" retryAttemptDelaySeconds="60"/>
</cache>
<cache name="writeThroughCache4" eternal="false" maxElementsInMemory="1000" overflowToDi
<cacheWriter writeMode="write_through" notifyListenersOnException="false" maxWriteDela
rateLimitPerSecond="0" writeCoalescing="false" writeBatching="false" writ
retryAttempts="0" retryAttemptDelaySeconds="0">
<cacheWriterFactory class="net.sf.ehcache.writer.WriteThroughTestCacheWriterFactor
>
</cacheWriter>
</cache>
<cache name="writeBehindCache5" eternal="false" maxElementsInMemory="1000" overflowToDis
<cacheWriter writeMode="write-
behind" notifyListenersOnException="true" maxWriteDelay="8" rateLimitPerSecond="5"
writeCoalescing="true" writeBatching="false" writeBatchSize="20"
retryAttempts="2" retryAttemptDelaySeconds="2">
<cacheWriterFactory class="net.sf.ehcache.writer.WriteThroughTestCacheWriterFactor
properties="just.some.property=test; another.property=test2" p
>
</cacheWriter>
</cache>
This configuration can also be achieved through the Cache constructor in Java:
Cache cache = new Cache(
new CacheConfiguration("cacheName", 10)
.cacheWriter(new CacheWriterConfiguration()
.writeMode(CacheWriterConfiguration.WriteMode.WRITE_BEHIND)
.maxWriteDelay(8)
.rateLimitPerSecond(5)
.writeCoalescing(true)
.writeBatching(true)
.writeBatchSize(20)
.retryAttempts(2)
.retryAttemptDelaySeconds(2)
.cacheWriterFactory(new CacheWriterConfiguration.CacheWriterFactoryConfiguration()
.className("com.company.MyCacheWriterFactory")
.properties("just.some.property=test; another.property=test2")
.propertySeparator(";"))));
Instead of relying on a CacheWriterFactoryConfiguration>> to create a
<<<CacheWriter, it's also possible to explicitly register a CacheWriter instance from within Java
code. This allows you to refer to local resources like database connections or file handles.
Cache cache = manager.getCache("cacheName");
MyCacheWriter writer = new MyCacheWriter(jdbcConnection);
cache.registerCacheWriter(writer);
37.All modes
• write-mode [write-through | write-behind] - Whether to run in write-behind or write-through
mode. The default is write-through.
37.write-through mode only
• notifyListenersOnException - Whether to notify listeners when an exception occurs on a store
operation. Defaults to false. If using cache replication, set this attribute to "true" to ensure that
changes to the underlying store are replicated.
37.write-behind mode only
• writeBehindMaxQueueSize - The maximum number of elements allowed per
queue, or per bucket (if the queue has multiple buckets). "0" means unbounded
(default). When an attempt to add an element is made, the queue size (or bucket
size) is checked, and if full then the operation is blocked until the size drops by one.
Note that elements or a batch currently being processed (and coalesced elements)
are not included in the size value. Programmatically, this attribute can be set with
net.sf.ehcache.config.CacheWriterConfiguration.setWriteBehindMaxQueueSize().
• writeBehindConcurrency - The number of thread-bucket pairs on the node
for the given cache (default is 1). Each thread uses the settings configured for
write-behind. For example, if rateLimitPerSecond is set to 100, each thread-
bucket pair will perform up to 100 operations per second. In this case, setting
writeBehindConcurrency="4" means that up to 400 operations per second will occur
on the node for the given cache. Programmatically, this attribute can be set with
net.sf.ehcache.config.CacheWriterConfiguration.setWriteBehindConcurrency().
• maxWriteDelaySeconds - The maximum number of seconds to wait before writing behind.
Defaults to 0. If set to a value greater than 0, it permits operations to build up in the queue to
enable effective coalescing and batching optimisations.
• rateLimitPerSecond - The maximum number of store operations to allow per second.
• writeCoalescing - Whether to use write coalescing. Defaults to false. When set to true, if multiple
operations on the same key are present in the write-behind queue, then only the latest write is
done (the others are redundant). This can dramatically reduce load on the underlying resource.
• writeBatching - Whether to batch write operations. Defaults to false. If set to true, storeAll and
deleteAll will be called rather than store and delete being called for each key. Resources such as
databases can perform more efficiently if updates are batched to reduce load.
• writeBatchSize - The number of operations to include in each batch. Defaults to 1. If there are
less entries in the write-behind queue than the batch size, the queue length size is used. Note that
batching is split across operations. For example, if the batch size is 10 and there were 5 puts and
5 deletes, the CacheWriter is invoked. It does not wait for 10 puts or 10 deletes.
• retryAttempts - The number of times to attempt writing from the queue. Defaults to 1.
• retryAttemptDelaySeconds - The number of seconds to wait before retrying.
37.1.6 API
CacheLoaders are exposed for API use through the cache.getWithLoader(...)
method. CacheWriters are exposed with cache.putWithWriter(...) and
cache.removeWithWriter(...) methods.
For example, following is the method signature for cache.putWithWriter(...).
/**
* Put an element in the cache writing through a CacheWriter. If no CacheWriter has been
* set for the cache, then this method has the same effect as cache.put().
* <p/>
* Resets the access statistics on the element, which would be the case if it has previo
* been gotten from a cache, and is now being put back.
* <p/>
* Also notifies the CacheEventListener, if the writer operation succeeds, that:
* <ul>
* <li>the element was put, but only if the Element was actually put.
* <li>if the element exists in the cache, that an update has occurred, even if the elem
* would be expired if it was requested
* </ul>
*
* @param element An object. If Serializable it can fully participate in replication and
* DiskStore.
* @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STA
* @throws IllegalArgumentException if the element is null
* @throws CacheException
*/
void putWithWriter(Element element) throws IllegalArgumentException, IllegalStateExcepti
CacheException;
See the Cache JavaDoc for the complete API.
37.1.7 SPI
The Ehcache write-through SPI is the CacheWriter interface. Implementers perform writes to the
underlying resource in their implementation.
/**
* A CacheWriter is an interface used for write-through and write-
behind caching to a
* underlying resource.
* <p/>
* If configured for a cache, CacheWriter's methods will be called on a cache operation.
* A cache put will cause a CacheWriter write
* and a cache remove will cause a writer delete.
* <p>
* Implementers should create an implementation which handles storing and deleting to an
* underlying resource.
* </p>
* <h4>Write-Through</h4>
* In write-
through mode, the cache operation will occur and the writer operation will occur
* before CacheEventListeners are notified. If
* the write operation fails an exception will be thrown. This can result in a cache whi
* is inconsistent with the underlying resource.
* To avoid this, the cache and the underlying resource should be configured to particip
* in a transaction. In the event of a failure
* a rollback can return all components to a consistent state.
* <p/>
* <h4>Write-Behind</h4>
* In write-behind mode, writes are written to a write-
behind queue. They are written by a
* separate execution thread in a configurable
* way. When used with Terracotta Server Array, the queue is highly available. In additi
* any node in the cluster may perform the
* write-behind operations.
* <p/>
* <h4>Creation and Configuration</h4>
* CacheWriters can be created using the CacheWriterFactory.
* <p/>
* The manner upon which a CacheWriter is actually called is determined by the
* {@link net.sf.ehcache.config.CacheWriterConfiguration} that is set up for cache
* that is using the CacheWriter.
* <p/>
* See the CacheWriter chapter in the documentation for more information on how to use w
*
* @author Greg Luck
* @author Geert Bevin
* @version $Id: $
*/
public interface CacheWriter {
/**
* Creates a clone of this writer. This method will only be called by ehcache before
* cache is initialized.
* <p/>
* Implementations should throw CloneNotSupportedException if they do not support cl
* but that will stop them from being used with defaultCache.
*
* @return a clone
* @throws CloneNotSupportedException if the extension could not be cloned.
*/
public CacheWriter clone(Ehcache cache) throws CloneNotSupportedException;
/**
* Notifies writer to initialise themselves.
* <p/>
* This method is called during the Cache's initialise method after it has changed i
* status to alive. Cache operations are legal in this method.
*
* @throws net.sf.ehcache.CacheException
*/
void init();
/**
* Providers may be doing all sorts of exotic things and need to be able to clean up
* dispose.
* <p/>
* Cache operations are illegal when this method is called. The cache itself is part
* disposed when this method is called.
*/
void dispose() throws CacheException;
/**
* Write the specified value under the specified key to the underlying store.
* This method is intended to support both key/
value creation and value update for a
* specific key.
*
* @param element the element to be written
*/
void write(Element element) throws CacheException;
/**
* Write the specified Elements to the underlying store. This method is intended to
* support both insert and update.
* If this operation fails (by throwing an exception) after a partial success,
* the convention is that entries which have been written successfully are to be rem
* from the specified mapEntries, indicating that the write operation for the entrie
* in the map has failed or has not been attempted.
*
* @param elements the Elements to be written
*/
void writeAll(Collection<Element> elements) throws CacheException;
/**
* Delete the cache entry from the store
*
* @param entry the cache entry that is used for the delete operation
*/
void delete(CacheEntry entry) throws CacheException;
/**
* Remove data and keys from the underlying store for the given collection of keys,
* present. If this operation fails * (by throwing an exception) after a partial suc
* the convention is that keys which have been erased successfully are to be removed
* the specified keys, indicating that the erase operation for the keys left in the
* has failed or has not been attempted.
*
* @param entries the entries that have been removed from the cache
*/
void deleteAll(Collection<CacheEntry> entries) throws CacheException;
}
37.1.8 FAQ
38.1.1 Introduction
Ehcache now comes with a Cache Server, available as a WAR for most web containers, or as a
standalone server. The Cache Server has two APIs: RESTful resource oriented, and SOAP. Both
support clients in any programming language.
(A Note on terminology: Leonard Richardson and Sam Ruby have done a great job of clarifying the
different Web Services architectures and distinguishing them from each other. We use their taxonomy
in describing web services. See http://www.oreilly.com/catalog/9780596529260/.)
38.OPTIONS /{cache}}
Retrieves the WADL for describing the available CacheManager operations.
38. GET /
Lists the Caches in the CacheManager.
38.OPTIONS /{cache}}
Retrieves the WADL describing the available Cache operations.
38.HEAD /{cache}}
Retrieves the same metadata a GET would receive returned as HTTP headers. There is no body
returned.
38.GET /{cache}
Gets a cache representation. This includes useful metadata such as the configuration and cache
statistics.
38. PUT /{cache}
Creates a Cache using the defaultCache configuration.
38. DELETE / {cache}
Deletes the Cache.
38.OPTIONS /{cache}}
Retrieves the WADL describing the available Element operations.
38.HEAD /{cache}/{element}
Retrieves the same metadata a GET would receive returned as HTTP headers. There is no body
returned.
38.GET /{cache}/{element}
Gets the element value.
38.HEAD /{cache}/{element}
Gets the element's metadata.
38.PUT /{cache}/{element}
Puts an element into the Cache.
The time to live of new Elements defaults to that for the cache. This may be overridden by setting the
HTTP request header ehcacheTimeToLiveSeconds. Values of 0 to 2147483647 are accepted. A
value of 0 means eternal.
38.DELETE / {cache}/{element}
Deletes the element from the cache.
The resource representation for all elements is *. DELETE/{cache}/* will call
<<<cache.removeAll().
Because Ehcache is a distributed Java cache, in some configurations the Cache server may contain
Java objects that arrived at the Cache server via distributed replication. In this case no MIME Type
will be set and the Element will be examined to determine its MIME Type.
Because anything that can be PUT into the cache server must be Serializable, it can also be distributed
in a cache cluster i.e. it will be Serializable.
38.GET
curl http://localhost:8080/ehcache/rest/sampleCache2/2
The server responds with:
<?xml version="1.0"?>
<oldjoke>
<burns>Say <quote>goodnight</quote>,
Gracie.</burns>
<allen><quote>Goodnight,
Gracie.</quote></allen>
<applause/>
import java.net.URL;
/**
* A simple example Java client which uses the built-
in java.net.URLConnection.
*
* @author BryantR
* @author Greg Luck
*/
public class ExampleJavaClient {
private static String TABLE_COLUMN_BASE =
"http://localhost:8080/ehcache/rest/tableColumn";
private static String TABLE_COLUMN_ELEMENT =
"http://localhost:8080/ehcache/rest/tableColumn/1";
/**
* Creates a new instance of EHCacheREST
*/
public ExampleJavaClient() {
}
public static void main(String[] args) {
URL url;
HttpURLConnection connection = null;
InputStream is = null;
OutputStream os = null;
int result = 0;
try {
//create cache
URL u = new URL(TABLE_COLUMN_BASE);
HttpURLConnection urlConnection = (HttpURLConnection) u.openConnection();
urlConnection.setRequestMethod("PUT");
int status = urlConnection.getResponseCode();
System.out.println("Status: " + status);
urlConnection.disconnect();
//get cache
url = new URL(TABLE_COLUMN_BASE);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();
is = connection.getInputStream();
byte[] response1 = new byte[4096];
result = is.read(response1);
while (result != -1) {
System.out.write(response1, 0, result);
result = is.read(response1);
}
if (is != null) try {
is.close();
} catch (Exception ignore) {
}
System.out.println("reading cache: " + connection.getResponseCode()
+ " " + connection.getResponseMessage());
if (connection != null) connection.disconnect();
//create entry
url = new URL(TABLE_COLUMN_ELEMENT);
This topology is the simplest. It does not use a load balancer. Each node is accessed directly by the
cache client using REST. No redundancy is provided.
The client can be implemented in any language because it is simply a HTTP client.
It must work out a partitioning scheme. Simple key hashing, as used by memcached, is sufficient.
Here is a Java code sample:
String[] cacheservers = new String[]
{"cacheserver0.company.com", "cacheserver1.company.com",
"cacheserver2.company.com", "cacheserver3.company.com", "cacheserver4.company.com",
"cacheserver5.company.com"};
Object key = "123231";
int hash = Math.abs(key.hashCode());
int cacheserverIndex = hash % cacheservers.length;
String cacheserver = cacheservers[cacheserverIndex];
Redundancy is added as shown in the above diagram by: Replacing each node with a cluster of two
nodes. One of the existing distributed caching options in Ehcache is used to form the cluster. Options
in Ehcache 1.5 are RMI and JGroups-based clusters. Ehcache-1.6 will add JMS as a further option.
Put each Ehcache cluster behind VIPs on a load balancer.
Many content-switching load balancers support URI routing using some form of regular expressions.
So, you could optionally skip the client-side hashing to achieve partitioning in the load balancer itself.
For example:
/ehcache/rest/sampleCache1/[a-h]* => cluster1
/ehcache/rest/sampleCache1/[i-z]* => cluster2
Things get much more sophisticated with F5 load balancers, which let you create iRules in the TCL
language. So rather than regular expression URI routing, you could implement key hashing-based
URI routing. Remember in Ehcache's RESTful server, the key forms the last part of the URI. e.g. In
the URI http://cacheserver.company.com/ehcache/rest/sampleCache1/3432 , 3432 is the key.
You hash using the last part of the URI.
See http://devcentral.f5.com/Default.aspx?
tabid=63&PageID=153&ArticleID=135&articleType=ArticleView for how to implment a URI
hashing iRule on F5 load balancers.
The World Wide Web is more and more used for application to application communication.
The programmatic interfaces made available are referred to as Web services.
They provide a set of recommendations for achieving this. See http://www.w3.org/2002/ws/.
An interoperability organisation, WS-I http://www.ws-i.org/, seeks to achieve interoperabilty between
W3C Web Services. The W3C specifications for SOAP and WSDL are required to meet the WS-I
definition.
Ehcache is using Glassfish's libraries to provide it's W3C web services. The project known as Metro
follows the WS-I definition.
Finally, OASIS ( http://oasis-open.org), defines a Web Services Security specification for SOAP:
WS-Security. The current version is 1.1. It provides three main security mechanisms: ability to send
security tokens as part of a message, message integrity, and message confidentiality.
Ehcache's W3C Web Services support the stricter WS-I definition and use the SOAP and WSDL
specfications.
Specifically:
• The method of operation is in the entity-body of the SOAP envelope and a HTTP header. POST
is always used as the HTTP method.
• The scoping information, used to identify the resource to perform the method on, is contained
in the SOAP entity-body. The URI path is always the same for a given Web Service - it is the
service "endpoint".
• The Web Service is described by and exposes a WSDL (Web Services Description Language)
file. It contains the methods, their arguments and what data types are used.
• The WS-Security SOAP extensions are supported
38.1.4.2 Security
By default no security is configured. Because it is simply a Servlet 2.5 web application, it can be
secured in all the usual ways by configuration in the web.xml.
In addition the cache server supports the use of XWSS 3.0 to secure the Web Service. See https://
xwss.dev.java.net/. All required libraries are packaged in the war for XWSS 3.0.
A sample, commented out server_security_config.xml is provided in the WEB-INF directory. XWSS
automatically looks for this configuration file.
A simple example, based on an XWSS example,
net.sf.ehcache.server.soap.SecurityEnvironmentHandler, which looks for a password
in a System property for a given username is included. This is not recommended for production use
but is handy when you are getting started with XWSS.
To use XWSS:
Add configuration in accordance with XWSS to the server_security_config.xml file. Create a class
which implements the CallbackHandler interface and provide its fully qualified path in the
SecurityEnvironmentHandler element.
The integration test EhcacheWebServiceEndpoint test shows how to use the XWSS client side.
On the client side, configuration must be provided in a file called client_security_config.xml
must be in the root of the classpath.
To add client credentials into the SOAP request do:
cacheService = new EhcacheWebServiceEndpointService().getEhcacheWebServiceEndpointPort()
//add security credentials
((BindingProvider)cacheService).getRequestContext().put(BindingProvider.USERNAME_PROPERT
"Ron");
((BindingProvider)cacheService).getRequestContext().put(BindingProvider.PASSWORD_PROPERT
"noR");
String result = cacheService.ping();
38.1.5 Requirements
38.1.5.1 Java
Java 5 or 6
• Glassfish V2/V3
• Tomcat 6
• Jetty 6
38.1.6 Downloading
The server is available as follows:
38.1.6.1 Sourceforge
Download here.
There are two tarball archives in tar.gz format:
• ehcache-server - this contains the WAR file which must be deployed in your own web container.
• ehcache-standalone-server - this contains a complete standalone directory structure with an
embedded Glassfish V3 web container together with shell scripts for starting and stopping.
38.1.6.2 Maven
The Ehcache Server is in the central Maven repository packaged as type war. Use the following
Maven pom snippet:
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-server</artifactId>
<version>enter_version_here</version>
<type>war</type>
</dependency>
It is also available as a jaronly version, which makes it easier to embed. This version excludes all
META-INF and WEB-INF configuration files, and also excludes the ehcache.xml. You need to
provide these in your maven project.
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-server</artifactId>
<version>enter_version_here</version>
<type>jar</type>
<classifier>jaronly</classifier>
</dependency>
38.1.7 Installation
No Meaning
1 HUP
2 INT
9 KILL
15 TERM
38.Executable jar
The server is also packaged as an executable jar for developer convenience which will work on all
operating systems.
A convenience shell script is provided as follows:
start - startup.sh
From the bin directory you can also invoke the following command directly:
unix - java -jar ../lib/ehcache-standalone-server-0.7.jar 8080 ../
war
windows - java -jar ..\lib\ehcache-standalone-server-0.7.jar 8080 ..
\war
38.1.9 Monitoring
The CacheServer registers Ehcache MBeans with the platform MBeanServer.
Remote monitoring of the MBeanServer is the responsibility of the Web Container or Application
Server vendor.
For example, some instructions for Tomcat are here: https://wiki.internet2.edu/confluence/display/
CPD/Monitoring+Tomcat+with+JMX
See your Web Container documentation for how to do this for your web container.
Of course, from there you can hook the Cache Server up to your monitoring tool of choice. See the
chapter on JMX Management and Monitoring for more information.
38.1.10 Download
Download the ehcache-standalone-server from http://sourceforge.net/projects/ehcache/files/ehcache-
server.
38.1.11 FAQ
* @param key - The key that retrieves a value that you want to protect via locking
* @param timeout - millis until giveup on getting the lock
* @return whether the lock was awarded
* @throws InterruptedException
*/
public boolean tryWriteLockOnKey(Object key, long timeout) throws InterruptedExcepti
Sync s = getLockForKey(key);
return s.tryLock(LockType.WRITE, timeout);
}
/**
* Release a held read lock for the passed in key
*
* @param key - The key that retrieves a value that you want to protect via locking
*/
public void releaseReadLockOnKey(Object key) {
releaseLockOnKey(key, LockType.READ);
}
/**
* Release a held write lock for the passed in key
*
* @param key - The key that retrieves a value that you want to protect via locking
*/
public void releaseWriteLockOnKey(Object key) {
releaseLockOnKey(key, LockType.WRITE);
}
39.1.2 Example
Here is a brief example:
String key = "123";
Foo val = new Foo();
cache.acquireWriteLockOnKey(key);
try {
cache.put(new Element(key, val));
} finally {
cache.releaseWriteLockOnKey(key);
}
...sometime later
String key = "123";
cache.acquireWriteLockOnKey(key);
try {
Object cachedVal = cache.get(key).getValue();
cachedVal.setSomething("abc");
cache.put(new Element(key, cachedVal));
} finally {
cache.releaseWriteLockOnKey(key);
}
40.1.2 SelfPopulatingCache
You want to use the BlockingCache, but the requirement to always release the lock creates gnarly
code. You also want to think about what you are doing without thinking about the caching.
Enter the SelfPopulatingCache. The name SelfPopulatingCache is synonymous with Pull-through
cache, which is a common caching term. SelfPopulatingCache though always is in addition to a
BlockingCache.
SelfPopulatingCache uses a CacheEntryFactory, that given a key, knows how to populate the
entry.
Note: JCache inspired getWithLoader and getAllWithLoader directly in Ehcache which work with a
CacheLoader may be used as an alternative to SelfPopulatingCache.
41 OpenJPA Caching
.......................................................................................................................................
41.1.1 Installing
To use it, add a Maven dependency for ehcache-openjpa.
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-openjpa</artifactId>
<version>0.1</version>
or download from downloads.
41.1.2 Configuration
Set OpenJPA#s openjpa.QueryCache to ehcache and openjpa.DataCacheManager to
ehcache. That#s it!
See http://openjpa.apache.org/builds/1.0.2/apache-openjpa-1.0.2/docs/manual/
ref_guide_caching.html for more on caching in OpenJPA.
42 Grails Caching
.......................................................................................................................................
42.1.1 Using Ehcache as a Second Level Caching Provider for Hibernate within Grails
Grails 1.2RC1 and higher use Ehcache as the default Hibernate second level cache. However earlier
versions of Grails ship with the Ehcache library and are very simple to enable.
The following steps show how to configure Grails to use Ehcache. For 1.2RC1 and higher some of
these steps are already done for you.
timeToIdleSeconds="300"
/>
</ehcache>
43 JRuby Caching
.......................................................................................................................................
43.1.1 Installation
Ehcache JRuby integration is provided by the jruby-ehcache gem. To install it simply execute (note:
you may need to use "sudo" to install gems on your system):
jgem install jruby-ehcache
If you also want Rails caching support, also install the correct gem for your Rails version:
jgem install jruby-ehcache-rails2 # for Rails 2
jgem install jruby-ehcache-rails3 # for Rails 3
43.1.3 Dependencies
With this configuration out of the way, you can now use the Ehcache API directly from your Rails
controllers and/or models. You could of course create a new Cache object everywhere you want to
use it, but it is better to create a single instance and make it globally accessible by creating the Cache
object in your Rails environment.rb file.
For example, you could add the following lines to config/environment.rb:
require 'ehcache'
EHCACHE = Ehcache::CacheManager.new.cache
By doing so, you make the EHCACHE constant available to all Rails-managed objects in your
application. Using the Ehcache API is now just like the above JRuby example.
If you are using Rails 3 then you have a better option at your disposal: the built-in Rails 3 caching
API. This API provides an abstraction layer for caching underneath which you can plug in any one
of a number of caching providers. ? The most common provider to date has been the memcached
provider, but now you can also use the Ehcache provider.
Switching to the Ehcache provider requires only one line of code in your Rails environment file (e.g.
development.rb or production.rb):
config.cache_store = :ehcache_store
A very simple example of the Rails caching API is as follows:
Rails.cache.write("answer", "42")
Rails.cache.read("answer") # => '42'
Using this API, your code can be agnostic about the underlying provider, or even switch providers
based on the current environment (e.g. memcached in development mode, Ehcache in production)
43.1.7.2 Dependencies
To start the demo, make sure you are using JRuby 1.5.0 or later.
The demo uses sqlite3 which needs to be installed on your OS (it is by default on Mac OS X).
There is a Gemfile which will pull down all of the required Ruby dependencies using Bundler.
From the ehcache-rails-demo directory:
jgem install bundler
jruby -S bundle install
44 Glassfish HowTo
.......................................................................................................................................
44.1.1 Versions
Ehcache has been tested with and is used in production with Glassfish V1, V2 and V3.
In particular:
• Ehcache 1.4 - 1.7 has been tested with Glassfish 1 and 2.
• Ehcache 2.0 has been tested with Glassfish 3.
44.1.2 HowTo
44.1.2.1 HowTo Get A Sample Application using Ehcache packaged and Deployed to Glassfish
Ehcache comes with a sample web application which is used to test the page caching. The page
caching is the only area that is sensitive to the Application Server. For Hibernate and general caching,
it is only dependent on your Java version.
From a checkout of Ehcache run the following from the core directory:
You need:
• a Glassfish installation.
• a GLASSFISH_HOME environment variable defined.
• $GLASSFISH_HOME/bin added to your PATH
Do the following:
# To package and deploy to domain1:
ant deploy-default-web-app-glassfish
# Start domain1:
asadmin start-domain domain1
# Stop domain1:
asadmin stop-domain domain1
# Overwrite the config with our own which changes the port to 9080:
ant glassfish-configuration
# Start domain1:
asadmin start-domain domain1
You can then run the web tests in the web package or point your browser at http://
localhost:9080.
See for a quickstart to Glassfish.
44.1.2.2 How to get around the EJB Container restrictions on thread creation
When Ehcache is running in the EJB Container, for example for Hibernate caching, it is in technical
breach of the EJB rules. Some app servers let you override this restriction.
I am not exactly sure how this in done in Glassfish. For a number of reasons we run Glassfish without
the Security Manager, and we do not have any issues.
In domain.xml ensure that the following is not included.
<jvm-options>-Djava.security.manager</jvm-options>
44.1.3.1 Ehcache page caching versions below Ehcache 1.3 get an IllegalStateException in Glassfish.
This issue was fixed in Ehcache 1.3.
44.1.3.2 I get a Could not ungzip. Heartbeat will not be working. Not in GZIP
format reported from PayloadUtil exception when using Ehcache with my Glassfish cluster. Why?
Ehcache and Glassfish clustering have nothing to do with each other. The error is caused because
Ehcache has received a multicast message from the Glassfish cluster. Ensure that Ehcache clustering
has its own unique multicast address different to Glassfish.
45.1.2 Compatibility
Ehcache is compatible and works with Google App Engine.
Google App Engine provides a constrained runtime which restricts networking, threading and file
system access.
45.1.3 Limitations
All features of Ehcache can be used except for the DiskStore and replication. Having said that, there
are workarounds for these limitations. See the Recipes section below.
As of June 2009, Google App Engine appears to be limited to a heap size of 100MB. (See http://
gregluck.com/blog/archives/2009/06/the_limitations.html for the evidence of this).
45.1.4 Dependencies
Version 2.3 and higher of Ehcache are compatible with Google App Engine.
Older versions will not work.
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
diskPersistent="false"
memoryStoreEvictionPolicy="LRU"
/>
<!--Example sample cache-->
<cache name="sampleCache1"
maxElementsInMemory="10000"
maxElementsOnDisk="1000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU"
/>
</ehcache>
45.1.6 Recipes
You can get acceleration for dynamic files using Ehcache's caching filters as you usually would.
See the Web Caching chapter.
46.1.1.2 In development, there appear to be class loader memory leak as I continually redeploy my web
application.
There are lots of causes of memory leaks on redeploy. Moving Ehcache out of the WAR and into
$TOMCAT/common/lib fixes this leak.
46.1.1.4 Multiple Host Entries in Tomcat's server.xml stops replication from occurring
The presence of multiple Host entries in Tomcat's server.xml prevents replication from occuring.
The issue is with adding multiple hosts on a single Tomcat connector. If one of the hosts is localhost
and another starts with v, then the caching between machines when hitting localhost stops working
correctly.
The workaround is to use a single Host entry or to make sure they don't start with "v".
Why this issue occurs is presently unknown, but is Tomcat specific.
47.1.3.1 net.sf.jsr107cache.CacheManager
CacheManager does not have the following features:
• shutdown the CacheManager - there is no way to free resources or persist. Implementations may
utilise a shutdown hook, but that does not work for application server redeployments, where a
shutdown listener must be used.
• List caches in the CacheManager. There is no way to iterate over, or get a list of caches.
• remove caches from the CacheManager - once its there it is there until JVM shutdown. This does
not work well for dynamic creation, destruction and recreation of caches.
• CacheManager does not provide a standard way to configure caches. A Map can be populated
with properties and passed to the factory, but there is no way a configuration file can be
configured. This should be standardised so that declarative cache configuration, rather than
programmatic, can be achieved.
47.1.3.2 net.sf.jsr107cache.CacheFactory
A property is specified in the resource services/net.sf.jsr107cache.CacheFactory for a CacheFactory.
The factory then resolves the CacheManager which must be a singleton.
A singleton CacheManager works in simple scenarios. But there are many where you want multiple
CacheManagers in an application. Ehcache supports both singleton creation semantics and instances
and defines the way both can coexist.
The singleton CacheManager is a limitation of the specification.
(Alternatives: Some form of annotation and injection scheme)
Pending a final JSR107 implementation, the Ehcache configuration mechanism is used to create
JCaches from ehcache.xml config.
47.1.3.3 net.sf.jsr107cache.Cache
• The spec is silent on whether a Cache can be used in the absence of a CacheManager. Requiring
a CacheManager makes a central place where concerns affecting all caches can be managed, not
just a way of looking them up. For example, configuration for persistence and distribution.
• Cache does not have a lifecycle. There is no startup and no shutdown. There is no way, other
than a shutdown hook, to free resources or perform persistence operations. Once again this will
not work for redeployment of applications in an app server.
• There is no mechanism for creating a new cache from a default configuration such as a public
void registerCache(String cacheName) on CacheManager. This feature is considered
indispensable by frameworks such as Hibernate.
• Cache does not have a getName() method. A cache has a name; that is how it is retrieved from
the CacheManager. But it does not know its own name. This forces API users to keep track of
the name themselves for reporting exceptions and log messages.
• Cache does not support setting a TTL override on a put. e.g. put(Object key, Object
value, long timeToLive). This is a useful feature.
• The spec is silent on whether the cache accepts null keys and elements. Ehcache allows all
implementations. i.e.
cache.put(null, null);
assertNull(cache.get(null));
cache.put(null, "value");
assertEquals("value", cache.get(null));
cache.put("key", null);
assertEquals(null, cache.get("key"));
null is effectively a valid key. However because null id not an instance of Serializable
null-keyed entries will be limited to in-process memory.
• The load(Object key), loadAll(Collection keys) and getAll(Collection
collection) methods specify in the javadoc that they should be asynchronous. Now, most
load methods work off a database or some other relatively slow resource (otherwise there would
be no need to have a cache in the first place).
To avoid running out of threads, these load requests need to be queued and use a finite number
of threads. The Ehcache implementation does that. However, due to the lack of lifecycle
management, there is no immediate way to free resources such as thread pools.
• The load method ignores a request if the element is already loaded in for that key.
• get and getAll are inconsistent. getAll throws CacheException, but get does not. They both
should.
/**
* Returns a collection view of the values contained in this map. The
* collection is backed by the map, so changes to the map are reflected in
* the collection, and vice-versa. If the map is modified while an
* iteration over the collection is in progress (except through the
* iterator's own <tt>remove</tt> operation), the results of the
* iteration are undefined. The collection supports element removal,
* which removes the corresponding mapping from the map, via the
* <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
* <tt>removeAll</tt>, <tt>retainAll</tt> and <tt>clear</
tt> operations.
* It does not support the add or <tt>addAll</tt> operations.
* <p/>
*
* @return a collection view of the values contained in this map.
*/
public Collection values() {
It is not practical or desirable to support this contract. Ehcache has multiple maps for storage of
elements so there is no single backing map. Allowing changes to propagate from a change in
the collection maps would break the public interface of the cache and introduce subtle threading
issues.
The Ehcache implementation returns a new collection which is not connected to internal
structures in ehcache.
47.1.3.4 net.sf.jsr107cache.CacheEntry
• getHits() returns int. It should return long because production cache systems have entries hit
more than Integer.MAX_VALUE times.
Once you get to Integer.MAX_VALUE the counter rolls over. See the following test:
@Test public void testIntOverflow() {
long value = Integer.MAX_VALUE;
value += Integer.MAX_VALUE;
value += 5;
LOG.info("" + value);
int valueAsInt = (int) value;
LOG.info("" + valueAsInt);
assertEquals(3, valueAsInt);
}
• getCost() requirs the CacheEntry to know where it is. If it is in a DiskStore then its cost of
retrieval could be higher than if it is in heap memory. Ehcache elements do not have this concept,
and it is not implemented. i.e. getCost always returns 0. Also, if it is in the DiskStore, when you
retrieve it is in then in the MemoryStore and its retrieval cost is a lot lower. I do not see the point
of this method.
• getLastUpdateTime() is the time the last "update was made". JCACHE does not support
updates, only puts
47.1.3.5 net.sf.jsr107cache.CacheStatistics
• getObjectCount() is a strange name. How about getSize()? If a cache entry is an object graph
each entry will have more than one "object" in it. But the cache size is what is really meant, so
why not call it that?
• Once again getCacheHits and getCacheMisses should be longs.
public interface CacheStatistics {
public static final int STATISTICS_ACCURACY_NONE = 0;
public static final int STATISTICS_ACCURACY_BEST_EFFORT = 1;
public static final int STATISTICS_ACCURACY_GUARANTEED = 2;
public int getStatisticsAccuracy();
public int getObjectCount();
public int getCacheHits();
public int getCacheMisses();
public void clearStatistics();
• There is a getStatisticsAccuracy() method but not a corresponding setStatisticsAccuracy
method on Cache, so that you can alter the accuracy of the Statistics returned.
Ehcache supports this behaviour.
• There is no method to estimate memory use of a cache. Ehcache serializes each Element to a
byte[] one at a time and adds the serialized sizes up. Not perfect but better than nothing and
works on older JDKs.
• CacheStatistics is obtained using cache.getCacheStatistics() It then has getters for
values. In this way it feels like a value object. The Ehcache implementation is Serializable so that
it can act as a DTO. However it also has a clearStatistics() method. This method clear counters
on the Cache. Clearly CacheStatistics must hold a reference to Cache to enable this to happen.
But what if you are really using it as a value object and have serialized it? The Ehcache
implementation marks the Cache reference as transient. If clearStatistics() is called when the
cache reference is no longer there, an IllegalStateException is thrown.
A much better solution would be to move clearStatistics() to Cache.
47.1.3.6 net.sf.jsr107cache.CacheListener
/**
* Interface describing various events that can happen as elements are added to
* or removed from a cache
*/
public interface CacheListener {
/
** Triggered when a cache mapping is created due to the cache loader being consulted */
public void onLoad(Object key);
/
** Triggered when a cache mapping is created due to calling Cache.put() */
public void onPut(Object key);
/** Triggered when a cache mapping is removed due to eviction */
• Listeners often need not just the key, but the cache Entry itself. This listener interface is
extremely limiting.
• There is no onUpdate notification method. These are mapped to JCACHE's onPut notification.
• There is no onExpired notification method. These are mapped to JCACHE's onEvict notification.
47.1.3.7 net.sf.jsr107cache.CacheLoader
• JCache can store null values against a key. In this case, on JCache# get or getAll should an
implementation attempt to load these values again? They might have been null in the system
the CacheLoader loads from, but now aren't. The Ehcache implementation will still return nulls,
which is probably the correct behaviour. This point should be clarified.
47.1.4.1 JMX
JSR107 is silent on JMX which has been included in the JDK since 1.5.
49 FAQ
.......................................................................................................................................
49.1.2 Can you use more than one instance of Ehcache in a single VM?
As of ehcache-1.2, yes. Create your CacheManager using new CacheManager(...) and keep hold of
the reference. The singleton approach accessible with the getInstance(...) method is still available too.
Remember that Ehcache can supports hundreds of caches within one CacheManager. You would use
separate CacheManagers where you want quite different configurations.
The Hibernate EhCacheProvider has also been updated to support this behaviour.
49.1.3 Can you use Ehcache with Hibernate and outside of Hibernate at the same time?
Yes. You use 1 instance of Ehcache and 1 ehcache.xml. You configure your caches with Hibernate
names for use by Hibernate. You can have other caches which you interact with directly outside of
Hibernate.
That is how I use Ehcache in the original project it was developed in. For Hibernate we have about 80
Domain Object caches, 10 StandardQueryCaches, 15 Domain Object Collection caches.
We have around 5 general caches we interact with directly using BlockingCacheManager. We have
15 general caches we interact with directly using SelfPopulatingCacheManager. You can use one of
those or you can just use CacheManager directly.
I have updated the documentation extensively over the last few days. Check it out and let me know
if you have any questions. See the tests for example code on using the caches directly. Look at
CacheManagerTest, CacheTest and SelfPopulatingCacheTest.
49.1.4 What happens when maxElementsInMemory is reached? Are the oldest items are expired
when new ones come in?
When the maximum number of elements in memory is reached, the least recently used ("LRU")
element is removed. Used in this case means inserted with a put or accessed with a get.
If the overflowToDisk cache attribute is false, the LRU Element is discarded. If true, it is transferred
asynchronously to the DiskStore.
49.1.5 Is it thread safe to modify Element values after retrieval from a Cache?
Remember that a value in a cache element is globally accessible from multiple threads. It is inherently
not thread safe to modify the value. It is safer to retrieve a value, delete the cache element and then
reinsert the value.
The UpdatingCacheEntryFactory does work by modifying the contents of values in place in the
cache. This is outside of the core of Ehcache and is targeted at high performance CacheEntryFactories
for SelfPopulatingCaches.
49.1.7 Why is there an expiry thread for the DiskStore but not for the MemoryStore?
Because the memory store has a fixed maximum number of elements, it will have a maximum
memory use equal to the number of elements * the average size. When an element is added beyond
the maximum size, the LRU element gets pushed into the DiskStore.
While we could have an expiry thread to expire elements periodically, it is far more efficient to only
check when we need to. The tradeoff is higher average memory use.
The expiry thread keeps the disk store clean. There is hopefully less contention for the DiskStore's
locks because commonly used values are in the MemoryStore. We mount our DiskStore on Linux
using RAMFS so it is using OS memory. While we have more of this than the 2GB 32 bit process size
limit it is still an expensive resource. The DiskStore thread keeps it under control.
If you are concerned about cpu utilisation and locking in the DiskStore, you can set the
diskExpiryThreadIntervalSeconds to a high number - say 1 day. Or you can effectively turn it off by
setting the diskExpiryThreadIntervalSeconds to a very large value.
49.1.11 Where is the source code? The source code is distributed in the root directory of the
download.
It is called ehcache-x.x.zip. It is also available from SourceForge online or through SVN.
49.1.14 Do you need to call CacheManager.getInstance().shutdown() when you finish with ehcache?
Yes, it is recommended. If the JVM keeps running after you stop using ehcache, you should call
CacheManager.getInstance().shutdown() so that the threads are stopped and cache memory released
back to the JVM. Calling shutdown also insures that your persistent disk stores get written to disk in a
consistent state and will be usable the next time they are used.
If the CacheManager does not get shutdown it should not be a problem. There is a shutdown hook
which calls the shutdown on JVM exit. This is explained in the documentation here.
49.1.16 I have created a new cache and its status is STATUS_UNINITIALISED. How do I initialise it?
You need to add a newly created cache to a CacheManager before it gets intialised. Use code like the
following:
CacheManager manager = CacheManager.create();
Cache myCache = new Cache("testDiskOnly", 0, true, false, 5, 2);
manager.addCache(myCache);
49.1.23 Why can't I run multiple applications using Ehcache on one machine?
Because of an RMI bug, in JDKs before JDK1.5 such as JDK1.4.2, Ehcache is limited
to one CacheManager operating in distributed mode per virtual machine. (The bug limits
the number of RMI registries to one per virtual machine). Because this is the expected
deployment configuration, however, there should be no practical effect. The tell tail error is
java.rmi.server.ExportException: internal error: ObjID already in use
On JDK1.5 and higher it is possible to have multiple CacheManagers per VM each participating in the
same or different clusters. Indeed the replication tests do this with 5 CacheManagers on the same VM
all run from JUnit.
49.1.24 How many threads does Ehcache use, and how much memory does that consume?
The amount of memory consumed per thread is determined by the Stack Size. This is set using -Xss.
The amount varies by OS. It is 512KB for Linux. I tend to override the default and set it to 100kb.
The threads are created per cache as follows:
• DiskStore expiry thread - if DiskStore is used
• DiskStore spool thread - if DiskStore is used
• Replication thread - if asynchronous replication is configured.
If you are not doing any of the above, no extra threads are created
49.1.25 I am using Tomcat 5, 5.5 or 6 and I am having a problem. What can I do?
Tomcat is such a common deployment option for applications using Ehcache that there is a chapter on
known issues and recommended practices.
See the Using Ehcache with Tomcat chapter. ( http://ehcache.org/documentation/tomcat.html)
49.1.26 I am using Java 6 and getting a java.lang.VerifyError on the Backport Concurrent classes.
Why?
The backport-concurrent library is used in Ehcache to provide java.util.concurrency facilities for Java
4 - Java 6. Use either the Java 4 version which is compatible with Java 4-6 or use the version for your
JDK.
49.1.27 How do I get a memory only cache to persist to disk between VM restarts?
While disk persistence between restarts is a feature of the DiskStore only, you can get the same
behaviour for a memory only cache by setting up a cache with maxElementsInMemory set to
Integer.MAX_VALUE, 2147483647 and diskPersistent set to true.
You can manually call flush() to flush to disk. It is a good idea to set clearOnFlush to false so that
the MemoryStore is not cleared each time. You can then call flush() to persist whenever you wish.
49.1.28 I get a javax.servlet.ServletException: Could not initialise servlet filter when using
SimplePageCachingFilter. Why?
If you use this default implementation, the cache name is called "SimplePageCachingFilter". You
need to define a cache with that name in ehcache.xml. If you override CachingFilter you are required
to set your own cache name.
49.1.30 How do I add a CacheReplicator to a cache that already exists? The cache event listening
works but it does not get plumbed into the peering mechanism.
The current API does not have a CacheManager event for cache configuration change. You can
however make it work by calling the notifyCacheAdded event.
getCache().getCacheManager().getCacheManagerEventListenerRegistry()
.notifyCacheAdded("cacheName");
49.1.31 I am using the RemoteDebugger to monitor cluster messages but all I see is "Cache size: 0"
If you see nothing happening, but cache operations should be going through, enable trace (LOG4J) or
finest (JDK) level logging on codenet.sf.ehcache.distribution /code in the logging configuration being
used by the debugger. A large volume of log messages will appear. The normal problem is that the
CacheManager has not joined the cluster. Look for the list of cache peers.
Finally, the debugger in ehcache-1.5 has been improved to provide far more information on the caches
that are replicated and events which are occurring.
49.1.32 With distributed replication on Ubuntu or Debian, I see the following warning,
WARN [Replication Thread] RMIAsynchronousCacheReplicator.flushReplicationQueue(324)
| Unable to send message to remote peer.
Message was: Connection refused to host: 127.0.0.1; nested exception is:
java.net.ConnectException: Connection refused
java.rmi.ConnectException: Connection refused to host: 127.0.0.1; nested exception is:
java.net.ConnectException: Connection refused
This is caused by a 2008 change to the Ubuntu/Debian linux default network configuration.
Essentially, this java call: InetAddress.getLocalHost(); always returns the loopback address,
which is 127.0.0.1. Why? Because in these recent distros, a system call of $ hostname always returns
an address mapped onto the loopback device. Which causes ehcache's RMI Peer creation logic to
always assign the loopback address, which causes the error you are seeing.
All you need to do is crack open the network config and make sure that the hostname of the machine
returns a valid network address accessible by other peers on the network.
49.1.33 I see log messages about SoftReferences. What are these about and how do I stop getting
the messages?
Ehcache uses SoftReferences with asynchronous RMI based replication, so that replicating caches
do not run out of memory if the network is interrupted. Elements scheduled for replication will be
collected instead. If this is happening, you will see warning messages from the replicator. It is also
possible that a SoftReference can be reclaimed during the sending in which case you will see a debug
level message in the receiving CachePeer.
Some things you can do to fix them:
• Set -Xms equal to -Xms. SoftReferences are also reclaimed in preference to increasing the heap
size, which is a problem when an application is warming up.
• Set the -Xmx to a high enough value so that SoftReferences do not get reclaimed.
Having done the above, SoftReferences will then only be reclaimed if there is some interruption
to replication and the message queue gets dangerously high.
49.1.34 My Hibernate Query caches entries are replicating but the other caches in the cluster are
not using them.
This is a Hibernate 3 bug. See http://opensource.atlassian.com/projects/hibernate/browse/HHH-3392
for tracking. It is fixed in 3.3.0.CR2 which was released in July 2008.
49.1.38 Why does Ehcache 1.6 use more memory than 1.5?
ConcurrentHashMap does not provide an eviction mechanism. We add that ourselves. For caches
larger than 5000 elements, we create an extra ArrayList equal to the size of the cache which holds
keys. This can be an issue with larger keys. An optimisation which cache clients can use is:
http://www.codeinstructions.com/2008/09/instance-pools-with-
weakhashmap.html
To reduce the number of key instances in memory to just one per logical
key, all puts to the underlying ConcurrentHashMap could be replaced by
map.put(pool.replace(key), value), as well as keyArray.set(index,
pool.replace(key))
You can take this approach when producing the keys before handing them over to EhCac
Even with this approach there is still some added overhead consumed by a reference consumed by
each ArrayList element.
Update: Ehcache 2.0 will introduce a new implementation for MemoryStore based on a custom
ConcurrentHashMap. This version provides fast iteration and does away with the need for
the keyArray thus bringing memory use back down to pre 1.6 levels. And with other memory
optimisations made to Element in 1.7, memory use will actually be considerably lower than pre 1.6
levels.
49.1.39 What does this mean? "Caches cannot be added by name when default cache config is not
specified in the config. Please add a default cache config in the configuration."
From Ehcache 2.4, we have made the defaultCache optional. When you try to add a cache by
name, CacheManager.add(String name),