Skip to content

Commit

Permalink
Docs
Browse files Browse the repository at this point in the history
  • Loading branch information
jodydonetti committed Jun 18, 2022
1 parent 58e237d commit 9efcd90
Show file tree
Hide file tree
Showing 8 changed files with 42 additions and 33 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ On August 2021, FusionCache received the [Google Open Source Peer Bonus Award](h
## :heavy_check_mark: Features
These are the **key features** of FusionCache:

- [**🚀 Cache Stampede prevention**](docs/FactoryOptimization.md): using the optimized `GetOrSet[Async]` method prevents multiple concurrent factory calls per key, with a guarantee that only 1 will be executed at the same time for the same key. This avoids overloading the data source when no data is in the cache or when a cache entry expires
- [**🚀 Cache Stampede prevention**](docs/CacheStampede.md): using the optimized `GetOrSet[Async]` method prevents multiple concurrent factory calls per key, with a guarantee that only 1 will be executed at the same time for the same key. This avoids overloading the data source when no data is in the cache or when a cache entry expires
- [**🔀 2nd level (optional)**](docs/CacheLevels.md): FusionCache can transparently handle an optional 2nd level cache: anything that implements the standard `IDistributedCache` interface is supported like Redis, MongoDB, CosmosDB, SqlServer, etc
- [**📢 Backplane**](docs/Backplane.md): when using a distributed cache as a 2nd layer in a multi-node scenario, you can also enable a backplane to immediately notify the other nodes about changes in the cache, to keep everything synchronized without having to do anything
- [**💣 Fail-Safe**](docs/FailSafe.md): enabling the fail-safe mechanism prevents throwing an exception when a factory or a distributed cache call would fail, by reusing an expired entry as a temporary fallback, all transparently and with no additional code required
Expand Down Expand Up @@ -231,7 +231,7 @@ The documentation is available in the :open_file_folder: [docs](docs/README.md)
- [**🦄 A Gentle Introduction**](docs/AGentleIntroduction.md): what you need to know first
- [**🔀 Cache Levels**](docs/CacheLevels.md): a bried description of the 2 available caching levels and how to setup them
- [**📢 Backplane**](docs/Backplane.md): how to get an always synchronized cache, even in a multi-node scenario
- [**🚀 Cache Stampede prevention**](docs/FactoryOptimization.md): no more overloads during a cold start or after an expiration
- [**🚀 Cache Stampede prevention**](docs/CacheStampede.md): no more overloads during a cold start or after an expiration
- [**💣 Fail-Safe**](docs/FailSafe.md): an explanation of how the fail-safe mechanism works
- [**⏱ Timeouts**](docs/Timeouts.md): the various types of timeouts at your disposal (calling a factory, using the distributed cache, etc)
- [**🧙‍♂️ Adaptive Caching**](docs/AdaptiveCaching.md): how to adapt cache duration (and more) based on the object being cached itself
Expand Down
4 changes: 2 additions & 2 deletions docs/AGentleIntroduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ To avoid this and have everything always synchronized you can use a backplane, a
You can read more [**here**](Backplane.md), or enjoy the complete [**step by step**](StepByStep.md) guide.


## 🚀 Factory ([more](FactoryOptimization.md))
## 🚀 Factory ([more](CacheStampede.md))

A factory is just a function that you specify when using the main `GetOrSet[Async]` method: basically it's the way you specify **how to get a value** when it's needed.

Expand All @@ -81,7 +81,7 @@ FusionCache will search for the value in the cache (*memory* and *distributed*,

Special care has been put into ensuring that **only 1** factory per-key will be executed concurrently, to avoid what is known as [Cache Stampede](https://en.wikipedia.org/wiki/Cache_stampede).

You can read more [**here**](FactoryOptimization.md), or enjoy the complete [**step by step**](StepByStep.md) guide.
You can read more [**here**](CacheStampede.md), or enjoy the complete [**step by step**](StepByStep.md) guide.


## 💣 Fail-Safe ([more](FailSafe.md))
Expand Down
33 changes: 33 additions & 0 deletions docs/CacheStampede.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<div align="center">

![FusionCache logo](logo-128x128.png)

</div>

# :rocket: Cache Stampede prevention

A [Cache Stampede](https://en.wikipedia.org/wiki/Cache_stampede) is a typical failure you may encounter while using caching in a high load scenario: FusionCache takes great care in coordinating the execution of concurrent factories for the same cache key, to avoid this type of failure altogether.

Inside FusionCache a factory is just a function that you specify when using the main `GetOrSet[Async]` method: basically it's the way you specify **how to get a value** when it is not in the cache or is expired.

Here's an example:

```csharp
var id = 42;

var product = cache.GetOrSet<Product>(
$"product:{id}",
_ => GetProductFromDb(id), // THIS IS THE FACTORY
options => options.SetDuration(TimeSpan.FromMinutes(1))
);
```

FusionCache will search for the value in the cache (*memory* and *distributed*, if available) and, if nothing is there, will call the factory to obtain the value: it then saves it into the cache with the specified options, and returns it to the caller, all transparently.

Special care is put into calling just one factory per key, concurrently: this means that if 10 (or 100, or more) concurrent requests for the same key arrive at the same time and the data is not there, **only one factory** will be executed, and the result will be stored and shared with all callers right away.

![Factory Call Optimization](images/factory-optimization.png)

As you can see, when multiple concurrent `GetOrSet[Async]` calls are made for the same key, only 1 of them will be executed: the returned value will be cached to be readily available, and then returned to all the callers for the same cache key.

This ensures that the data source (let's say a database) **will not be overloaded** with multiple requests for the same piece of data at the same time.
2 changes: 1 addition & 1 deletion docs/Comparison.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ In trying to make an honest and generic overview I've identified a set of **very

The general features I've identified are:

- [**Cache Stampede prevention**](FactoryOptimization.md): the ability to guarantee only one factory will be executed concurrently per-key, even in highly concurrent scenarios. This will reduce a lot the load on your origin datasource (database, etc)
- [**Cache Stampede prevention**](CacheStampede.md): the ability to guarantee only one factory will be executed concurrently per-key, even in highly concurrent scenarios. This will reduce a lot the load on your origin datasource (database, etc)
- **Native sync/async support**: native support for both programming models. Even though nowadays the async one is more widly used and in general more performant, they are both useful and have their place in everyday usage
- [**Fail-Safe**](FailSafe.md) (or similar mechanism): in general the ability to temporarily re-use an expired entry in case it's currently not possible to get a new one. This can greatly reduce transient errors in your application
- [**Timeouts**](Timeouts.md): the ability to avoid factories to run for too long, potentially creating a blocking situation or resulting in too slow responses
Expand Down
2 changes: 1 addition & 1 deletion docs/CoreMethods.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ If instead the value is not in the cache (or is expired) it can automatically **

- a **DEFAULT VALUE**: that will be **SET** in the cache and returned to you

- a [**FACTORY**](FactoryOptimization.md) method: it will be executed, and if the execution goes well the obtained value will be **SET** in the cache and returned to you
- a [**FACTORY**](CacheStampede.md) method: it will be executed, and if the execution goes well the obtained value will be **SET** in the cache and returned to you

These are the happy paths.

Expand Down
26 changes: 1 addition & 25 deletions docs/FactoryOptimization.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,4 @@

# :rocket: Cache Stampede prevention

A [Cache Stampede](https://en.wikipedia.org/wiki/Cache_stampede) is a typical failure you may encounter while using caching in a high load scenario: FusionCache takes great care in coordinating the execution of concurrent factories for the same cache key, to avoid this type of failure altogether.

Inside FusionCache a factory is just a function that you specify when using the main `GetOrSet[Async]` method: basically it's the way you specify **how to get a value** when it is not in the cache or is expired.

Here's an example:

```csharp
var id = 42;

var product = cache.GetOrSet<Product>(
$"product:{id}",
_ => GetProductFromDb(id), // THIS IS THE FACTORY
options => options.SetDuration(TimeSpan.FromMinutes(1))
);
```

FusionCache will search for the value in the cache (*memory* and *distributed*, if available) and, if nothing is there, will call the factory to obtain the value: it then saves it into the cache with the specified options, and returns it to the caller, all transparently.

Special care is put into calling just one factory per key, concurrently: this means that if 10 (or 100, or more) concurrent requests for the same key arrive at the same time and the data is not there, **only one factory** will be executed, and the result will be stored and shared with all callers right away.

![Factory Call Optimization](images/factory-optimization.png)

As you can see, when multiple concurrent `GetOrSet[Async]` calls are made for the same key, only 1 of them will be executed: the returned value will be cached to be readily available, and then returned to all the callers for the same cache key.

This ensures that the data source (let's say a database) **will not be overloaded** with multiple requests for the same piece of data at the same time.
This content has been moved to the [CacheStampede](CacheStampede.md) page.
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ A deeper description of the main features:

- [**🔀 Cache Levels**](CacheLevels.md): a bried description of the 2 available caching levels and how to setup them
- [**📢 Backplane**](Backplane.md): how to get an always synchronized cache, even in a multi-node scenario
- [**🚀 Cache Stampede prevention**](FactoryOptimization.md): no more overloads during a cold start or after an expiration
- [**🚀 Cache Stampede prevention**](CacheStampede.md): no more overloads during a cold start or after an expiration
- [**💣 Fail-Safe**](FailSafe.md): an explanation of how the fail-safe mechanism works
- [**⏱ Timeouts**](Timeouts.md): the various types of timeouts at your disposal (calling a factory, using the distributed cache, etc)
- [**🧙‍♂️ Adaptive Caching**](AdaptiveCaching.md): how to adapt cache duration (and more) based on the object being cached itself
Expand Down
2 changes: 1 addition & 1 deletion src/ZiggyCreatures.FusionCache/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ On August 2021, FusionCache received the [Google Open Source Peer Bonus Award](h
## ✔ Features
These are the **key features** of FusionCache:

- [**🚀 Cache Stampede prevention**](https://github.com/jodydonetti/ZiggyCreatures.FusionCache/blob/main/docs/FactoryOptimization.md): using the optimized `GetOrSet[Async]` method prevents multiple concurrent factory calls per key, with a guarantee that only 1 factory will be called at the same time for the same key (this avoids overloading the data source when no data is in the cache or when a cache entry expires)
- [**🚀 Cache Stampede prevention**](https://github.com/jodydonetti/ZiggyCreatures.FusionCache/blob/main/docs/CacheStampede.md): using the optimized `GetOrSet[Async]` method prevents multiple concurrent factory calls per key, with a guarantee that only 1 factory will be called at the same time for the same key (this avoids overloading the data source when no data is in the cache or when a cache entry expires)
- [**🔀 Optional 2nd level**](https://github.com/jodydonetti/ZiggyCreatures.FusionCache/blob/main/docs/CacheLevels.md): FusionCache can transparently handle an optional 2nd level cache: anything that implements the standard `IDistributedCache` interface is supported (eg: Redis, MongoDB, SqlServer, etc)
- [**📢 Backplane**](https://github.com/jodydonetti/ZiggyCreatures.FusionCache/blob/main/docs/Backplane.md): when using a distributed cache as a 2nd layer in a multi-node scenario, you can also enable a backplane to immediately notify the other nodes about changes in the cache, to keep everything synchronized without having to do anything
- [**💣 Fail-Safe**](https://github.com/jodydonetti/ZiggyCreatures.FusionCache/blob/main/docs/FailSafe.md): enabling the fail-safe mechanism prevents throwing an exception when a factory or a distributed cache call would fail, by reusing an expired entry as a temporary fallback, all transparently and with no additional code required
Expand Down

0 comments on commit 9efcd90

Please sign in to comment.