Replies: 13 comments 3 replies
-
Hi @brianmat thanks for your interest in FusionCache! Your issue is very detailed and well thought out, and it covers a scenario I'm not currently using a lot (Azure Functions) so there's a lot of food for thought. I'll take some time to think about it and see if I can come up with a reasonable path forward and a good design that makes sense. I'll update you asap. |
Beta Was this translation helpful? Give feedback.
-
Hi @jodydonetti , Any updates on that? |
Beta Was this translation helpful? Give feedback.
-
Hi @arnoldsi-vii , I've been quite busy with finishing the design and impl of the new backplane feature, which I finally released yesterday as a first alpha release 🎉 All of this took way more time and effort than expected to be able to support all the use cases that emerged from the community. Anyway, I'm saying this because I hope to be able to finally release the next official version very soon (hopefully next week 🤞), and after that I will go over the backlog which includes this very issue, too. Thanks. |
Beta Was this translation helpful? Give feedback.
-
I really like how this library progressing and In a future I probably will be able to add some PRs. Our platform Using mostly using Serverless where local cache is not really needed due serverless limits, but also EC2 machines where local cache with distributed do a great job |
Beta Was this translation helpful? Give feedback.
-
Thanks, appreciate that!
If it can be useful youcan find a comparison here.
Ahah thanks 😬
Yeah the serverless scenario is something I'd like to support more. I hope to be able to move on very soon, after the final release of the backplane. |
Beta Was this translation helpful? Give feedback.
-
@jodydonetti thank you. few ideas for future:
|
Beta Was this translation helpful? Give feedback.
-
Ok, help me to understand more please.
I thought about that initially, but I preferred to avoid an extra dependency. And thanks for this conversation, it's useful to me for collecting different experiences and opinions from the community, and it will help me to shape the future of FusionCache! |
Beta Was this translation helpful? Give feedback.
-
@jodydonetti i didn’t checked the current implementation of circuit breaker, I used Polly in our projects and it worked great (Polly has a lot of abilities as you know) As for serverless scenario. Lambda (aws scenario) lives for a very short time and has memory limit that you can use, therefore occupying memory in lambda for cache seems not a best option, usually redis in cloud environment close to those lambdas (serverless functions). to summarize, in serverless scenario main cache is distributed and backup is memory |
Beta Was this translation helpful? Give feedback.
-
@jodydonetti I want to give another example of serverless and would like to hear you thoughts of how the library will operate. Let's say we have lambda which will run for 500ms. user made first call to save the data. Memory save was 10ms. Then its started to save to distributed cache (in background) which from some reason started to take more than 500ms. This means the cache will never hit the distributed cache data and other nodes will never know about the change and might show wrong data. One solution to this issue is to disable background factory in serverless scenario, but from what I saw, if it fail to save to distributed cache it only log the error. Maybe you can add fail event (not sure that Other solution as I mentioned before is to make distribution cache as main cache, but I think it will lose the purpose of this awesome library. Let me know that you think. |
Beta Was this translation helpful? Give feedback.
-
@arnoldsi-vii thanks for the additional info, I'll think about it and let you know! |
Beta Was this translation helpful? Give feedback.
-
@arnoldsi-vii I don't think making distributed cache the main cache would hamper the library that much. In my opinion, one of the strong points of FusionCache is the ability to handle the fallback values correctly. It's easy to implement a simple Redis cache, but there's a lot of thought put into the cache update logic and I think that's very valuable. Serverless code does add a wrinkle and I think memorycache has a more limited value due to recycling of apps and management of state. |
Beta Was this translation helpful? Give feedback.
-
Hi @brianmat and @arnoldsi-vii , I'm getting back to my backlog of things to consider, so here we go. In general the main observation behind this proposal was that in some scenarios like serverless, the 1st layer (memory cache) can either 1) be avoided or 2) not be so prominent, since the instances where the code runs are short-lived. A suggested approach may be to just use a distributed cache ( 🗓️ The times they are a-changin'Some time has passed, and in this time some features have been added and changes have been made: because of this I'd like to get back to some of your previous points to re-evaluate them. The most important ones are the introduction of the backplane (which solves the synchronization problem) and/or the NOTE: I may comment again on some of your points already commented before, but I want to take this opportunity to re-evaluate everything so please excuse me if I repeat myself. But first, let's get back to the 2 proposals. 2️⃣ The 2 optionsBasically 2 possible solutions have been suggested:
Let's reason about them a little bit. Option 1: no memory cacheOne of the reasons against simply using a distributed cache instance ( If it's true that some of the other features like soft/hard timeouts would still work, others would not, or at least not fully. For example the cache stampede prevention would only work partially: while the factory is running you would have cache stampede prevention (so not a lot of database calls) but the same cannot be said for the initial distributed cache calls, all of which will be made (since without a local memory cache there would be nowhere to locally save the data and let other callers use it 🤷). Option 2: change orderIn this case the idea would be to keep the memory cache (so memory will be allocated, etc) but we would first check the distributed cache, and only then we would check the memory cache in case of problems. Here the problem would be the same as above for the cache stampede prevention related to the distributed cache, since all the calls to the distributed cache would need to be made. Other than that the points being made were related to local memory caches out-of-sync, and I don't see much value in this approach since the introduction of the backplane and the Now I'd like to comment on specific points made by you. 🙋♂️ Points made by @brianmat
As I said without a memory cache there would be nothing to fall back to, in case Redis would fail. How would you approach this in such scenario?
One thought in general is that, after the beginning of this discussion, I've finally introduced the backplane which would really solve the synchronization problem between an updated distributed cache and a local memory cache. On top of that the recent introduction of the Do you think one of these new approaches (either a backplane or different durations) would cover your scenario?
I'm open to this idea, but at the same time it may be a lot of work and introduce new behaviours and edge cases to handle, so I'd like to know if you are still of the same idea and exactly why you would still like to specify a preferred cache type with the other 2 options available.
Agree, but I think you would agree that at this point we are not talking about the option 1 (no memory cache) approach, since there would not be a fallback in case of Redis problems, but only about the option 2 (distributed-first-memory-second), am I right?
Since I don't have a lot of real-world experience with a serverless approach, I'd like to better understand how much time (I mean the lifetime of each instance/pod/whatever) are we talking about here: seconds? minutes? I'm asking because in a scenario where the hypothetical serverless endpoints are called frequently I fail to see the benefits of not having an instance that runs for some time, where a local cache can give you a lot of advantages even if we are talking about a relatively small amount of time (eg: think microcaching) including full cache stampede prevention etc. And if instead these endpoints are not called that frequently, I think the 1st pass on the memory cache would not be that impactful on the overall run time (I think we are talking about microseconds). It would be like micro optimizing a But again, I'm not that experienced with a serverless approach, so if you can help me understand more I would appreciate that 🙏 🙋♂️ Points made by @arnoldsi-vii
To have the fallback on memory we should 1) not exclude memory and 2) also save on memory, otherwise there wouldn't be anything there to use as a fallback. And when you finally say "Basically switch places" that to me seems like a confirmation that you are not talking about option 1 (no memory cache) but instead about option 2 (distributed-first-memory-second), did I understood it correctly?
Here instead you seem to suggest avoiding memory to consume less memory.
If we are talking about millions of requests I'm not sure a serverless approach is the best use of resources, but again I'm not that experienced with the serverless world so if you can explain a bit more that would be really helpful 🙏 Also, in such a scenario the memory cache has a lot of advantages:
Ok so to me what it's clear that you would like is distributed first, memory second (so, option 2).
Not really, if I got the example right: if you don't actively enable background processing of distributed cache operations it will not run in the background. Also if you use the backplane the changes will be automatically propagated as soon as possible, so that the other nodes will be automatically synchronized.
Watch out about the difference between background processing of the factory (which will happen only if you also enable timeouts, and the timeouts actually occur) and background processing of the distributed cache (which will happen only if you set In any other case the code will wait for everything to finish.
This was true, but is not anymore: if you really want you can enable the new While we are here though I'd like to point out that manually managing distributed cache errors may be a little too much to handle, so think about it. 🏁 ConclusionsIf you withstood this giant wall of thext, thanks 😅, I really appreciate your involvement and your contributions! |
Beta Was this translation helpful? Give feedback.
-
Directed Cache Store (L2 Cache Key Only or L1 Cache Key Only)I too would like the ability to have the ability to read/write explicitly to a specific cache, especially writing a key to only L2 (distributed) cache. We would like leverage some of the FusionCache's serialization, immutability, and other features while at the same time have the option for a little more control in shaping the caching storage of lifetime of certain keys. Use-case: Consistency ModelWe operate on large web farm with stateless applications. Thus if you update your profile or we authenticate you, we update L2 (distributed) cache only so that the next call hosted by a different server can read those changes. An L1(memory) cache layer on Host2 would not return a newly set value by Host1 since the new value is on distributed cache. The eventual consistency is sometimes unacceptable since we need real time consistency across all instances running across all hosts. Use case: Memory groomingUnder large volumes we want to keep memory cache memory pressure to a minimum while using an L2(distributed) cache to reduce loads on our data stores. In this case, we would like to be able have L1(memory) cache to have a different lifetime than L2(distributed) lifetime. These lifetimes should be able to be specified at the key level as part of the key options; reverting back to cache level defaults if not explicitly specified. Use case: PerformanceIn some cases we want to have keys only in memory and not on distributed cache. We would like to leverage FusionCache's serialization, tags, immutability, and other related capabilities while interacting with L1 (MemoryCache). Re: Fallback and other capabilitiesWe recognize that by directing a key to have an explicit store that it might impact other capabilities. In those cases, the engineer willingly makes the trade off. For instance if a key is on an L2(distributed) only cache, and an unrecoverable transient error occurs the library would return null/not-found state and we would simply re-read the value from the database; fall back algorithm would not be in play. Suggestion/RequestPer-Key OptionsThis is something we do in our home-grown caching layer, and it the only thing that is keeping us from considering FusionCache
Normally we use set of cache level defaults but there are use-cases where we need to tweak settings so we get a logical result such as L1-Lifetime is 5 minutes and L2-Lifetime is 30 minutes. (reducing per-host memory pressure on high volume keys) On each of our operations, we also have the ability to define which level we are targeting. (by example only)
class ExampleOptions
{
TimeSpan? L1Lifetime;
TimeSpan? L2Lifetime;
CacheProvider CacheProvider = Level1ThenLevel2;
public enum CacheProvider {
Level1ThenLevel2 = 0,
Level1Only = 1,
Level2Only = 2
Level2ThenLevel1
}
}
_fusionCache.Set("key","value",new(CacheProvider=L2Only,L2Lifetime="00:01:00"));
_fusionCache.Get("key",CacheProvider.L2Only) Suggestion - Per-Cache OptionsCreate a way to disable or not provide either L1 (MemoryCache implementation) or L2 (DistributedCache) implementation to a name FusionCache instance. If an implementation does this, they would understand that certain features (e.g. fallback) might be limited or crippled since they are not applicable. Alternate Strategy for Per-Cache SelectionAs an alternative to an integrated directed cache key option, we might create three named FusionCache instances with no-op implementations:
This alternate approach has some disadvantages and does not address the per-cache, per-key lifetime capability we are also looking for. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I like all of the functionality currently provided within FusionCache, but I would like the ability to turn off the memorycache option.
When using Azure Functions I would prefer to just go straight to Redis and not have the overhead of memorycache due to their stateless nature. I still want to have the fallback value capability in the event Redis is unavailable, but I just don't need the extra step of dealing with memorycache.
This would also help with longer-lived data which could change very infrequently but is accessed often. If I have a long TTL on a value I could have an instance where a load-balanced environment could be out of sync. Let's say I have a TTL of 90 minutes on data but due to a production problem I need to update the current value in Redis. I have no way of evicting the current memorycache values even though Redis has a more current (and correct) value.
This does touch a bit on your backplane idea, but in that case, I would still like to have a preferred cache type for a value. I think this could go in the FusionCacheEntryOptions as a PreferredCache property. This value could be an enum of Local or Distributed. This way I could determine which cache to prefer for a value.
So, this could be seen as 1 of 2 proposals to the FusionCacheEntryOptions:
Looking at the GetOrSetEntryInteral I am not sure if one will be easier than the other. If I had to pick only one option I would say option 1 would do what I really want at the moment. Since I know I would be losing performance by going to Redis first then memorycache would have a smaller performance benefit since I can still use the fallback option.
What are your thoughts?
Beta Was this translation helpful? Give feedback.
All reactions