Cache scope and Object Store in Mule 4
- February 14, 2020
Before learning about cache scope and Object Store in Mule 4, we need to understand general caching.
What does caching mean?
Caching (pronounced cashing) is the process of storing frequently used data in memory, file system or database, which saves processing time and load if it would have to be accessed from the original source location every time.
In computing, a cache is a high-speed data storage layer that stores a subset of data. Future requests for that data are served up faster than is possible by accessing the data’s primary storage location. Caching allows you to efficiently reuse previously retrieved or computed data.
How does caching work?
The data in a cache is generally stored in fast access hardware such as RAM (random access memory) and may also be used in correlation with a software component. A cache’s primary purpose is to increase data retrieval performance by reducing the need to access the underlying slower storage layer.
There are two main types of caching:
- Client-side caching
- Server-side caching
Caching benefits
- Decreased network costs: Content can be cached at various points in the network path between the content consumer and content origin. When the content is cached closer to the consumer, requests won’t cause much additional network activity beyond the cache.
- Improved responsiveness: Caching enables content to be retrieved faster because an entire network round trip isn’t necessary. Caches maintained close to the user, like the browser cache, can make this retrieval nearly instantaneous.
- Increased performance on the same hardware: For the server where the content originated, more performance can be squeezed from the same hardware by allowing aggressive caching. The content owner can leverage the powerful servers along the delivery path to take the brunt of certain content loads.
- Availability of content during network interruptions: With certain policies, caching can be used to serve content to end users even when it may be unavailable for short periods of time from the origin servers.
General cache use cases
- In-memory data lookup: If you have a mobile/web app front end, you might want to cache information like user profile, historical or static data, or some API response according to your use cases. Caching will help in storing such data. Also, when you create a dynamic programming solution for some problem, two-dimensional arrays or hash maps work as a caching.
- RDBMS speedup: Relational databases are slow when it comes to working with millions of rows. Unnecessary, old or high-volume data can make their index slower, whether you do sharding or partitioning. A single node can always experience delay and latency in query response when the database is full in its capacity.
- Session store: Active web sessions are very frequently accessed data — whether you want to do API authentication, or you want to store recent cart information in an e-commerce app, the cache can serve sessions well.
- Token caching: API tokens can be cached in memory to deliver high-performance user authentication and validation.
Eviction policy
- Least Recently Used (LRU): In most caching use cases, applications access the same data again and again. In such use cases, the cached data that’s not used recently or cold data can be safely evicted.
- Least Frequently Used (LFU): If you have a case where you know the data is repetitive, go for LFU to avoid cache miss.
- Most Recently Used (MRU): This strategy removes most recently used items as they aren’t required — at least in the near future.
- First In, First Out (FIFO): It’s like MRU, but it follows strict ordering of inserted data items. MRU doesn’t honor insertion order.
Caching strategy
- Single node (in-process) caching: It’s a caching strategy for non-distributed systems. Applications instantiate and manage their own or third-party cache objects. Both application and cache are in the same memory space.
- Distributed caching: When we talk about Internet scale web applications, we actually talk about millions of requests per minute, petabytes or terabytes of data in the context. A single dedicated powerful machine or two won’t be able to handle such a humongous scale. We need several machines to handle such scenarios. Multiple machines make a cluster, and at a very high scale, we need multiple such clusters.
Caching in MULE 4
In Mule 4, caching can be achieved using cache scope and/or object-store. Cache scope internally uses object store to store the data. Cache scope and object store have their specific use cases where they can be used effectively.
What is cache scope
The cache scope is for storing and reusing frequently called data. You can use a cache scope to reduce the processing load on the Mule instance and to increase the speed of message processing within a flow. It’s particularly effective for these tasks:
- Processing repeated requests for the same information
- Processing requests for information that involve large, non-consumable payloads
The cache scope only caches non-consumable payloads. It doesn’t cache consumable payloads (such as a streaming payload), which can only be read once before they are lost.
What is Object Store?
Object store lets applications store data and states across batch processes, Mule components and applications, from within an application. If used on CloudHub, the object store is shared between applications deployed on cluster.
Object Store v2 features
- Persists keys for 30 days unless updated. If a key is updated, the TTL (time-to-live) is extended by another 30 days. In Object Store v2, there’s no limit on the number of keys per app.
- It allows for an unlimited number of entries. There’s no limit on the total size of v2 object-stores.
- Stores value up to 10 MB (when Base64 encoded) in size. You can estimate base64 size of a payload as follows: CEILING(base10size * 1024/3) * 4, where base10size is object size in bytes. + Example: A base10 payload size of 7.5 MB converts to 10.24 MB base64.
- It’s available in all supported regions and availability zones within each region.
- It’s co-located in the same region as your workers. For example, workers hosted in Singapore would use Object Store v2 hosted in Singapore.
- It provides a Mule connector and REST interface for access by external applications.
- It provides end-to-end secure TLS-transport.
- It encrypts persistent storage to FIPS 140-2 compliant standards.
Object Store file location for on perm
While running the project using a studio Object Store file will be created at the below-mentioned location.
<Studio_Home>\plugins\org.mule.tooling.server.<Mule_Version>.ee_<Studio_Version>.<Timestamp>\mule\.mule\<Project_Name>\objectstore
While running the project on the perm Object Store file will be created at the below mentioned location.
<Mule_Home>\.mule\<Project_Name>\objectstore
How cache scope works
Cache scope works as per the below-mentioned Algorithm.
- Start Cache Scope
- Check if filter expression is present or not?
- If filter expression is present then evaluate the expression
- If the evaluation result is true to go to step # 3
- If the evaluation result is false to go to step # 9
- Generate the Key for request
- If Default then generate a key using SHA256KeyGenerator
- If Key Expression then generate a key using a custom expression
- If Key Generator then generate a key using custom java class.
- Check if Key is Present in Cache?
- If Key is present in cache get the corresponding response use it and go to step # 10(This is called a Cache Hit)
- If Key is not present in cache go to step # 5 (This is called a Cache Miss)
- Execute Outbound processor
- Is the response consumable?
- If yes go to step # 10
- If no go to step # 7
- Generate Response Key Using SHA256 Digest
- Store the Response in Cache and go to step # 10
- If Custom Object Store is configured, store it using specified configuration.
- Else store the response in memory/local file
- Execute Outbound processor
- End Cache Scope
Mule 4 Project
Overview
The project has three flows:
- helloworldFlow, which listens on /hello and returns the json payload as “Hello World.”
- byeworldFlow, which listens on /hello and returns the json payload as “Bye World.”
- scheduler calls helloworldFlow and byeworldFlow over HTTP from inside the Cache scope.
- objectStoreFlow call helloworldFlow over HTTP, store response using a custom key and retrieve response using the same key.
Here is configuration XML for flows
<?xml version=”1.0″ encoding=”UTF-8″?>
<mule xmlns:os=”http://www.mulesoft.org/schema/mule/os” xmlns:ee=”http://www.mulesoft.org/schema/mule/ee/core” xmlns:http=”http://www.mulesoft.org/schema/mule/http” xmlns=”http://www.mulesoft.org/schema/mule/core” xmlns:doc=”http://www.mulesoft.org/schema/mule/documentation” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=”http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd http://www.mulesoft.org/schema/mule/ee/core http://www.mulesoft.org/schema/mule/ee/core/current/mule-ee.xsd http://www.mulesoft.org/schema/mule/os http://www.mulesoft.org/schema/mule/os/current/mule-os.xsd”>
<http:listener-config name=”HTTP_Listener_config” doc:name=”HTTP Listener config” doc:id=”ed8128b6-5001-4964-9828-9246c1d2a4b9″>
<http:listener-connection host=”0.0.0.0″ port=”8081″/>
</http:listener-config>
<http:request-config name=”HTTP_Request_configuration” doc:name=”HTTP Request configuration” doc:id=”79f2b2b7-1811-4aa0-9286-2778ac9049a6″>
<http:request-connection host=”localhost” port=”8081″/>
</http:request-config>
<os:object-store name=”Object_store” doc:name=”Object store” doc:id=”ec62ef70-080b-4a1a-86d2-9466b4c40a35″/>
<ee:object-store-caching-strategy name=”Caching_Strategy” doc:name=”Caching Strategy” doc:id=”628bf63b-c6a9-4a21-8e50-135f4fafe317″ objectStore=”Object_store”/>
<flow name=”helloworldFlow” doc:id=”0288e2b0-5cf6-41b7-a29e-3cb8ba1effcc”>
<http:listener doc:name=”Listener” doc:id=”38bc54c8-7d8d-477d-8f9d-88e2f31bb965″ config-ref=”HTTP_Listener_config” path=”/hello”>
<http:response statusCode=”200″>
<http:body><![CDATA[#[output application/json —payload]]]></http:body>
<http:headers><![CDATA[#[output application/java
—
{
“Content-Type” : “application/json”
}]]]></http:headers>
</http:response>
</http:listener>
<set-payload value=”#[{ "response": "Hello World" }]” doc:name=”Set Payload” doc:id=”2f87aff3-a56f-4da4-ba1d-d0feadba3685″/>
<logger level=”INFO” doc:name=”Logger” doc:id=”847b059e-bfea-496f-b49c-bbdf092fae35″ message=”#["Hello Called"]”/>
</flow>
<flow name=”byeworldFlow” doc:id=”28528dc4-bfea-460e-b91d-26ccd3c005ac”>
<http:listener doc:name=”Listener” doc:id=”39e03cf9-cd3b-4308-879b-73bdc41fe2af” config-ref=”HTTP_Listener_config” path=”/bye”>
<http:response statusCode=”200″>
<http:body><![CDATA[#[output application/json —payload]]]></http:body>
<http:headers><![CDATA[#[output application/java
—
{
“Content-Type” : “application/json”
}]]]></http:headers>
</http:response>
</http:listener>
<set-payload value=”#[{ "response": "Bye World" }]” doc:name=”Set Payload” doc:id=”fd66f58b-ee9c-431e-9529-3242c49a3420″/>
<logger level=”INFO” doc:name=”Logger” doc:id=”de70255d-b2c4-42e9-84c4-2ce0a72720b1″ message=”#["Bye Called"]”/>
</flow>
<flow name=”scheduler” doc:id=”cd8c639d-f471-4b46-a5d2-6f83dd6d733e”>
<scheduler doc:name=”Scheduler” doc:id=”5e8514a3-ef66-4554-b824-c470dcb60fa3″>
<scheduling-strategy>
<fixed-frequency frequency=”10″ timeUnit=”SECONDS”/>
</scheduling-strategy>
</scheduler>
<ee:cache doc:name=”Cache” doc:id=”eaeefc29-5c3d-47cc-8cf3-632c98b2088b” cachingStrategy-ref=”Caching_Strategy”>
<http:request method=”GET” doc:name=”hello” doc:id=”c918c0f2-bf73-46bf-b862-ca8646b2de41″ config-ref=”HTTP_Request_configuration” path=”/hello”/>
<http:request method=”GET” doc:name=”bye” doc:id=”36ff7b9e-917f-44d8-888b-7a6caa9052d4″ config-ref=”HTTP_Request_configuration” path=”/bye”/>
</ee:cache>
<logger level=”INFO” doc:name=”Logger” doc:id=”deaa1204-09e2-4cd6-9c5a-746d7177b8ea” message=”#["Scheduler Called"]”/>
</flow>
<flow name=”objectStoreFlow” doc:id=”7bef0ebd-89b3-4e13-9aab-13df96c33430″>
<http:listener doc:name=”Listener” doc:id=”8b93b995-7807-40cb-8b8e-0f92561c85b4″ config-ref=”HTTP_Listener_config” path=”/objectStore”/>
<http:request method=”GET” doc:name=”hello” doc:id=”31b8bc93-cf9e-43b0-8cee-f28328e817cc” config-ref=”HTTP_Request_configuration” path=”/hello”/>
<os:store doc:name=”Store” doc:id=”14ce71ea-daea-4b51-a998-2871f8a5db48″ key=”output”/>
<os:retrieve doc:name=”Retrieve” doc:id=”5a534ae0-0f89-4964-af5c-32a4a4fbe85b” key=”output”>
<os:default-value><![CDATA[#[“Default”]]]></os:default-value>
</os:retrieve>
<logger level=”INFO” doc:name=”Logger” doc:id=”8f04d071-81f7-48cb-ac25-273650037ca7″/>
</flow>
</mule>
Hello World Flow
Bye World Flow
Scheduler Flow
Object Store Flow
Standard Output Logs
When we run the project schedule, flow gets triggered every 10 seconds. It calls hello world flow and bye world flow from inside the cache. When scheduler flow gets triggered from the first time, it calls both the flows on http and store the response in cache i.e., Object Store. When the scheduler flows get triggered a second time, it uses cached responses and not call flows.
Cache configuration details
Default Cache Configuration without Caching Strategy.
Caching strategy details
Caching strategy configuration for how to handle Key Generation.
Object store configuration
Caching strategy with Object Store to customize the Object Store behavior like Max Entries and Entry TTL.
Use cases for cache scope and Object Store
Cache scope is used in below-mentioned cases:
- Need to store the whole response from the outbound processor
- Data returned from the outbound processor doesn’t change frequently
- As cache scope internally handles the cache hit and cache miss scenarios, it’s more readable.
Object Store is used in below-mentioned cases:
- Need to store custom/intermediary data
- Need to store watermarks
- Sharing the data/stage across applications, schedulers and batch
In this technical article, we’ve learned what caching is, its use cases, different types of eviction mode and caching strategy. Also, we’ve seen how we can implement the caching using Mule 4.