ZiggyCreatures / FusionCache

FusionCache is an easy to use, fast and robust hybrid cache with advanced resiliency features.
MIT License
1.56k stars 84 forks source link

Distributed invalidation without backplane? #259

Closed DanielStout5 closed 1 month ago

DanielStout5 commented 1 month ago

Problem

I'd like to use FusionCache with a distributed cache, but without a backplane (trying to avoid adding another dependency, and the cost of Redis for many separate small sites). In that case it doesn't seem like we can ever trust the in-memory values from the other server(s).

Solution

One solution seems like it would be to poll the distributed cache in the background - not necessarily for actual cached values, but for something that indicates whether to invalidate values stored in memory.

Polling doesn't seem ideal since it would add many requests to the distributed cache even if the values never change or aren't even being read.

A fix at least for polling when values aren't being read would be to trigger the distributed cache check when reading an in-memory value which hasn't been checked against the distributed value for a configurable period of time.

Is there support for anything like that built-in?

An alternative could be to just use the distributed cache without ever checking in-memory, but some of the other features of FusionCache like stampede prevention would be nice to have.

DanielStout5 commented 1 month ago

I think a much simpler solution will just be to have a very short Duration (for the in-memory cache) and a long distributed duration:

DefaultEntryOptions = new FusionCacheEntryOptions
{
    Duration = TimeSpan.FromSeconds(30),
    DistributedCacheDuration = TimeSpan.FromHours(24)
}

And for invalidations just call FusionCache.RemoveAsync

jodydonetti commented 1 month ago

Hi @DanielStout5 and thanks for using FusionCache and sorry for the delay.

I'd like to use FusionCache with a distributed cache, but without a backplane (trying to avoid adding another dependency, and the cost of Redis for many separate small sites)

Out of curiosity, what are you using as a distributed cache? I'm asking since 9 times out of 10 it's Redis, so enabling the backplane does not incur in extra costs, but here you are probably using something else.

In that case it doesn't seem like we can ever trust the in-memory values from the other server(s).

Yes, without the backplane the other nodes may be behind, since the backplane itself is the mechanism to do exactly that.

I think a much simpler solution will just be to have a very short Duration (for the in-memory cache) and a long distributed duration: And for invalidations just call FusionCache.RemoveAsync

Exactly what I was about to suggest: low duration in memory, normal duration in distributed, active invalidation when possible via Remove/Expire: this usually works very well. I would also suggest enabling fail-safe and soft/hard timeouts for extra protection in case something goes wrong.

Hope this helps!

DanielStout5 commented 1 month ago

Out of curiosity, what are you using as a distributed cache? I'm asking since 9 times out of 10 it's Redis, so enabling the backplane does not incur in extra costs, but here you are probably using something else.

Azure Table Storage. If we were using Redis we would definitely also use the backplane feature!

jodydonetti commented 1 month ago

Ooh, never heard of an IDistributedCache impl based on Azure Table Storage, tell me more please.

Which impl are you using? How is it working? Any limitation or something to know about?

Thanks!

DanielStout5 commented 1 month ago

Which impl are you using?

It's a custom implementation inspired by this one with some simplifications and improvements (e.g. using multiple partitions rather than putting all keys in the same partition)

How is it working?

Seems good so far! We were already using Azure Blob Storage, so also using Table Storage was convenient. We can view the contents of the distributed cache using the Azure Storage Explorer. Latency is acceptable (surely not as fast as Redis, but sufficient for our use-case)

Any limitation or something to know about?

Haven't run into any issues so far! It's very cost effective, just $0.000000036 USD per transaction (read/write) which is $36 USD for 1 billion reads.

jodydonetti commented 1 month ago

It's a custom implementation inspired by this one with some simplifications and improvements (e.g. using multiple partitions rather than putting all keys in the same partition)

Nice! If you are planning on releasing it let me know: I've collected here most of them, and it can be useful for others, too.

Seems good so far! We were already using Azure Blob Storage, so also using Table Storage was convenient. We can view the contents of the distributed cache using the Azure Storage Explorer. Latency is acceptable (surely not as fast as Redis, but sufficient for our use-case)

Good to know, another tool in our toolbelt.

Haven't run into any issues so far! It's very cost effective, just $0.000000036 USD per transaction (read/write) which is $36 USD for 1 billion reads.

And tha is nice actually: I've heard people on Azure using the SqlServer based implementation to not pay for the extra Redis instance, and this can be a nice alternative to consider, thanks for letting me know!