Correct grammar, spelling and verbiage in the Multi-Site Caching Guide.

Resolves gh-80.
This commit is contained in:
John Blum
2020-04-19 20:46:00 -07:00
parent 01e0f2f5f0
commit ff9594e26d

View File

@@ -39,6 +39,7 @@ link:../index.html[Index]
link:../index.html#geode-samples[Back to Samples] link:../index.html#geode-samples[Back to Samples]
[[geode-samples-caching-multisite-background]] [[geode-samples-caching-multisite-background]]
== Background == Background
@@ -198,7 +199,7 @@ by using the _Multi-Site Caching_ pattern along with giving you the configuratio
== Example == Example
For our example, we are going to build on the Spring code snippet above, using the `CustomerService` class with For our example, we are going to build on the Spring code snippet above, using the `CustomerService` class with
the _Look-Aside Caching_ pattern applied, then enhance the caching solution with an _Active-Active_, Multi-Site, the _Look-Aside Caching_ pattern applied, then enhance the caching solution with an _Active-Active_, Multi-Site
WAN topology. WAN topology.
However, instead of looking up `Customers` by `Account` number, we are simply going to lookup `Customers` by "name". However, instead of looking up `Customers` by `Account` number, we are simply going to lookup `Customers` by "name".
@@ -216,7 +217,7 @@ include::{samples-dir}/caching/multi-site/src/main/java/example/app/caching/mult
NOTE: The `Customer` class uses https://projectlombok.org/[Project Lombok] to simplify the implementation. NOTE: The `Customer` class uses https://projectlombok.org/[Project Lombok] to simplify the implementation.
The `Customer` class is mapped to the "Customers" `Region` using the SDG `@Region` mapping annotation. The `@Region` The `Customer` class is mapped to the "Customers" `Region` using the SDG `@Region` mapping annotation. The `@Region`
annotation is very similar in purpose to the JPA `@Entity` and `@Table` annotation. A `Customer` is very simply defined annotation is very similar in purpose to the JPA `@Entity` and `@Table` annotations. A `Customer` is very simply defined
in terms of an `id` and `name`, which will be used to lookup a `Customer`. in terms of an `id` and `name`, which will be used to lookup a `Customer`.
[[geode-samples-caching-multisite-example-customerservice]] [[geode-samples-caching-multisite-example-customerservice]]
@@ -244,24 +245,24 @@ cache the results of the `findBy(..)` method. Since a `Customer's` "name" is not
candidate for caching. candidate for caching.
`@Cacheable` works by first searching for the `Customer` by "name" in the "CustomerByName" cache. If an entry is found, `@Cacheable` works by first searching for the `Customer` by "name" in the "CustomerByName" cache. If an entry is found,
then the cached value (i.e. `Customer`) is returned. Otherwise, the `findBy(..)` method is invoked to lookup the then the cached value (i.e. `Customer`) is returned immediately, without invoking the `findBy(..)` method. Otherwise,
`Customer` by "name". When the `findBy(..)` method returns, assuming it does not return a `null` value, then `@Cacheable` the `findBy(..)` method is invoked to lookup the `Customer` by "name". When the `findBy(..)` method returns, assuming
will store the `Customer` in the cache keyed by the `Customer's` "name" (i.e. the "name" argument passed to it does not return a `null` value, then `@Cacheable` logic will store the `Customer` in the cache keyed by the
the `findBy(..)` method). `Customer's` "name" (i.e. the "name" argument passed to the `findBy(..)` method).
To make the `findBy(..)` operation appear to be expensive (either time or resource consuming), we add a safe Thread To make the `findBy(..)` operation appear to be expensive (either time or resource consuming), we add a safe Thread
sleep call. Otherwise, the `findBy(..)` method simply constructs a new `Customer` with the given "name" and returns it. sleep call. Otherwise, the `findBy(..)` method simply constructs a new `Customer` with the given "name" and returns it.
The `CustomerService` class contains a `isCacheMiss()` method to determine whether the `Customer` was found in the cache The `CustomerService` class contains a `isCacheMiss()` method to determine whether the `Customer` was found in the cache
mapped to the givne "name", or if the `findBy(..)` method had to be invoked (i.e. a _cache miss_). mapped to the given "name", or if the `findBy(..)` method had to be invoked (i.e. a _cache miss_).
What is not apparent from looking at the `findBy(..)` service method is how the _Look-Aside Cache_ pattern is decorated, What is not apparent from looking at the `findBy(..)` service method is how the _Look-Aside Cache_ pattern is decorated,
or enhanced with _Multi-Site (WAN) Caching_. It turns out to be all in the configuration as we will see further below. or enhanced by _Multi-Site (WAN) Caching_. It turns out to be all in the configuration as we will see further below.
[[geode-samples-caching-multisite-example-customercontroller]] [[geode-samples-caching-multisite-example-customercontroller]]
=== `CustomerController` class === `CustomerController` class
Finally, we add `CustomerController` class exposing a simple REST interface for our application: Finally, we add `CustomerController` class exposing a simple REST interface to the Web application:
.CustomerController class .CustomerController class
[source,java] [source,java]
@@ -270,7 +271,7 @@ include::{samples-dir}/caching/multi-site/src/main/java/example/app/caching/mult
---- ----
The `CustomerController` is a Spring Web MVC `@RestController`, which uses the `CustomerService` class, and allows users The `CustomerController` is a Spring Web MVC `@RestController`, which uses the `CustomerService` class, and allows users
to search for `Customers` using a Web browser. to search for `Customers` by "name" using a Web browser.
[[geode-samples-caching-multisite-example-client-app]] [[geode-samples-caching-multisite-example-client-app]]
=== Spring Boot, {geode-name} `ClientCache` application === Spring Boot, {geode-name} `ClientCache` application
@@ -411,12 +412,12 @@ Compare and contrast this with the Spring Boot `application.properties` for clus
[[geode-samples-caching-multisite-example-server-configuration]] [[geode-samples-caching-multisite-example-server-configuration]]
=== Cluster/Server Configuration === Cluster/Server Configuration
Let's break down the `BootGeodeMultiSiteCachingServerApplication` class configuration a bit further. Let's break down the `BootGeodeMultiSiteCachingServerApplication` class configuration in more detail.
[[geode-samples-caching-multisite-example-server-configuration-cacheserver-region]] [[geode-samples-caching-multisite-example-server-configuration-cacheserver-region]]
==== `CacheServer` and "_CustomersByName_" `Region` Configuration ==== `CacheServer` and "_CustomersByName_" `Region` Configuration
First, we have the configuration for the peer `Cache`, `CacheServer` and "CustomersByName" REPLICATE `Region`: This first bit of configuration creates a peer `Cache`, a `CacheServer` and the "CustomersByName" REPLICATE `Region`:
.CacheServer & Region .CacheServer & Region
[source,java] [source,java]
@@ -425,24 +426,24 @@ include::{samples-dir}/caching/multi-site/src/main/java/example/app/caching/mult
---- ----
The `CacheServer` port is set to the ephemeral port (i.e. `0`) to let the system allocate a port. Since the client is The `CacheServer` port is set to the ephemeral port (i.e. `0`) to let the system allocate a port. Since the client is
connecting to the cluster via a Locator, the Locator sends meta-data about the cluster to the client thereby informing connecting to the cluster via a Locator, the Locator sends meta-data about the cluster to the client informing
the client of the available `CacheServers`, which server is hosting what data, the port(s) the `CacheServer(s)` the client of the available `CacheServers`, which server is hosting what data, the port(s) the `CacheServer(s)`
are listening on, and so on. are listening on, and so on.
The name of the client and server-side Region backing the cache named in the `@Cacheable` annotation declared on The name of the client and server-side `Region` backing the cache named in the `@Cacheable` annotation declared on
the `CustomerService.findBy(..)` method must match. The client-side "CustomersByName" `Region` is a PROXY, and the `CustomerService.findBy(..)` method must match. The client-side "CustomersByName" `Region` is a PROXY, and
therefore forwards all data access operations to the matching server-side REPLICATE Region by the same name therefore forwards all data access operations to the matching server-side REPLICATE `Region` by the same name
(i.e. "CustomersByName"). (i.e. "CustomersByName").
TIP: The `DataPolicy` of the server-side, "CustomersByName" `Region` could have been PARTITION, sharding the data across TIP: The `DataPolicy` of the server-side, "CustomersByName" `Region` could have been PARTITION, thereby sharding the
the servers in the cluster that host the "CustomersByName" `Region`. However, it is common for "reference" data, such as data across the servers in the cluster that host the "CustomersByName" `Region`. However, it is common for "reference"
"cached" data, to be stored in a REPLICATE `Region`. However, if the data is transactional in anyway, then it is data, such as "cached" data, to be stored in a REPLICATE `Region`. Although, if the data is transactional in nature,
recommended that you use a PARTITION `Region`. then it is recommended that you use a PARTITION `Region`.
[[geode-samples-caching-multisite-example-server-configuration-locator-manager]] [[geode-samples-caching-multisite-example-server-configuration-locator-manager]]
==== `Locator` and `Manager` Configuration ==== `Locator` and `Manager` Configuration
The next bit of configuration involves enabling the embedded Locator and starting a Manager service inside the server: The next bit of configuration enables an embedded Locator and starts a Manager service inside the server:
.Locator & Manager .Locator & Manager
[source,java] [source,java]
@@ -450,8 +451,8 @@ The next bit of configuration involves enabling the embedded Locator and startin
include::{samples-dir}/caching/multi-site/src/main/java/example/app/caching/multisite/server/BootGeodeMultiSiteCachingServerApplication.java[tags=locator-manager-configuration] include::{samples-dir}/caching/multi-site/src/main/java/example/app/caching/multisite/server/BootGeodeMultiSiteCachingServerApplication.java[tags=locator-manager-configuration]
---- ----
If you are starting up a multi-node cluster, then you can choose whether to start an embedded Locator & Manager If you are starting up a multi-node cluster, then you can choose whether to start an embedded Locator and Manager
on a node-by-node basis. If you do, you must vary the port numbers or configure the Locator & Manager using on a node-by-node basis. If you do, you must vary the port numbers or configure the Locator and Manager using
the ephemeral port. the ephemeral port.
We'll see below how configuring a Manager can be useful for inspecting the cluster using _Gfsh_. But first, let's We'll see below how configuring a Manager can be useful for inspecting the cluster using _Gfsh_. But first, let's
@@ -460,9 +461,9 @@ talk about the final bit of configuration that enables _Multi-Site Caching_ with
[[geode-samples-caching-multisite-example-server-configuration-gateway-sender-receiver]] [[geode-samples-caching-multisite-example-server-configuration-gateway-sender-receiver]]
==== `GatewaySender` and `GatewayReceiver` Configuration ==== `GatewaySender` and `GatewayReceiver` Configuration
The final bit of configuration configures a `GatewaySender` for sending `Region` operations from this cluster The final bit of configuration configures a `GatewaySender` for sending `Region` events from this cluster
(e.g. cluster #1) to a remote cluster (e.g. cluster #2). Gateways are an essential component for enabling (i.e. cluster #1) to a remote cluster (e.g. cluster #2). {geode-name} (or {gemfire-name}) Gateways are the essential
_Multi-Site Caching_ using a WAN topology: component for enabling _Multi-Site Caching_ using a WAN topology:
.Gateway Sender & Receiver .Gateway Sender & Receiver
[source,java] [source,java]
@@ -474,35 +475,37 @@ Just as the Locator communicates cluster meta-data to the clients allowing clien
servers, and specifically `CacheServers` in the cluster, the remote Locator endpoint communicates cluster meta-data servers, and specifically `CacheServers` in the cluster, the remote Locator endpoint communicates cluster meta-data
between sites. between sites.
While a `GatewaySender` is configured per `Region`, a `GatewayReceiver` is setup for the entire cluster, and the Gateway While a `GatewaySender` is configured per `Region`, a `GatewayReceiver` is setup per server, and the Gateway events
events are then routed to the right cluster objects, typically `Regions`. `GatewaySenders` are `Region` specific since are routed to the appropriate server objects, such as `Regions`. `GatewaySenders` are `Region` specific since you might
you might have different {apache-geode-javadoc}/org/apache/geode/cache/wan/GatewayEventFilter.html[event filters] have different {apache-geode-javadoc}/org/apache/geode/cache/wan/GatewayEventFilter.html[event filters] coupled with
combined with {apache-geode-javadoc}/org/apache/geode/cache/wan/GatewayEventSubstitutionFilter.html[event substitution filtering] {apache-geode-javadoc}/org/apache/geode/cache/wan/GatewayEventSubstitutionFilter.html[event substitution filtering],
or different {apache-geode-javadoc}/org/apache/geode/cache/wan/GatewayTransportFilter.html[transports], etc. or be using different {apache-geode-javadoc}/org/apache/geode/cache/wan/GatewayTransportFilter.html[transports], etc.
You can even control the _concurrency-level_ along with the {apache-geode-javadoc}/org/apache/geode/cache/wan/GatewaySender.OrderPolicy.html[order of events] You can even control the _concurrency-level_ along with the {apache-geode-javadoc}/org/apache/geode/cache/wan/GatewaySender.OrderPolicy.html[order of events]
passing through the Gateway(s). In fact, there are many aspects of Gateways you can control, different configurations to passing through the Gateway(s). In fact, there are many aspects of Gateways you can control, different configurations
use, conflict resolution policies, etc, setup to properly address the unique requirements (or SLAs) of your application you can use, conflict resolution policies, etc, in order to properly address the unique requirements (or SLAs) of your
use case(s), that are quite frankly, well beyond the scope of this guide. Therefore, you are encouraged to follow the application use case(s), that are quite frankly, well beyond the scope of this guide. Therefore, you are encouraged to
{apache-geode-docs}/topologies_and_comm/multi_site_configuration/chapter_overview.html[User Guide] for further guidance. follow the {geode-name} {apache-geode-docs}/topologies_and_comm/multi_site_configuration/chapter_overview.html[User Guide]
for further guidance.
Although, there is 1 aspect of the configuration we want to address here, and that is _Active-Active_ Although, there is 1 aspect of the Gateway configuration we want to address here, and that is _Active-Active_
vs. _Active-Passive_. vs. _Active-Passive_.
Currently, the example is setup to use _Active-Active_ replication, where all clusters are actors in the overall Currently, the example is setup to use _Active-Active_ replication, where all clusters are actors in the overall
system architecture. However, it is a simple matter to setup our system architecture using the _Active-Passive_ pattern. system architecture. However, it is a simple matter to setup the system architecture using an _Active-Passive_
WAN Gateway pattern.
You can do this by limiting the `GatewaySender` configuration to, for example, cluster/site #1. That is, you do not You do this by limiting the `GatewaySender` configuration to cluster/site #1, for example. That is, you do not
configure a `GatewaySender` on the "CustomersByName" `Region` in cluster/site #2. Cluster #2 still requires a configure a `GatewaySender` on the "CustomersByName" `Region` in cluster/site #2. Cluster #2 still requires a
`GatewayReceiver` so events sent from cluster #1 are received by and replicated in cluster #2. This arrangement is used `GatewayReceiver` so Gateway events sent from cluster #1 are received by and replicated in cluster #2. This arrangement
in cases where no clients can actively connect directly to cluster #2 thereby positioning cluster #2 for standby in the is commonly used to position cluster #2 for standby in the event that cluster #1 goes down. As such, no clients can
event the cluster #1 goes down. connect directly to cluster #2.
Therefore, we have declared Spring Profiles for each side of the Gateway, the receiving side (`GatewayReceiver`) along The configuration declares Spring Profiles for each side of the Gateway, the receiving side (`GatewayReceiver`) along
with the sending side (`GatewaySender`). The sending side clearly does not require a `GatewayReceiver` when it is the with the sending side (`GatewaySender`). The sending side clearly does not require a `GatewayReceiver` when it is the
"_Active_" cluster in the _Active-Passive_ architecture. _Active-Passive_ replication is 1-way. "_Active_" cluster in the _Active-Passive_ architecture. _Active-Passive_ replication is 1-way.
Now that we have talked about the configuration in detail, let's run the example and have a look at the cluster Now that we have talked about the configuration in more detail, let's run the example and have a look at the cluster
using _Gfsh_. using _Gfsh_.
[[geode-samples-caching-multisite-example-run]] [[geode-samples-caching-multisite-example-run]]
@@ -540,10 +543,11 @@ configuration. The configuration for each cluster has been neatly encapsulated i
file denoted by a Spring Profile, i.e. `server-site1` for cluster #1 and `server-site2` for cluster #2. file denoted by a Spring Profile, i.e. `server-site1` for cluster #1 and `server-site2` for cluster #2.
Therefore, to start a cluster, simply run the `BootGeodeMultiSiteCachingServerApplication` class from your IDE Therefore, to start a cluster, simply run the `BootGeodeMultiSiteCachingServerApplication` class from your IDE
and enable the Spring Profile for the cluster you want start, e.g. cluster #1 using: and enable the Spring Profile for the cluster you want start, e.g. to start cluster #1 use:
`-Dspring.profiles.active=server-site1`. `-Dspring.profiles.active=server-site1`.
To run cluster #2, simply create another run configuration with the Spring Profile set to `server-site2`. To start cluster #2, simply create another run configuration in your IDE with the
`BootGeodeMultiSiteCachingServerApplication` class with the Spring Profile set to `server-site2`.
When the cluster starts up, you should see log output similar to (log output formatted to fit this guide): When the cluster starts up, you should see log output similar to (log output formatted to fit this guide):
@@ -860,7 +864,7 @@ Region | data-policy | REPLICATE
---- ----
Even though the `GatewaySender` and `GatewayReceiver` were configured correctly, _Gfsh_ apparently is not aware of it, Even though the `GatewaySender` and `GatewayReceiver` were configured correctly, _Gfsh_ apparently is not aware of it,
at least not by `list gateways`: at least not by `list gateways` command, anyway:
[source,text] [source,text]
---- ----
@@ -870,7 +874,7 @@ GatewaySenders or GatewayReceivers are not available in cluster
---- ----
Interestingly, the `describe region` command for the "CustomersByName" `Region` does appropriately show the `Region` Interestingly, the `describe region` command for the "CustomersByName" `Region` does appropriately show the `Region`
has a `GatewaySender` identified as "customersByNameGatewaySender". has a `GatewaySender` identified as "customersByNameGatewaySender", as we expect!
[[geode-samples-caching-multisite-example-run-clients]] [[geode-samples-caching-multisite-example-run-clients]]
=== Start the Clients === Start the Clients
@@ -1068,12 +1072,12 @@ After the client has successfully started, you can see that the client has conne
.Client connected to cluster .Client connected to cluster
[source,text] [source,text]
---- ----
Cluster-10 gfsh>list clients list clients
Client List Client List
Client Name / ID | Server Name / ID Client Name / ID | Server Name / ID
------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------
10.99.199.24(BootGeodeMultiSiteCachingClientApplication-Site1:47756:loner):... | member=BootGeodeMultiSiteCachingServerApplication-Site1,port=51682 10.99.199.24(BootGeodeMultiSiteCachingClientApplication-Site1:47756:loner):52447:333e0094:BootGeodeMultiSiteCachingClientApplication-Site1 | member=BootGeodeMultiSiteCachingServerApplication-Site1,port=51682
---- ----
@@ -1096,17 +1100,16 @@ effects of a resource expensive operation, we add a 5 second delay, which if you
include::{samples-dir}/caching/multi-site/src/main/java/example/app/caching/multisite/client/service/CustomerService.java[tags=find-by-name] include::{samples-dir}/caching/multi-site/src/main/java/example/app/caching/multisite/client/service/CustomerService.java[tags=find-by-name]
---- ----
On subsequent access, the operation results in a cache hit given the same argument (e.g. "JonDoe"), and we again witness On subsequent access, the operation results in a cache hit when given the same argument (e.g. "JonDoe"), and we again
the effects that caching now has on our application (i.e. no 5 second delay; the result is returned immediately). witness the effects that caching now has on our application (i.e. no 5 second delay; the result is returned immediately).
Simply hit refresh in your Web browser to resubmit the HTTP request and receive a response: Simply hit refresh in your Web browser to resubmit the HTTP request and receive a response:
image::{images-dir}/Multi-Site-Caching-Client-Application-1-Customer-JonDoe-CacheHit.png[] image::{images-dir}/Multi-Site-Caching-Client-Application-1-Customer-JonDoe-CacheHit.png[]
Of course, this only half of the equation. What happens when we access "JonDoe" from site #2 using client #2? This time, the access was a cache hit! Of course, this is only half of the equation. What happens when we access
"JonDoe" from site #2 using client #2? Well, "JonDoe" has already been replicated from cluster #1 to cluster #2
Well, "JonDoe" has already been replicated from cluster #1 to cluster #2 and therefore, the operation results in and therefore, the operation results in a cache hit:
a cache hit:
image::{images-dir}/Multi-Site-Caching-Client-Application-2-Customer-JonDoe-CacheHit.png[] image::{images-dir}/Multi-Site-Caching-Client-Application-2-Customer-JonDoe-CacheHit.png[]
@@ -1117,14 +1120,13 @@ image::{images-dir}/Multi-Site-Caching-Client-Application-2-Customer-JaneDoe-Cac
Of course, if we hit refresh in our Web browser, then the subsequent access of "JaneDoe" from client #2 should result Of course, if we hit refresh in our Web browser, then the subsequent access of "JaneDoe" from client #2 should result
in a cache hit. However, without hitting refresh, let's immediately go back to client #1 and try to access "JaneDoe". in a cache hit. However, without hitting refresh, let's immediately go back to client #1 and try to access "JaneDoe".
The result is already a cache hit since the "JaneDoe" has already been replicated between the 2 sites over the WAN The result is a cache hit since the "JaneDoe" has already been replicated between the 2 sites over the WAN Gateways:
Gateways:
image::{images-dir}/Multi-Site-Caching-Client-Application-1-Customer-JaneDoe-CacheHit.png[] image::{images-dir}/Multi-Site-Caching-Client-Application-1-Customer-JaneDoe-CacheHit.png[]
After our testing, we can query the data in _Gfsh_: In addition to testing in a Web browser, you can also query the data using _Gfsh_:
.Querying the Customers from Gfsh .Querying "CustomersByName" from Gfsh
[source,text] [source,text]
---- ----
Cluster-10 gfsh>describe region --name=CustomersByName Cluster-10 gfsh>describe region --name=CustomersByName
@@ -1162,10 +1164,11 @@ configured, SBDG will configure {geode-name}'s PDX Serialization framework.
PDX allows you to query objects in serialized form, without causing a deserialization, as long as you know the structure PDX allows you to query objects in serialized form, without causing a deserialization, as long as you know the structure
of your application domain model types. Using PDX can be helpful in situations where your application domain model types of your application domain model types. Using PDX can be helpful in situations where your application domain model types
refer to 3rd party library types you cannot control, and that may not be `java.io.Serializable`. refer to 3rd party library types you cannot control, and that may not implement `java.io.Serializable`.
You should refer to the {geode-name} User Guide on more details on TIP: You should refer to the {geode-name} User Guide on more details on
{apache-geode-docs}/developing/data_serialization/gemfire_pdx_serialization.html[PDX]. {apache-geode-docs}/developing/data_serialization/gemfire_pdx_serialization.html[PDX]. You can also refer to SBDG's
support of link:../index.html#geode-data-serialization[PDX Serialization].
You can try other experiments, too. For example, you can rerun this example with the _Active-Passive_ pattern, which we You can try other experiments, too. For example, you can rerun this example with the _Active-Passive_ pattern, which we
leave as an exercise for the curious reader. leave as an exercise for the curious reader.
@@ -1175,7 +1178,7 @@ leave as an exercise for the curious reader.
You have now just learned and witnessed first-hand the power of _Look-Aside Caching_ enhanced with _Multi-Site Caching_, You have now just learned and witnessed first-hand the power of _Look-Aside Caching_ enhanced with _Multi-Site Caching_,
implemented with {geode-name} (or {gemfire-name}) WAN Gateway functionality. This is but a simple example. WAN Gateway implemented with {geode-name} (or {gemfire-name}) WAN Gateway functionality. This is but a simple example. WAN Gateway
functionality can accommodate a wide-range of different use cases. functionality can accommodate a wide-range of different use cases and complex configuration.
Imagine if timely and accurate (i.e. "consistent") information is a major concern for your application use case Imagine if timely and accurate (i.e. "consistent") information is a major concern for your application use case
and your application is backed by an RDBMS for its _System of Record_ (SOR). How do you keep the remote database and your application is backed by an RDBMS for its _System of Record_ (SOR). How do you keep the remote database
@@ -1186,11 +1189,11 @@ between the clusters, like so:
image::{images-dir}/Look-Aside--Near--Inline--Multi-Site-Caching.png[] image::{images-dir}/Look-Aside--Near--Inline--Multi-Site-Caching.png[]
In this image, we also depicted the use of _Near Caching_ to reduce network traffic. The system architecture could In this image, we also depicted the use of _Near Caching_ to reduce network traffic between the client(s)
optionally use the _Active-Active_ WAN Gateway pattern and the cluster on the right, could optionally serve application and the servers in the cluster. The system architecture could optionally use the _Active-Active_ WAN Gateway pattern
clients, or not, which might be the case in an _Active-Passive_ configuration. The choice is yours and you are only and the cluster on the right could optionally serve application clients, or not, which might be the case in an
limited by your imagination and constrained by your application requirements. Whatever the case, you have extreme power _Active-Passive_ configuration. The choice is yours and you are only limited by your imagination and constrained by
and flexibility at your fingertips. your application requirements. Whatever the case, you have extreme power and flexibility at your fingertips.
Indeed, when you combine and apply multiple patterns of caching (_Look-Aside_, _Near_, _Inline_ and now, Indeed, when you combine and apply multiple patterns of caching (_Look-Aside_, _Near_, _Inline_ and now,
_Multi-Site Caching_) to your applications, you can greatly enhance your end-users experience. _Multi-Site Caching_) to your applications, you can greatly enhance your end-users experience.