Saturday, June 6, 2020

Improving performance and availability using OSB Result Caching


OSB Result Caching was introduced with 11g and provides a quick and easy way to configure caching of data. It's an in-memory data grid solution that could relieve back-end systems from the burden of high-volume calls. Other benefits are improvement of performance as retrieving data from cache means faster response time compared to calling external services and ensuring high-availability of data as it sits in cache even though back-end systems might be down.

All in all it's worth considering enabling caching on OSB, but a good caching strategy should be in place to prevent the pitfalls of memory issues, security risks and presenting outdated data. Some starting points to take into account:
-The services to be cached deal with high-volume calls and are synchronous.
-The data returned does not change and is static or it's easy to predict when it's going to change.
-The data returned is not business critical.
-The services to be cached do not implement some kind of security.


It's important to know that a distinction can be made between in-process and out-of-process caching. As an in-memory solution, results are cached in the JVM heap and when reaching the maximum heap size garbage collection kicks in and could lead to serious memory issues undermining performance, something you do not want. When using in-process caching, the cache resides in the OSB's heap. For small usage that should do fine but if OSB result caching features are seriously utilized, out-of-process caching using Coherence servers' own heaps is a far better choice.

For out-of-process caching one or multiple Coherence clusters can be set up with one or multiple Coherence servers targeted. I won't go into detail on how to do that in this blog, but I will touch upon the topics of:
1. Configuring the cache through the configuration file
2. OSB Result Caching via Business Service definition
3. OSB Result Caching via Pipeline
4. Cache entry invalidation 

1. Configuring the cache through the configuration file

The default cache configuration file osb-coherence-cache-config.xml can be found in resultcache.gar/META-INF. It's very easy to create a customized cache configuration. In order to do so you just need to create a copy of the file, make your customizations and add it to the Coherence cluster configuration:Please note that when you create the cache configuration the name should always be /osb/service/ResultCache and the JNDI Name should always be servicebus/result-cache. There can only be one active cache for OSB result caching. The Coherence and OSB servers need to be restarted when adding or changing the cache configuration.

Now, a custom cache configuration may look as follows:

<local-scheme>
  <scheme-name>expiring-backing-map</scheme-name>
  <eviction-policy>LFU</eviction-policy>
  <high-units>3500</high-units>
  <unit-calculator>BINARY</unit-calculator>
  <unit-factor>1048576</unit-factor> <!--1024*1024=1MB-->
  <expiry-delay>1d</expiry-delay>
</local-scheme>

So this is a basic setup of a cache. An eviction-policy is in place which evicts entries when the cache is starting to reach its max. The policy used is "Least Frequently Used" (LFU) meaning the entries that are the least frequently used are evicted first until the low watermark is reached again. Another policy could be "Least Recently Used" (LRU). The unit-factor is set to 1MB here, so that's the unit we're calculating against. Together with the high-units set to 3500 it means our cache has a capacity of 3500MB. By default the low-units are set to 80% of the high-units, so when eviction kicks in the cache prunes itself back to the low watermark. The expiry-delay is set to 1 day, meaning entries in cache expire after 1 day. This is a default and can be overridden by the settings on the Business Service as we will see.

For more information on size limitation, please take a look at this Oracle Doc: https://docs.oracle.com/middleware/1212/coherence/COHDG/cache_config.htm#COHDG5217

2. OSB Result Caching via Business Service definition
Result caching for an external service is enabled by checking the 'Result Caching Support' box via the tab 'Performance' in the Business Service Defnition. An important condition is that result caching is enabled in the global settings of OSB, this is done via the Enterprise Manager.

Two concepts are important here, the cache token and expiration time, or the time-to-live (TTL).
The cache token acts as the key for the entry in cache and is used to retrieve the data. Together with the service reference and operation it provides a unique identification to gather the right entry from cache. The cache token could for example be an employee, customer or product ID. The identifier must reside in $body, $header, $operation or $transportMetaData and should resolve to a String, attribute or element without child-elements. Invalid expressions cause data not being stored in cache. Use pipeline configuration for more complex tokens.
The expiration time sets the validity for an entry. After expiration the cache will be updated with a new entry, the response from the first request made to the external service after expiration time. By default the value of expiry-delay is taken from the configuration file. The duration set via the Business Service Definition overrides the default value. The duration set via pipeline, as we will see later, overrides the setting in the Business Service Definition on its turn.

 
So let's see how we can test result caching after configuration.
When we call the external service we can check the Response Metadata. If all is configured well, two extra properties are visible: cache-token (which could for example be a customer ID in String value) and cache-originated which tells us whether the entry was retrieved from cache or not. So the very first call should have a value 'false', but the next call being made within the duration of the configured expiration time, it should return 'true'. There are factors though that could cause entries to be invalidated before their expiration time as we will see later under '4. Cache entry invalidation'.



3. OSB Result Caching via Pipeline
An alternative to configuration via Business Service Definition is configuration via pipeline. It gives us more possibilities to do more complex configurations, for example conditional caching and caching on multiple operations.

Two elements are relevant here:

$outbound/ctx:transport/ctx:request/tp:cache-token
$outbound/ctx:transport/ctx:request/tp:cache-ttl


These are set in the routing to the Business Service in the route-node of the pipeline. What we see below is an if-then construct. As not all operations should have caching a few conditions are tested, for example, if $operation = 'getCustomerInfo'. Next, using two inserts the values for cache-ttl and cache-token are set. In the example below the cache-ttl is set to 86400 seconds, or 24 hours. The value must always be in seconds.



Next we configure the cache-token. If you would need multiple elements from the request to be the token, you could do something like the following.



Please note that the 'Result Caching Support' box via the tab 'Performance' in the Business Service Defnition still needs to be checked in order for caching to work.

Using pipeline testing we can check what this did for our result cache settings:
 

Checking $outbound/transport/request we can see the cache-token used and the cache-ttl that we set. In the response we see the cache-token and the cache-originated property.

4. Cache entry invalidation
Cache entries can be invalidated or flushed in several ways. It's important to understand that the cache is an in-memory solution. So upon restart of your Coherence server the cache is flushed. In 12.2.1 the feature Coherence Persistence was introduced allowing data to be persisted on-disk; this requires additional installations and configuration so snapshots of cache(s) can be made.

Invalidation occurs:
-The time-to-live has expired. The entry will be invalidated and replaced with the response of the next call done to the external service.
-Disabling result caching in the Business Service by unchecking 'Result Caching Support'. All entries of this particular Business Service are flushed from cache. Same happens when this is done via the Enterprise Manager.
-The Business Service is updated, renamed or deleted. All entries are flushed from cache.
-A resource that has a dependency with the Business Service, for example a WSDL, is updated. All entries from the Business Service are flushed.
-Result Caching is disabled globally through the Enterprise manager. The whole cache is flushed and becomes unavailable.


Concluding
A cache summary is available though the Enterprise Manger. The dashboards shows the number of objects in cache and memory used amongst others.


This was a short introduction on OSB Result Caching and how to use it to improve performance and availability of data. Hope it helped!