JBoss.orgCommunity Documentation
Eviction controls JBoss Cache's memory management by restricting how many nodes are allowed to be stored in memory, and for how long. Memory constraints on servers mean caches cannot grow indefinitely, so eviction needs to occur to prevent out of memory errors. Eviction is most often used alongside cache loaders.
Eviction in JBoss Cache is designed around four concepts:
In addition, Regions play a key role in eviction, as eviction is always configured on a per-region basis so that different subtrees in the cache can have different eviction characteristics.
This is done on the caller's thread whenever anyone interacts with the cache. If eviction is enabled, an
EvictionInterceptor
is added to the interceptor chain and events are recorded in an
event queue. Events are denoted by the EvictionEvent
class. Event queues are held on
specific Regions so each region has its own event queue.
This aspect of eviction is not configurable, except that the EvictionInterceptor
is either
added to the interceptor chain or not, depending on whether eviction is enabled.
An EvictionAlgorithm
implementation processes the eviction queue to decide which nodes to
evict. JBoss Cache ships with a number of implementations, including FIFOAlgorithm
,
LRUAlgorithm
, LFUAlgorithm
, etc. Each implementation has a corresponding
EvictionAlgorithmConfig
implementation with configuration details for the algorithm.
Custom EvictionAlgorithm
implementations can be provided by implementing the interface
or extending one of the provided implementations.
Algorithms are executed by calling its process()
method and passing in the event queue to
process. This is typically done by calling Region.processEvictionQueues()
, which will
locate the Algorithm assigned to the region.
Once the EvictionAlgorithm
decides which nodes to evict, it uses an implementation of
EvictionActionPolicy
to determine how to evict nodes. This is configurable on a per-region
basis, and defaults to DefaultEvictionActionPolicy
, which invokes Cache.evict()
for each node that needs to be evicted.
JBoss Cache also ships with RemoveOnEvictActionPolicy
, which calls Cache.removeNode()
for each node that needs to be evicted, instead of Cache.evict()
.
Custom EvictionActionPolicy
implementations can be used as well.
By default, a single cache-wide eviction thread is used to periodically iterate through registered regions
and call Region.processEvictionQueues()
on each region. The frequency with which this
thread runs can be configured using the wakeUpInterval
attribute in the eviction
configuration element, and defaults to 5000 milliseconds if not specified.
The eviction thread can be disabled by setting wakeUpInterval
to 0
.
This can be useful if you have your own periodic maintenance thread running and would like to iterate through
regions and call Region.processEvictionQueues()
yourself.
The concept of regions and the Region
class were
visited earlier when talking about marshalling. Regions are also
used to define the eviction behavior for nodes within that region. In addition to using a region-specific
configuration, you can also configure default, cache-wide eviction behavior for nodes that do not fall into
predefined regions or if you do not wish to define specific regions. It is important to note that when
defining regions using the configuration XML file, all elements of the Fqn
that defines
the region are String
objects.
For each region, you can define eviction parameters.
It's possible to define regions that overlap. In other words, one region can be defined for
/a/b/c
, and another defined for /a/b/c/d
(which is just the
d subtree of the /a/b/c
sub-tree).
The algorithm, in order to handle scenarios like this consistently, will always choose the first region
it encounters. In this way, if the algorithm needed to decide how to handle node
/a/b/c/d/e
, it would start from there and work
its way up the tree until it hits the first defined region - in this case
/a/b/c/d
.
Nodes marked as resident (using
Node.setResident()
API) will be ignored by the eviction policies both when checking whether to trigger
the eviction and when proceeding with the actual eviction of nodes. E.g. if a region is configured to have a
maximum of 10 nodes, resident nodes won't be
counted when deciding whether to evict nodes in that region. In addition, resident nodes will not be
considered for eviction when the region's eviction
threshold is reached.
In order to mark a node as resident the
Node.setResident()
API should be used. By default, the newly created nodes are not resident.
The
resident
attribute of a node is neither replicated, persisted nor transaction-aware.
A sample use case for resident nodes would be ensuring "path" nodes don't add "noise" to an eviction policy. E.g.,:
...
Map lotsOfData = generateData();
cache.put("/a/b/c", lotsOfData);
cache.getRoot().getChild("/a").setResident(true);
cache.getRoot().getChild("/a/b").setResident(true);
...
In this example, the nodes
/a
and
/a/b
are paths which exist solely to
support the existence of node
/a/b/c
and don't hold any data themselves. As such, they are
good candidates for being marked as resident. This would lead to better memory management as no eviction
events would be
generated when accessing
/a
and/a/b
.
N.B. when adding attributes to a resident node, e.g.
cache.put("/a", "k", "v")
in the above example, it would make sense to mark the nodes
as non-resident again and let them be considered for eviction..
The basic eviction configuration element looks like:
...
<eviction wakeUpInterval="500" eventQueueSize="100000">
<default algorithmClass="org.jboss.cache.eviction.LRUAlgorithm">
<property name="maxNodes" value="5000" />
<property name="timeToLive" value="1000" />
</default>
</eviction>
...
wakeUpInterval
- this required parameter defines how often the eviction thread runs, in milliseconds.
eventQueueSize
- this optional parameter defines the size of the bounded queue which holds eviction events. If your
eviction thread does not run often enough, you may find that the event queue fills up. It may then be
necessary to get your eviction thread to run more frequently, or increase the size of your event queue.
This configuration is just the default event queue size, and can be overridden
in specific eviction regions. If not specified, this defaults to 200000
.
algorithmClass
- this is required, unless you set individual algorithmClass
attributes on each and every region. This
defines the default eviction algorithm to use if one is not defined for a region.
algorithmClass
.
See the section specific to the algorithm you are interested in for details.
Configuring eviction using the
Configuration
object entails the use of the
org.jboss.cache.config.EvictionConfig
bean, which is passed into
Configuration.setEvictionConfig()
. See the
chapter on Configuration
for more on building a
Configuration
programatically.
The use of simple POJO beans to represent all elements in a
cache's configuration also makes it fairly easy to programatically
add eviction regions after the cache is started. For example,
assume we had an existing cache configured via XML with the
EvictionConfig element shown above. Now at runtime we wished to
add a new eviction region named "/org/jboss/fifo", using
LRUAlgorithm
but a different number of
maxNodes
:
Fqn fqn = Fqn.fromString("/org/jboss/fifo");
// Create a configuration for an LRUPolicy
LRUAlgorithmConfig lruc = new LRUAlgorithmConfig();
lruc.setMaxNodes(10000);
// Create an eviction region config
EvictionRegionConfig erc = new EvictionRegionConfig(fqn, lruc);
// Create the region and set the config
Region region = cache.getRegion(fqn, true);
region.setEvictionRegionConfig(erc);
org.jboss.cache.eviction.LRUAlgorithm
controls both the node lifetime and age. This policy guarantees a constant order (
O (1)
) for
adds, removals and lookups (visits). It has the following configuration
parameters:
maxNodes
- This is the maximum number of nodes allowed in this region. 0 denotes immediate expiry, -1 denotes no limit.
timeToLive
- The amount of time a node is not written to or read (in milliseconds) before the node is swept away. 0
denotes immediate expiry, -1 denotes no limit.
maxAge
- Lifespan of a node (in milliseconds) regardless of idle time before the node is swept away. 0
denotes immediate expiry, -1 denotes no limit.
minTimeToLive
- the minimum amount of time a node must be allowed to live after being accessed before it is allowed to
be considered for eviction. 0 denotes that this feature is disabled, which is the default value.
org.jboss.cache.eviction.FIFOAlgorithm
controls the eviction in a proper first in first out order. This policy
guarantees a constant order (
O (1)
) for adds, removals and lookups (visits). It has the
following configuration parameters:
maxNodes
- This is the maximum number of nodes allowed in this region. 0 denotes immediate expiry, -1 denotes no limit.
minTimeToLive
- the minimum amount of time a node must be allowed to live after being accessed before it is allowed to
be considered for eviction. 0 denotes that this feature is disabled, which is the default value.
org.jboss.cache.eviction.MRUAlgorithm
controls
the eviction in based on most recently used algorithm. The most recently
used nodes will be the first to evict with this policy. This policy
guarantees a constant order (
O (1)
) for adds, removals and lookups (visits). It has the
following configuration parameters:
maxNodes
- This is the maximum number of nodes allowed in this region. 0
denotes immediate expiry, -1 denotes no limit.
minTimeToLive
- the minimum amount of time a node must be allowed to live after being accessed before it is allowed to
be considered for eviction. 0 denotes that this feature is disabled, which is the default value.
org.jboss.cache.eviction.LFUAlgorithm
controls
the eviction in based on least frequently used algorithm. The least
frequently used nodes will be the first to evict with this policy. Node
usage starts at 1 when a node is first added. Each time it is visited,
the node usage counter increments by 1. This number is used to determine
which nodes are least frequently used. LFU is also a sorted eviction
algorithm. The underlying EvictionQueue implementation and algorithm is
sorted in ascending order of the node visits counter. This class
guarantees a constant order (
O (1)
) for adds, removal and searches. However, when any
number of nodes are added/visited to the queue for a given processing
pass, a single quasilinear (
O (n * log n)
) operation is used to resort the queue in
proper LFU order. Similarly if any nodes are removed or evicted, a
single linear (
O (n)
) pruning operation is necessary to clean up the
EvictionQueue. LFU has the following configuration parameters:
maxNodes
- This is the maximum number of nodes allowed in this region. 0
denotes immediate expiry, -1 denotes no limit.
minNodes
- This is the minimum number of nodes allowed in this region. This value determines what
the eviction queue should prune down to per pass. e.g. If
minNodes is 10 and the cache grows to 100 nodes, the cache is
pruned down to the 10 most frequently used nodes when the
eviction timer makes a pass through the eviction
algorithm.
minTimeToLive
- the minimum amount of time a node must be allowed to live after being accessed before it is allowed to
be considered for eviction. 0 denotes that this feature is disabled, which is the default value.
org.jboss.cache.eviction.ExpirationAlgorithm
is a policy
that evicts nodes based on an absolute expiration time. The
expiration time is indicated using the
org.jboss.cache.Node.put()
method, using a String key
expiration
and the absolute time as a
java.lang.Long
object, with a value indicated as milliseconds past midnight
January 1st, 1970 UTC (the same relative time as provided by
java.lang.System.currentTimeMillis()
).
This policy guarantees a constant order (
O (1)
) for adds and removals.
Internally, a sorted set (TreeSet) containing the expiration
time and Fqn of the nodes is stored, which essentially
functions as a heap.
This policy has the following configuration parameters:
expirationKeyName
- This is the Node key name used
in the eviction algorithm. The configuration default is
expiration
.
maxNodes
- This is the maximum number of nodes allowed in this region. 0
denotes immediate expiry, -1 denotes no limit.
The following listing shows how the expiration date is indicated and how the policy is applied:
Cache cache = DefaultCacheFactory.createCache();
Fqn fqn1 = Fqn.fromString("/node/1");
Long future = new Long(System.currentTimeMillis() + 2000);
// sets the expiry time for a node
cache.getRoot().addChild(fqn1).put(ExpirationConfiguration.EXPIRATION_KEY, future);
assertTrue(cache.getRoot().hasChild(fqn1));
Thread.sleep(5000);
// after 5 seconds, expiration completes
assertFalse(cache.getRoot().hasChild(fqn1));
Note that the expiration time of nodes is only checked when the
region manager wakes up every
wakeUpIntervalSeconds
, so eviction
may happen a few seconds later than indicated.
org.jboss.cache.eviction.ElementSizeAlgorithm
controls
the eviction in based on the number of key/value pairs in the node. Nodes The most recently
used nodes will be the first to evict with this policy. It has the following configuration parameters:
maxNodes
- This is the maximum number of nodes allowed in this region. 0
denotes immediate expiry, -1 denotes no limit.
maxElementsPerNode
- This is the trigger number of attributes per node for the node to be selected for eviction. 0
denotes immediate expiry, -1 denotes no limit.
minTimeToLive
- the minimum amount of time a node must be allowed to live after being accessed before it is allowed to
be considered for eviction. 0 denotes that this feature is disabled, which is the default value.