Cacheonix Web Cache

Table of Contents

Introduction

Caching improves application performance of web applications by serving dynamically generated content that changes infrequently from memory instead spending CPU and I/O time to generate or retrieve the content.

Cacheonix Web Cache is a server-side cache and is shipped as a servlet filter. Cacheonix caches the content that is dynamically generated by web applications such as JSP, Struts actions, images, JSON and XML responses. Cacheonix Web Cache further reduces the latency of the request-response cycle by minimizing the client traffic via automatic compression of text responses such as HTML and by supporting client-side cache headers. Cacheonix Web Cache is an integral part of Cacheonix and lives inside cacheonix.jar with the rest of Cacheonix API.

The diagram below shows the position of Cacheonix Web Cache relative to the rest of a web application:

Concepts

HTTP requests

A typical HTTP request that is processed by a web application consists of a request URI, request parameters, cookies, and request headers. Cacheonix uses the request URI, parameters and cookies as a key when caching a response.

HTTP responses

A web application responds to the HTTP request with a set of cookies and response headers and stream of bytes. A typical response stream generated by a web app contains an HTML page, an image, XML or JSON content. Cacheonix stores the responses generated by the web application in a cache. Cacheonix returns a cached response when it receives a request that contains already cached request URI, request parameters and cookies.

Web cache request filter

The main component of Cacheonix Web Cache is a servlet filter org.cacheonix.cache.web.RequestCacheFilter. A servlet filter is as a class implementing the standard Filter API as defined by the Servlets specification. Servlet filters are configured in the main web application configuration file, web.xml. Filters work as request pre-processors. Servlet containers such as Tomcat or Jetty, also known as web application servers, call servlet filters in a chained manner before the web application servlet, also known as an endpoint servlet, get a chance to process the request and generate a response. The order of execution is defined by the order of filter appearance in the web.xml.

The diagram below shows filter's flow of execution:

Caching dynamic content

Caching improves performance of a web application by serving the dynamic content from memory instead spending CPU time to generate the content or I/O time to retrieve the content from the file system or a database.

Generally speaking, the dynamic content doesn't exist at the time of a request and is generated by the web application using application logic. Examples of dynamics contents are HTML pages generated by JSPs, servlets and Struts applications, images and XML and JSON reponses to REST requests. Static content remains unchanged throughout the life of the web application and usually is served as files.

A good candidate for caching is the dynamic content that changes infrequently. Use cases may include login forms, product catalogs, and documentation pages. Another good example is REST API calls that return responses that don't change too often.

Configuration

Adding Cacheonix Web Cache to your web application consists of  adding Cacheonix Web Cache filter to your application's web.xml and configuring the filter mapping.

Minimal environment requirements

Minimal JDK version: 1.6.

Minimal Servlet API version: 2.3. 

Minimal servlet container:  Tomcat 7.0, Jetty 8.0, etc

Adding Cacheonix to Maven project

To add Cacheonix to your Maven build, add the following to the <dependencies> section of your pom.xml:

<dependency>
   <groupId>org.cacheonix</groupId>
   <artifactId>cacheonix-core</artifactId>
   <version>2.2.1</version>
</dependency>

Adding Cacheonix manually

Alternatively, cacheonix.jar can be downloaded directly from http://downloads.cacheonix.org.

Configuring servlet filter

To enable caching of the dynamic content in your application, add Cacheonix Web Cache filter to your web.xml and map the filter to the URL pattern:

<filter>
    <filter-name>CacheonixWebCache</filter-name>
    <filter-class>org.cacheonix.cache.web.RequestCacheFilter</filter-class>
</filter>

...

<filter-mapping>
       <filter-name>CacheonixWebCache</filter-name>
       <url-pattern>*.htm</url-pattern>
</filter-mapping>

Element filter-name maps Cacheonix Web Cache to a name CacheonixWebCache that will be used the when mapping the filter to the URL pattern.

Element url-pattern tells the servlet container that Cacheonix Web Cache will process all URIs with extension '.htm'

Order of filters

You web application may have many filters. The position of Cacheonix Web Cache filter in the sequence of filters is important. It's important to place Cacheonix Web Cache filter after the filters that make decisions whether to generate request output such as authentication filters, but before the filters that generate the actual content that must be cached such as Struts filters. The diagram below illustrates the position of the Cacheonix Web Cache filter:

Configuring url-pattern

According to the section 12.2 of the Servlet spec v.3.0:

"In the Web application deployment descriptor, the following syntax is used to define mappings:
• A string beginning with a '/' character and ending with a '/*' suffix is used for path mapping.
• A string beginning with a '*.' prefix is used as an extension mapping.
• The empty string ("") is a special URL pattern that exactly maps to the
application's context root, i.e., requests of the form http://host:port/<context- root>/. In this case the path info is '/' and the servlet path and context path is empty string ("").
• A string containing only the '/' character indicates the "default" servlet of the application. In this case the servlet path is the request URI minus the context path and the path info is null.
• All other strings are used for exact matches only"

It's quite a mouthful, so here are a few practical examples:

Caching all PDF responses:

<url-pattern>*.pdf</url-pattern>

Caching all semi-static content, assuming it's generated under /static/ path

<url-pattern>/static/*</url-pattern>

Caching a particular page:

<url-pattern>/product/catalog.htm</url-pattern>

Configuring web cache

Default cache configuration

The minimal configuration as described above will create a web cache using a default, built-in Cacheonix configuration template that is stored in cacheonix.jar's META-INF/cacheonix-config.xml. Cacheonix Web cache in the minimal configuration will create a local LRU cache with size of 10000 elements and maximum 10 Megabytes stored in memory.

Selecting cache size

The choice of the cache size depends on the size and the number of dynamically generated content that you would like to cache. For example, if your application produces 1000 cacheable HTML pages each 10Kb in size, then you may want to pick the cache size to be 10Mb to fit most of the pages. We recommend limiting the total size of all Cacheonix caches to be under 50% of the free JVM heap. See the following sections for the examples of setting the cache size and expiration.

Custom cache configuration

Cacheonix provides two configuration parameters that allow customizing Cacheonix Web Cache configuration, configurationPath and cacheName.

Parameter configurationPath allows setting a custom path to a Cacheonix configuration file. Cacheonix will use web application classpath to look for the Cacheonix configuration file.

Parameter cacheName allows setting a custom name of the cache that is going to hold cached requests. Cacheonix will use classpath to look for this path. You may want to use a custom name if you want to access Cacheonix Web Cache directly using cache API, for example, to reset the cache. The example below shows configuring a cache named MyCacheonixWebCache of 50 Mb in size.

Custom configuration example, web.xml:

<filter>
    <filter-name>Cacheonix Web Cache</filter-name>
    <filter-class> org.cacheonix.cache.web.RequestCacheFilter</filter-class>
    <init-param>
       <param-name>configurationPath</param-name>
       <param-value>cacheonix-config.xml</param-value>
    </init-param>
   <init-param>
       <param-name>cacheName</param-name>
       <param-value>MyCacheonixWebCache</param-value>
    </init-param>
</filter>

Custom configuration example, cacheonix-config.xml:

<?xml version ="1.0"?>
<cacheonix xsi:schemaLocation="http://www.cacheonix.org/schema/configuration http://www.cacheonix.org/schema/cacheonix-config-2.0.xsd"
        xmlns="http://www.cacheonix.org/schema/configuration"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

   <tempDir path="${java.io.tmpdir}"/>

   <local>
      <localCache name="MyCacheonixWebCache">
         <store>
            <lru maxBytes="50mb"/>
         </store>
      </localCache>
   </local>
</cacheonix>

Configuring cache expiration

Cache expiration is configured by adding element expiration to the store element. In the example below the cached requests will expire every hour (60 minutes):

<?xml version ="1.0"?>
<cacheonix xsi:schemaLocation="http://www.cacheonix.org/schema/configuration http://www.cacheonix.org/schema/cacheonix-config-2.0.xsd"
        xmlns="http://www.cacheonix.org/schema/configuration"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

   <tempDir path="${java.io.tmpdir}"/>

   <local>
      <localCache name="MyCacheonixWebCache">
         <store>
            <expiration timeToLive="60min"/>
            <lru maxBytes="50mb"/>
         </store>
      </localCache>
   </local>
</cacheonix>

Automatic gzip compression

Cacheonix further reduces response latency by automatically applying gzip compression to responses with text response types such as text/html. gzip compression helps to serve responses faster because compressed responses are smaller in size and take less time to write to the client. Cacheonix Web Cache applies gzip compression when the client declares that is supports gzip encoding. No additional configuration is needed to enable gzip compression.

Automatic client cache headers

In addition to caching requests in memory of the app server, Cacheonix enables client-side caching by adding the following headers to the response:

  • Cache-control,
  • Expires and
  • Last-modified.

In addition to this, Cacheonix supports request header If-Modified-Since and will further reduce client traffic by responding with status code 304 or SC_NOT_MODIFIED if If-Modified-Since is in the future. No additional configuration is needed to enable client cache headers.

About Cacheonix

Cacheonix is an open source project offering a JVM-local Java cache and a distributed, strictly consistent Java cache. Cacheonix helps organizations to scale Java applications horizontally by reducing or eliminating access to serialized resources such as transactional databases or file system. Distributed Cacheonix enables building clustered Java applications while maintaining simplicity of coding in a standalone JVM by offering a simple map and lock APIs that hide the complexity of distributed data management in a cluster.

Source code and contributing

You can access Cacheonix source code at https://github.com/cacheonix/cacheonix-core. We welcome contributors, so if you'd like to contribute, please send an e-mail to simeshev@cacheonix.org.

Roadmap 

Cacheonix team is working on the following features for Cacheonix web cache:

  • Gradle support
  • Sprint boot support

Resources

  1. Configuring Cacheonix
  2. Cacheonix Wiki
  3. Cacheonix at GitHub
  4. Understanding and Using Servlet Filters
  5. Servlet 3.0 Specification

Labels

 
(None)