Edit and complete the Async Inline Caching Sample Guide.
Refactor the Async Inline Caching Sample Code to include (Asciidoc) documentation markers. Change the batch time interval in the AEQ batch-size configuration/strategy bean definition to 15 minutes. Rename the GolfTournament created in the SpringBootApplication class to 'The Masters'. Refactor the isFinished(..) and isNotFinished() methods in the PgaTourService class to accept a nullable GolfTournament argument. Refactor the GolferController class to declare the REST API web service endpoints to use '/api/golf/tournament/' as the base Webapp context.
This commit is contained in:
@@ -46,30 +46,32 @@ link:../index.html#geode-samples[Back to Samples]
|
||||
== Background
|
||||
|
||||
In _Synchronous Inline Caching_, data is immediately read from or written to the primary data source, (a.k.a. the
|
||||
_System of Record_ (SOR)), before the cache is modified, thereby guaranteeing a degree of consistency. The "synchronous"
|
||||
arrangement of the _Inline Caching_ pattern is commonly referred to as "_Read/Write-Through_".
|
||||
_System of Record_ (SOR)), before the cache is modified, thereby guaranteeing a degree of consistency between the cache
|
||||
and the backend data source. The "synchronous" arrangement of the _Inline Caching_ pattern is commonly referred to as
|
||||
"_Read/Write-Through_".
|
||||
|
||||
With _Asynchronous Inline Caching_, data changes are written to the primary data source asynchronously, after the cache
|
||||
has already been modified. The "asynchronous" arrangement of the _Inline Caching_ pattern is commonly referred to as
|
||||
"_Write-Behind_". The cache entry is modified, then, and only then, will the primary data source possibly reflect the
|
||||
changes sometime later.
|
||||
"_Write-Behind_". The cache entry is modified, then, and only then, will the primary data source reflect the changes
|
||||
sometime later.
|
||||
|
||||
It is possible for the primary data source (i.e. _System of Record_ (SOR)) and the cache to get out-of-sync. Clearly,
|
||||
the primary data source may contain information that the cache does not. Another application may be updating the primary
|
||||
data source and not using the cache. The cache entry change may not be promptly written to the primary data source until
|
||||
the "_Write-Behind_" operation is triggered, which is often implementation dependent. The data change might violate
|
||||
a database constraint, fail to commit and be rolled back. All sorts of reasons can cause the primary data source
|
||||
and the cache to become out-of-sync, or inconsistent.
|
||||
Due to the asynchronous nature of _Async Inline Caching_, it is possible for the primary data source (i.e. _System
|
||||
of Record_ (SOR)) and the cache to get out-of-sync. Additionally, the primary data source may contain information that
|
||||
the cache does not. That is to say, another application may be updating the primary data source and not using the cache.
|
||||
The cache entry change may not be promptly written to the primary data source until the "_Write-Behind_" operation is
|
||||
triggered, which is often implementation dependent. A data change could violate a database constraint, fail to commit
|
||||
and be rolled back. All sorts of reasons can cause the primary data source and the cache to become out-of-sync,
|
||||
or inconsistent.
|
||||
|
||||
For this reason, throughput and latency are the primary applications concerns, rather than consistency, for when to use
|
||||
_Asynchronous Inline Caching_.
|
||||
For this reason, throughput and latency are the primary application concerns, rather than consistency, when using
|
||||
the _Asynchronous Inline Caching_ pattern.
|
||||
|
||||
The general pattern of Inline Caching is depicted as follows:
|
||||
|
||||
image::{images-dir}/Inline-Caching-Overview.png[]
|
||||
|
||||
The layer in the application/system architecture involving _Inline Caching_ logic sits between the cache and the primary
|
||||
data source:
|
||||
The layer in the application/system architecture involving the _Inline Caching_ logic sits between the cache
|
||||
and the primary data source:
|
||||
|
||||
image::{images-dir}/Inline-Caching-Layer.png[]
|
||||
|
||||
@@ -85,24 +87,379 @@ IMPLEMENTATION
|
||||
|
||||
As readers should know, the application cache is backed by an {apache-geode-name} Region.
|
||||
|
||||
In _Synchronous_, _Read-Through_ and/or _Write-Through_, _Inline Caching_, a `CacheLoader` configured for the Region
|
||||
and used to "_Read-Through_" to the backend/primary data source on a cache miss. When a cache entry is written, then
|
||||
a configured `CacheWriter` for the Region is invoked to "_Write-Through_" to the backend/primary data source. The cache
|
||||
is only modified if the `CacheWriter` was successful in modify the backend/primary data source.
|
||||
In _Synchronous_, _Read-Through_ and/or _Write-Through_, _Inline Caching_, a `CacheLoader` is configured for the Region
|
||||
and used to "_Read-Through_" to the backend/primary data source on a cache miss. When a cache entry is written, a
|
||||
configured `CacheWriter` for the Region is invoked to "_Write-Through_" to the backend/primary data source. The cache
|
||||
is only modified if the `CacheWriter` was successful in modifying the backend/primary data source.
|
||||
|
||||
Both the `CacheLoader` and `CacheWriter` are optional. That is, you can configure one side of
|
||||
_Synchronous Inline Caching_, either the "_Read-Through_", or the "_Write-Through_", both, or neither.
|
||||
Both the `CacheLoader` and `CacheWriter` are optional. That is, you can configure just one side of
|
||||
_Synchronous Inline Caching_ or the other, either "_Read-Through_" or "_Write-Through_", both, or neither.
|
||||
|
||||
With _Asynchronous, Write-Behind, Inline Caching_, you (may) configure the Region with an associated `AsyncEventQueue`
|
||||
(AEQ) and registered `AsyncEventListener`. When the cache is written to, the entry event is then forwarded and stored
|
||||
on the AEQ, where at sometime later, the registered `AsyncEventListener` for the AEQ will be invoked, which can then
|
||||
asynchronously modify the backend/primary data source.
|
||||
on the AEQ, where at sometime later, the registered `AsyncEventListener` for the AEQ will be invoked to process the
|
||||
(batch of) `AsyncEvents`, which can then asynchronously modify the backend/primary data source.
|
||||
|
||||
Unlike _Synchronous Inline Caching_, _Asynchronous Inline Caching_ does not have an equivalent for "_Read-Through_",
|
||||
such as "_Read-Behind_".
|
||||
such as "_Read-Behind_", particularly in a Reactive sense.
|
||||
|
||||
NOTE: At some point later, we may consider the development of "_Read-Behind_" with with use of Reactive Programming
|
||||
and the Reactive Spring Data Repository abstraction.
|
||||
|
||||
link:../index.html#geode-samples[Back to Samples]
|
||||
|
||||
[[geode-samples-caching-inline-asynchronous-example]]
|
||||
== Example
|
||||
|
||||
For our example, we have built a Golf Tournament application that runs a simulation with a set of professional golfers
|
||||
playing at _The Masters_. The (12) golfers play 18 holes of golf in pairs and proceed from hole 1 to hole 18 in under
|
||||
a minute. For each hole played, their score of the whole is calculated. At the end of the round, each golfers final
|
||||
score is calculated relative to par for the course (72).
|
||||
|
||||
The Golf Tournament application is a Spring Boot application using {apache-geode-name} to persist the golfers score in
|
||||
realtime as the players complete each hole. However, to make the play "official", the golfer's score is recorded to a
|
||||
backend database, asynchronously using _Asynchronous_, _Write-Behind_, _Inline Caching_. It is assumed that there is
|
||||
additional validation required (e.g. such as signing scorecards, etc) that goes on before the final score is accepted
|
||||
and recorded to the _System of Record_ (SOR), in the "history books", so to speak.
|
||||
|
||||
Now that the problem context is established, let's review a few of the classes.
|
||||
|
||||
NOTE: Each of the application domain classes are code snippets or a preview of the actual class, and not actual code.
|
||||
See the actual Sample code for more detail.
|
||||
|
||||
We start by defining our Golf Tournament application domain model types, starting with the `Golfer` class. Essentially,
|
||||
the `Golfer` class models a person who plays golf and is defined as:
|
||||
|
||||
.`Golfer` class.
|
||||
[source,java]
|
||||
----
|
||||
@Entity
|
||||
@Table(name = "golfers")
|
||||
public class Golfer implements Comparable<Golfer> {
|
||||
|
||||
@javax.persistence.Id @Id
|
||||
private String name;
|
||||
|
||||
private Integer hole = 0;
|
||||
|
||||
private Integer score = 0;
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
The `Golfer` class has been annotated with JPA's `@Entity` annotation making it a proper (persistent) entity class.
|
||||
The `Golfer` class is also annotated with `@Table` to persist instances of `Golfer` into the "_golfers_" table
|
||||
of the database.
|
||||
|
||||
The application also defines a non-entity, `GolfCourse` class to model the golf course, which requires a name
|
||||
and `List` of pars for each hole (all 18 holes) of the golf course:
|
||||
|
||||
.`GolfCourse` class
|
||||
[source,java]
|
||||
----
|
||||
class GolfCourse {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final List<Integer> parForHole = new ArrayList<>(18);
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
Next, a non-entity, `GolfTournament` class has been defined to model the golf tournament being played. It expects a name
|
||||
for the tournament, the golf course` where the tournament is held and played, and a `Set` of `Golfers` (players)
|
||||
registered to play.
|
||||
|
||||
Additionally, the `GolfTournament` class contains an inner class, the `Pairing` class, to group the registered players
|
||||
into pairs to play a round.
|
||||
|
||||
.`GolfTournament` class
|
||||
[source,java]
|
||||
----
|
||||
class GolfTournament implements Iterable<Pairing> {
|
||||
|
||||
private final String name;
|
||||
|
||||
private GolfCourse golfCourse;
|
||||
|
||||
private final List<Pairing> pairings = new ArrayList<>();
|
||||
|
||||
private final Set<Golfer> players = new ArrayList<>();
|
||||
|
||||
public static class Pair {
|
||||
|
||||
private final Golfer playerOne;
|
||||
private final Golfer playerTwo;
|
||||
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
The `GolfTournament.Pairing` class serves as a composite acting on both players in the pair, such as to advance
|
||||
the hole of play.
|
||||
|
||||
The `GolfTournament` class has additional builder methods to register players, build pairings, enable the tournament
|
||||
to be played and determine when the tournament is finished (i.e. when all pairs complete all 18 holes of play).
|
||||
|
||||
There is a `GolferRepository` interface extending the `JpaRepository` interface to persist the state of each `Golfer`
|
||||
to the backend database:
|
||||
|
||||
.`GolferRepository` interface
|
||||
[source,java]
|
||||
----
|
||||
interface GolferRepository extends JpaRepository<Golfer, String> { }
|
||||
----
|
||||
|
||||
NOTE: While `GolferRepository` extends from the `JpaRepository` interface directly, it is recommended to extend
|
||||
the `CrudRepository` interface instead, keeping your application SD _Repositories_ agnostic from the underlying
|
||||
data store. The reason `GolferRepository` extends from the `JpaRepository` interface directly, is to make it absolutely
|
||||
clear that the `Golfer` state will be persisted to a backend database (RDBMS) using JPA along with Hibernate as the
|
||||
provider.
|
||||
|
||||
The `GolferRepository` will be used by SBDG's _Asynchronous Inline Caching_ framework and infrastructure components.
|
||||
|
||||
The _Repository_ is injected into and used by the `AsyncEventListener` registered on the AEQ attached to the "Golfers"
|
||||
Region to perform asynchronous, _Write-Behind_, _Inline Caching_, operations to the backend database
|
||||
and _System of Record_ (SOR).
|
||||
|
||||
We'll see in a moment how this association is made and how _Asynchronous Inline Caching_ is setup, made simple by SBDG.
|
||||
|
||||
To encapsulate the application logic and provide a (possibly transactional) facade to the `Golfer's` state,
|
||||
a `GolferService` class has been defined:
|
||||
|
||||
.`GolferService` class
|
||||
[source,java]
|
||||
----
|
||||
@Service
|
||||
class GolferService {
|
||||
|
||||
@CachePut(cacheNames = "Golfers", key = "#golfer.name")
|
||||
public Golfer update(Golfer golfer) {
|
||||
return golfer;
|
||||
}
|
||||
|
||||
public List<Golfer> getAllGolfersFromCache() {
|
||||
// Use SDG GemfireTemplate to access the "Golfers" Region
|
||||
}
|
||||
|
||||
public List<Golfer> getAllGolfersFromDatabase() {
|
||||
// Use the GolfersRepository to access the "Golfers" stored in the database.
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
The `GolferService` class has been marked as a application service using Spring's `@Service` stereotype annotation.
|
||||
|
||||
Along with the `GolferService` the application uses a `PgaTourService` class to manage and run a (single)
|
||||
`GolfTournament`. Its primary method used to run a `GolfTournament` is the `play()` method:
|
||||
|
||||
.`PgaTourService` class, `play()` method
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}/caching/inline-async/src/main/java/example/app/caching/inline/async/client/service/PgaTourService.java[tags=play]
|
||||
----
|
||||
|
||||
This is a Spring `@Scheduled` service method called every 2.5 seconds after an initial delay of 5 seconds. Essentially,
|
||||
the service method runs through the pairings, where each `Golfer` plays all 18 holes, their scores are calculated
|
||||
and recorded for each hole until the round is completed, whether the players score is then calculated relative to par
|
||||
for course and recorded to the cache, and eventually the database.
|
||||
|
||||
To get everything started, a Spring Boot application class (i.e. a class annotated with the `@SpringBootApplication`
|
||||
annotation) is used to bootstrap the application.
|
||||
|
||||
.`BootGeodeAsyncInlineCachingClientApplication` class
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}/caching/inline-async/src/main/java/example/app/caching/inline/async/client/BootGeodeAsyncInlineCachingClientApplication.java[tags=class]
|
||||
----
|
||||
|
||||
The `GolfTournament` is kicked off in the `ApplicationRunner`.
|
||||
|
||||
.`ApplicationRunner` bean in the `GolfApplicationConfiguration` class
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}/caching/inline-async/src/main/java/example/app/caching/inline/async/client/BootGeodeAsyncInlineCachingClientApplication.java[tags=application-configuration]
|
||||
----
|
||||
|
||||
As the golf tournament progresses (in the `@Scheduled`, PgaTourService.play()` service method), the updates to the
|
||||
`Golfers` in the pairs are written to the "_Golfers_" cache (i.e. "_Golfers_" Region) by calling
|
||||
the `GolferService.update(:Golfer)` service method:
|
||||
|
||||
.`GolferService` class, `update(:Golfer)` method
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}/caching/inline-async/src/main/java/example/app/caching/inline/async/client/service/GolferService.java[tags=cache-put]
|
||||
----
|
||||
|
||||
This method simply "puts" the `Golfer` in the cache (i.e. "_Golfers_" Region) mapped to the `Golfer's name` (as a
|
||||
key/value cache entry).
|
||||
|
||||
The cache/Region entry `put` operation results in cache event being added to the AEQ, which will eventually trigger
|
||||
the SBDG framework-provided `AsyncEventListener` with our injected `GolferRepository` to write the `Golfer's` state
|
||||
to the backend database.
|
||||
|
||||
The configuration of the "_Golfers_" Region (cache) with an AEQ and listener using the `GolferRepository` is defined
|
||||
as follows:
|
||||
|
||||
.`AsyncInlineCachingConfiguration` class
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}/caching/inline-async/src/main/java/example/app/caching/inline/async/config/AsyncInlineCachingConfiguration.java[tags=class]
|
||||
----
|
||||
|
||||
The Spring `@Configuration` class used to enable _Async Inline Caching_ consists of 2 different AEQ configuration
|
||||
arrangements and bean definitions.
|
||||
|
||||
The first is a AEQ configured with a "preference" for being triggered on the *batch size*, i.e. the number of events
|
||||
present in the AEQ:
|
||||
|
||||
.`AsyncInlineCachingConfiguration` class
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}/caching/inline-async/src/main/java/example/app/caching/inline/async/config/AsyncInlineCachingConfiguration.java[tags=queue-batch-size]
|
||||
----
|
||||
|
||||
The second AEQ configuration uses a "preference" for being triggered based on a *batch time interval*, i.e. after
|
||||
a period of time has elapsed, such as 5 seconds.
|
||||
|
||||
NOTE: The default AEQ _batch time interval_ in {apache-geode-name} is *5 milliseconds* (5 ms). However, to demonstrate
|
||||
the asynchronous nature of the cache to database update, a much longer delay was used. Likewise, the default AEQ
|
||||
_batch size_ is *100*.
|
||||
|
||||
In both AEQ configurations and bean definitions, the _batch size_ and _batch time interval_ have been set (overriding
|
||||
the {apache-geode-name} defaults) in order to show the effects of each AEQ settings independently. As you can imagine,
|
||||
particularly in a highly concurrent and transactional application with frequent updates, it would be hard to determine
|
||||
whether the AEQ event processing (and listener) was triggered by the _batch time interval_ or the _batch size_. And,
|
||||
with a default *5 millisecond* _batch time interval_, it is hard to witness the asynchronous nature of the cache
|
||||
to database updates to begin with.
|
||||
|
||||
We will have more to say on the AEQ configuration below.
|
||||
|
||||
The final class in the golf application is a `GolferController` class annotated with Spring's `@RestController`
|
||||
annotation in order to expose our golf application functionality as an API in a REST-ful interface:
|
||||
|
||||
.`GolferService` class, `update(:Golfer)` method
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}/caching/inline-async/src/main/java/example/app/caching/inline/async/client/web/GolferController.java[tags=class]
|
||||
----
|
||||
|
||||
The Spring Web MVC `@RestController` class exposes two REST-ful API web service endpoints returning JSON data:
|
||||
|
||||
* http://localhost:8080/api/golf/tournament/cache - used to get the current state of the golfers from the cache
|
||||
* http://localhost:8080/api/golf/tournament/database - used to get the current state of the golfers from the database
|
||||
|
||||
Both web service endpoints are consumed by the `golf-tournament-view.html` page, which uses jQuery and AJAX to make
|
||||
periodic HTTP requests to refresh the page.
|
||||
|
||||
[[geode-samples-caching-inline-asynchronous-example-run]]
|
||||
== Run the Example
|
||||
|
||||
To run the example, there are few more configuration details we need to cover.
|
||||
|
||||
While it is possible to run this example using an {apache-geode-name} client/server topology, we keep things simple
|
||||
by running the example using a single Spring Boot application class, namely the
|
||||
`BootGeodeAsyncInlineCachingClientApplication` along with a peer cache configuration.
|
||||
|
||||
That is, in our `BootGeodeAsyncInlineCachingClientApplication` class, we also apply the
|
||||
`PeerCacheApplicationConfiguration` by enabling the Spring Profile, "_peer-cache_":
|
||||
|
||||
.`PeerCacheApplicationConfiguration` class
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}/caching/inline-async/src/main/java/example/app/caching/inline/async/client/BootGeodeAsyncInlineCachingClientApplication.java[tags=peer-cache-configuration]
|
||||
----
|
||||
|
||||
It should be noted that an AEQ can only be created and registered on a Region existing on the server-side of
|
||||
an {apache-geode-name} system. That is, you cannot add an AEQ to a client-side Region. Therefore, in all your
|
||||
_Async Inline Caching_ Uses Cases (UC), synchronous or asynchronous, it will be the servers in an {apache-geode-name}
|
||||
cluster that are responsible for _Write-Behind_ functionality to the backend data store, not a Spring Boot,
|
||||
{apache-geode-name} client application.
|
||||
|
||||
However, for demonstration purposes, we override SBDG's default, auto-configuration providing a `ClientCache` instance
|
||||
by simply enabling the "_peer-cache_" Spring Profile, which replaces the `ClientCache` instance with a peer `Cache`
|
||||
instance instead.
|
||||
|
||||
Finally, when running this application, you must decide on your AEQ management strategy. For example, do you want
|
||||
the AEQ listener to be triggered by *batch size* (i.e. the number of cache events) or using the *batch time interval*.
|
||||
Each strategy can be enabled using a Spring Profile, either "_queue-batch-size_" or "_queue-batch-time-interval_".
|
||||
This allows you to experiment with different AEQ management strategies to observe the effects.
|
||||
|
||||
In total, the Spring Profiles you need to enable would appear as follows:
|
||||
|
||||
.Spring Profiles to enable when running the application.
|
||||
[source,txt]
|
||||
----
|
||||
-Dspring.profiles.active=peer-cache,queue-batch-size,server
|
||||
----
|
||||
|
||||
Of course, you can replace "_queue-batch-size_" with "_queue-batch-time-interval_".
|
||||
|
||||
The final configuration of the Spring Boot application, as seen in IntelliJ IDEA is:
|
||||
|
||||
image::{images-dir}/BootGeodeAsyncInlineCachingClientApplication-IntelliJ-IDEA-Run-Configuration.png[]
|
||||
|
||||
To access the golf application, simply navigate to:
|
||||
|
||||
http://localhost:8080/golf-tournament-view.html
|
||||
|
||||
You should see a web page similar to:
|
||||
|
||||
image::{images-dir}/Asynchronous-Inline-Caching-Application.png[]
|
||||
|
||||
You can also run this example using the SBDG Gradle build from the command-line like so:
|
||||
|
||||
.Run the example using Gradle
|
||||
[source,txt]
|
||||
----
|
||||
$ gradlew --no-daemon :spring-geode-sample-caching-inline-async:bootRun
|
||||
----
|
||||
|
||||
This is convenient since the Spring Profiles are already configured for you.
|
||||
|
||||
However, when you switch to using the "_queue-batch-time-interval_" you will see a similar effect and behavior, but
|
||||
with on a slightly different schedule for the database updates, i.e. at a fixed 5 second interval.
|
||||
|
||||
[[geode-samples-caching-inline-asynchronous-example-conclusion]]
|
||||
== Conclusion
|
||||
|
||||
_Asynchronous Inline Caching_ can be a powerful pattern of caching applied to your diverse Spring Boot application
|
||||
workflows depending on the use case and requirements.
|
||||
|
||||
If throughput and latency are important to create the necessary responsiveness in your application design and user
|
||||
experience, and consistency (i.e. between the cache and the backend _System of Record_ (SOR), or database) is not
|
||||
as important of a concern, then you might want to consider _Asynchronous Inline Caching_.
|
||||
|
||||
There are many factors to consider in the configuration of the AEQ that is at the heart of an _Asynchronous Inline
|
||||
Caching_ configuration, such as the appropriate *batch size* and *batch time interval*. Neither setting is exclusive
|
||||
from the other, in fact. Both settings are considered when {apache-geode-name} makes a decision of when to trigger
|
||||
the listener registered on the AEQ to process the events from operations on the Region to which the AEQ is attached.
|
||||
|
||||
You must decide on your *batch size*, based on how many events might occur in a given period of time. If the frequency
|
||||
is quite high, then you might need a smaller *batch size*, for instance. The AEQ is in-memory, therefore you must be
|
||||
conscious of memory constraints on your system, especially during peak loads. Of course, the AEQ can be configured
|
||||
to overflow events to disk and even persist events between restarts, but ideally you want these events to be processed
|
||||
in as near realtime as possible.
|
||||
|
||||
However, when the load on your application is low and events occur sporadically, you also must be mindful that the
|
||||
events do not sit in the AEQ for too long. If you have *batch size* of 1000, and there are currently only 20 events
|
||||
(well, any number of events less than 1000) sitting in the AEQ waiting to be processed, then the *batch time interval*
|
||||
becomes important, especially so that these remaining events (less than the configured *batch size*) don't wait in the
|
||||
queue indefinitely.
|
||||
|
||||
Other factors to consider are whether you can conflate the events in the AEQ. This minimizes the number of events for
|
||||
a single logical Object to the latest update. Additionally, do you need to overflow events to disk after the configured
|
||||
maximum queue memory is reached, or should events simply be discarded? Do you need to maintain the events in the queue
|
||||
between restarts (i.e. configure the AEQ to be persistent)? Do the disk writes for overflow and/or persistence need to
|
||||
be synchronous? Do the events in the queue need to be ordered based on some `OrderPolicy`? Do the events need to be
|
||||
filtered? How many dispatcher threads do you require? Etc. Etc. There are many important things consider in the
|
||||
configuration of the AEQ when using _Asynchronous Inline Caching_ for _Write-Behind_ capabilities.
|
||||
|
||||
Usually, it is safe to start with the defaults and adjust as needed, and as your measurements and tests dictate.
|
||||
|
||||
We hope that you found this guide useful and that it has armed you with more knowledge to tackle difficult problems,
|
||||
the type of application problems where the _Asynchronous Inline Caching_ pattern can be applied with immediate benefits.
|
||||
|
||||
Good luck.
|
||||
|
||||
link:../index.html#geode-samples[Back to Samples]
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 236 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 521 KiB |
Reference in New Issue
Block a user