I recently had to explain some basic caching principles to one of my clients so thought i would publish them.
Using a database and web application in these examples as the source, but it could be anything, but these are the most common in my experience to require the technology.
Basic Caching
The basic form of caching is simply to cache something on first request, then subsequent requests access the cached copy until it expires
Expiry is usual a fixed time, but can be sliding based on access time depending on the caching technology you are using.
Main con of this is that data updates aren’t immediate because they usually rely on expiry time.
Also your first access request is slow, if your objects are really large you might be running into webpage time outs on first load, or on first access after expiration.
Caching with Version Check
If you are caching large objects then you maybe be able to implement a versioning system, where by the objects when stored have a time-stamp or a version number. So when the user accesses the object in cache a “light weight” call can be made to compare this to tell if the cached copy is out of date, and update only in this event.
This has similar cons to above where the call that is made when the object is out of date is long.
Cache Pre-warming
If you don’t have any code in you ASPNET Global Application Start event, you should go and put some in there right now. Pre-warming anything these days is a must do, especially if you are trying to run on small VM sizes for easy scaling
Cache pre-warming is just one example, where on application start as apposed to first access you cache your data.
This can be combined with the above two methods to reduce the impact of the “long first load” issue, but when cache expires you still may get long loads to their users as their requests get used to repopulate your cache.
Application update of cache
If you have a single tier Application that runs on a single server this maybe easy, but when dealing with n-Tier applications on clusters it gets hard.
The principle is that your application will know when a data update happens, so it updates both sources, the cache and the database.
So yea, that’s easy right? when one user updates the database, we just update the cache too?
If you are using a external single source cache like redis (or something else if you are living in the nineties) then you may be able to pull this off, however if you are running on a cluster and using application cache, OR have a distribute application (e.g. a separate application to edit data, then multiple other apps read) then it can get really hard.
A few tips from Experience if you need to implement this
Use Pub/Sub
When you have multiple applications updating a reading the same data source, have them “subscribe” for updates, Azure Service Bus comes to mind as an easy way in, Redis has a good system, Signal-R is another one I’ve used in the past too, depends on your app really.
Don’t send the whole object
When using pub sub sending the whole object is going to get messy if you have a large amount of sequential updates, and may exceed your message queue data size if you have big objects, send an invalidation message. e.g. ObjectID=XYZ, so the application will know if it has Object ID XYZ in its cache it needs to go grab it again. You may even include a time-stamp so the end app can compare its time stamp and ignore subsequent messages.
Do the Cache update out-of-band with Page requests
One of the big mistakes i see made is updating cached objects in band with page requests, so you end up making some random poor sod responsible for your cache updates.
If you are using the pub sub system above you should have a thread running that’s hanging off a message queue that’ll pick up the object and update it.
Just a note on a common mistake I’ve seen made. If you are using static variables in C# to hold your data, then use a delegate to return the data to, then assign the delegate to the static variable. If you don’t it may lock the variable for the time it takes to return the data.
BAD EXAMPLE
private static object myCachedObject; private void UpdateMyCache() { myCachedObject = GoGetMyData(); } private object GoGetMyData()
GOOD EXAMPLE
private static object myCachedObject; private void UpdateMyCache() { var del=GoGetMyData() myCachedObject = del; } private object GoGetMyData() {