Having things in our pockets while we're out are usual, and so is having cached data while we're running our apps 🚶♀️🚶♂️💽💻
While resisting the urge to shout "Cache me outside.. how boww daah" at the screen, allow me to explain to you what caching is to me. I will also mention the different types that you can come across and their pros and cons. This is purely from my perspective, it also carries a couple of tips on how to start caching in .NET.
Caching is the action to store data the first time around you get it, and when it is required again, instead of going to the source (where you got it from), you can go to a much closer place (where you stored it) and retrieve it there instead. This, therefore, saves you time and money.
..Or as Microsoft puts it: “Caching enables you to store data in memory for rapid access. When the data is accessed again, applications can get the data from the cache instead of retrieving it from the original source.” - Caching in .NET framework applications
In my own head, I always see it as a thing you have in your pocket until someone asks for it again, meanwhile you can walk and go about your daily life while this "thing" lives in your pocket until it's needed again.
- Improves performances and scalability (don’t need to hammer the source that much)
- Can make data available when the source is unavailable
- “Caching works best with data that changes infrequently and is expensive to generate” - Cache in-memory in asp.net core
To be frank, not everything is roses and rainbows with what is introduced here. It is always advised that we shouldn't build and test our app to "depend on cached data" ; and rightly so, there could creep up discrepancies between the cached store and the origin very easily, especially if the data we're working with has a tendency to change frequently.
Also when it comes to in-memory cache, we should expect that the more data we store in memory the lower our performance levels become. Metaphorically speaking, we will find it harder to walk around with our pockets as packed as our wardrobes, something will eventual fall out. This is the same with our RAM storage, something has to give. If we use this caching strategy as a half way house for our DB, then we're in a world of trouble.
- In-memory (or in-process) caching (Cache stored in the memory of the web server, very simple to implement)
- Distributed caching (Cache shared across multiple servers)
The main differences between them can be seen in this link here
The decision to choose which really comes down to the situation, where we consider the size and frequency of the data that's being called upon. Can we afford to get from the a source that is a copy of the original, if so then how do we navigate around the consistency issues between these two sources?
For small applications, in general, it would probably be easier and simpler to use the in-memory caching strategy. This is considering the very likely outcome that there would be a minimal and predictable amount of request made given a particular unit of time.
- Install the “Microsoft.Extensions.Caching.Memory” nuget package
- Initialize the MemoryCache object with an options Accessor argument (I.e., MemoryCacheOptions)
- It would usually follow this pattern of fetching or setting:
if (!memoryCache.TryGetValue("cachedThingIdOrName", out List<int> data))
data = memoryCache.Set("cachedThingIdOrName", await GetLargeDatabaseList(), new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromSeconds(10));
It can also be injected using this:
- In startup, add this:
- Now in any constructor, you can just inject IMemoryCache and it can be used
- We can use a docker container to pull down/host the latest image for Redis
- After Redis is up and running, we need to download the
- We would also need to download the
- Go to the
ConfigureServicesmethod and add the extension method
AddStackExchangeRedisCachewith the following expression settings:
options.Configuration = Configuration.GetConnectionString("Some connectionstring in you config file")
- This gets the connection string /configuration used to connect to the Redis that is set up.
options.InstanceName = "RedisCachingApp_(app name)";
- This is just a convvention that can be used to stop any potential mix-up when it comes to inserting a value with the same key across multiple apps. Remember that Redis can be shared across different instances and apps in general, so it can be more likely that key names would be mixed, this isolates whatever is set in this app TO this app.
- Inject IDistributedCache into the constructor as normal and use
An important thing to note is to always use a form of expiration otherwise the data would stay in the cache forever.
SlidingExpiration are fine to use.
Thanks for hanging around, see you on the next one 🙌