6. Caching using Apache Geode or Pivotal GemFire

One of the quickest and easiest ways to get started using Apache Geode or Pivotal GemFire in your Spring Boot applications is to use either Apache Geode or Pivotal GemFire as a caching provider in Spring’s Cache Abstraction. SDG enables Apache Geode/Pivotal GemFire as a caching provider in Spring’s Cache Abstraction.

[Tip]Tip

See the Spring Data for Apache Geode Reference Guide for more details on the support and configuration of Apache Geode or Pivotal GemFire as a caching provider in Spring’s Cache Abstraction.

Indeed, caching can be an effective software design pattern to avoid the cost of invoking a potentially expensive operation when, given the same input, the operation yields the same output every time. Make sure you fully understanding the concepts behind Spring’s Cache Abstraction before you continue.

You can also refer to the relevant section on Caching in Spring Boot’s Reference Guide. Spring Boot even provides auto-configuration support for a few, simple caching providers out-of-the-box.

However, if you need the proven power of an enterprise-class caching solution, with strong consistency, high availability and multi-site (WAN) capabilities, then you should consider Apache Geode or Pivotal GemFire. Additionally, Pivotal Software, Inc. offers Pivotal GemFire as a service, known as Pivotal Cloud Cache (PCC), when deploying and running your Spring Boot applications in Pivotal Cloud Foundry (PCF).

Spring’s declarative, annotation-based caching makes it easy to get started with caching, which is as simple as annotating your application service components with the appropriate annotation.

[Tip]Tip

Spring’s declarative, annotation-based caching also supports JCache (JSR-107) annotations.

For example, suppose you want to cache the result for determining a person’s eligibility when applying for a financial loan:

@Service
class FinancialLoanApplicationService {

    @Cacheable("EligibilityDecisions", ...)
    EligibilityDecision processEligility(Person person, Timespan timespan) {
        ...
    }
}

When the FinancialLoanApplicationService.processEligibility(..) method is called, Spring’s caching infrastructure first consults the “EligibilityDecisions” cache to determine if a decision has already been computed for the given Person within the given span of time. If eligibility has already been determined, the the existing decision is returned from the cache, otherwise the processEligibility(..) method is invoked and the result is cached when the invocation returns.

Spring Boot for Apache Geode/Pivotal GemFire auto-configures Apache Geode or Pivotal GemFire as the caching provider when either one is declared on the application classpath, and when no other caching provider (e.g. Redis) has been configured.

If Spring Boot for Apache Geode/Pivotal GemFire detects that another cache provider has already been configured, then neither Apache Geode nor Pivotal GemFire will serve as the caching provider. This allows users to configure, e.g. Redis, or another store, as the caching provider, and to use Apache Geode or Pivotal GemFire as your application’s persistent store.

To configure the necessary cache Regions to back the caches declared in Spring cache annotations, this is as simple as using Spring Data for Apache Geode/Pivotal GemFire’s @EnableCachingDefinedRegions annotation.

The complete Spring Boot application looks like this:

package example.app;

import ...;

@SpringBootApplication
@EnableCachingDefinedRegions
class FinancialLoanApplication {

    public static void main(String[] args) {
        SpringApplication.run(FinancialLoanApplication.class, args);
    }
}
[Tip]Tip

The FinancialLoanApplicationService is picked up by Spring’s classpath component scan since this class is annotated with Spring’s @Service stereotype annotation.

6.1 Look-Aside Caching, Near Caching and Inline Caching

Three different types of caching strategies can be enabled with Spring when using Apace Geode or Pivotal GemFire for your application caching needs.

[Note]Note

Spring Boot for Apache Geode/Pivotal GemFire does not recognize and apply the spring.cache.cache-names property. Instead, you should use SDG’s @EnableCachingDefinedRegions on an appropriate Spring Boot application @Configuration class.

6.1.1 Look-Aside Caching

The caching pattern we demonstrated in the example above is a form of Look-Aside Caching.

Essentially, the item of interests is searched for in the cache first, before calling a potentially expensive operation, such a IO or network bound request resulting in either a blocking, or latency intensive operation. If the item can be found in the cache (usually, in-memory) then the item is returned without invoking the expensive operation. If the item cannot be found in the cache, then the operation must be invoked. However, the result of the operation is cached for subsequent requests when the the same input is provided.

6.1.2 Near Caching

Near Caching is another form of caching where the cache is collocated with the application. This is useful when the cache is configured using a client/server arrangement.

We already mentioned that Spring Boot for Apache Geode & Pivotal GemFire provides an auto-configured, ClientCache instance out-of-the-box, by default. The ClientCache instance is most effective when the data access operations, including cache access, is distributed to the servers in a cluster accessed by the client. This enables other cache client applications to access the same data. However, this also means that the application incurs a network hop penalty to evaluate the presence of the item in the cache.

To help avoid this network cost in a client/server topology, then a local application cache can be established to maintain a subset of the data in the corresponding server-side cache (known as a cache Region in GemFire/Geode), which contains only the data of interests to the application. This "local" cache is consulted before forwarding the lookup request to the server.

To enable Near Caching when using either Apache Geode or Pivotal GemFire, simply change the Region’s (i.e. the Cache in Spring’s Cache Abstraction) data management policy from PROXY (the default) to CACHING_PROXY, like so:

@SpringBootApplication
@EnableCachingDefinedRegions(clientRegionShortcut = ClientRegionShortcut.CACHING_PROXY)
class FinancialLoanApplication {

    public static void main(String[] args) {
        SpringApplication.run(FinancialLoanApplication.class, args);
    }
}
[Tip]Tip

The default, client Region data management policy is ClientRegionShortcut.PROXY. As such, all data access operations are immediately forwarded to the server.

6.1.3 Inline Caching

The final form of caching is Inline Caching.

When employing Inline Caching and a cache miss occurs, the application service method may still not be invoked since the cache (Region) can be configured to invoke a loader to load the missing entry.

With Apache Geode and Pivotal GemFire, the cache, or in GemFire/Geode terminology, Region, can be configured with a CacheLoader. This CacheLoader is implemented to retrieve the missing value from some external data source, which could be a RDBMS or any other type of data source.

[Tip]Tip

See the Apache Geode User Guide on Data Loaders for more details.

You can use Spring to configure a CacheLoader as a bean in the Spring ApplicationContext and then wire it to the cache Region. Given the CacheLoader is a Spring bean, you can inject any DataSource you like into the CacheLoader.

While you can configure client Regions with CacheLoaders, it is more common to configure the corresponding server-side Region; for example:

@SpringBootApplication
@CacheServerApplication
class FinancialLoanApplicationServer {

    public static void main(String[] args) {
        SpringApplication.run(FinancialLoanApplicationServer.class, args);
    }

	@Bean("EligibilityDecisions")
	public PartitionedRegionFactoryBean<Object, Object> eligibilityDecisionsRegion(
            GemFireCache gemfireCache, CacheLoader decisionManagementSystemLoader) {

        PartitionedRegionFactoryBean<?, EligibilityDecision> eligibilityDecisionsRegion =
            new PartitionedRegionFactoryBean<>();

        eligibilityDecisionsRegion.setCache(gemfireCache);
        eligibilityDecisionsRegion.setCacheLoader(decisionManagementSystemLoader);
        eligibilityDecisionsRegion.setClose(false);
        eligibilityDecisionsRegion.setPersistent(false);

        return eligibilityDecisionsRegion;
    }


    @Bean
    public CacheLoader<?, EligibilityDecision> decisionManagementSystemLoader(
            DataSource dataSource) {

        return new DecisionManagementSystemLoader(dataSource);
    }
}

If the configured CacheLoader still cannot resolve the value, the the cache lookup operation results in a miss and the application service method will then be invoked.

6.2 Advanced Caching Configuration

Both Apache Geode and Pivotal GemFire support additional caching capabilities to manage the entries stored in the cache.

As you can imagine, given the cache entries are stored in-memory, it becomes important to monitor and manage the available memory wisely. After all, by default, both Apache Geode and Pivotal GemFire store data on the JVM Heap.

Several techniques can be employed to more effectively manage memory, such as using Eviction, possibly overflowing to disk, configuring both entry Idle-Timeout (TTI) as well as Time-To-Live (TTL) Expiration policies, configuring Compression, and using Off-Heap, or main memory.

There are several other strategies that can be used as well, as described in Managing Heap and Off-heap Memory.

While this is well beyond the scope of this document, know that Spring Data for Apache Geode & Pivotal GemFire make all of these configuration options simple.

6.3 Disable Caching

There may be cases where you do not want your Spring Boot application to cache application state with Spring’s Cache Abstraction using either Apache Geode or Pivotal GemFire. In certain cases, you may be using another Spring supported caching provider, such as Redis, to cache and manage your application state, while, even in other cases, you may not want to use Spring’s Cache Abstraction at all.

Either way, you can specifically call out your Spring Cache Abstraction provider using the spring.cache.type property in application.properties, as follows:

Use Redis as the Spring Cache Abstraction Provider. 

#application.properties

spring.cache.type=redis
...

If you prefer not to use Spring’s Cache Abstraction to manage your Spring Boot application’s state at all, then do the following:

Disable Spring’s Cache Abstraction. 

#application.properties

spring.cache.type=none
...

See Spring Boot docs for more details.

[Tip]Tip

It is possible to include multiple providers on the classpath of your Spring Boot application. For instance, you might be using Redis to cache your application’s state while using either Apache Geode or Pivotal GemFire as your application’s persistent store (System of Record).

[Note]Note

Spring Boot does not properly recognize spring.cache.type=[gemfire|geode] even though Spring Boot for Apache Geode/Pivotal GemFire is setup to handle either of these property values (i.e. either “gemfire” or “geode”).