Curator's Note: The content of this article was originally written by Adam Abrevaya over at the NuoDB blog back in March.
Hi, I’m Adam Abrevaya, the VP of Engineering at NuoDB. You’ll be seeing much more from me in the way of me introducing new innovative features in upcoming releases, how we build NuoDB – i.e. insight into our engineering practices and how we test NuoDB (that gets really interesting at massive scale – 100s or 1000s of machines). Today however I’ll add my 2 cents to the caching discussion that Seth (see: Intro to the cache part 1) and Trek (see: Intro to the cache part 2) started.
Modern application architectures commonly use a caching layer in the middle-tier or app-server layer. In order for an application to maintain good performance, the commonly accessed data is maintained in process in the app-server or using an external caching engine such as MEMCACHED. The typical pattern is:
CREATE / READ
- check for the value in a cache
- if found,
use the value
get the value from the database
put the value in the cache
- check for the value in a cache
- if found
create the cache entry
- put the value in the cache
- update the database
- delete the row from the database
- if found
delete the cache entry
Some things the application developer needs to be aware of and to carefully think through are:
- cache invalidation: when does the cache get invalidated – is it by time or when memory is running low?
- update conflicts: how do updates from different processes to same cache entry get managed?
- cache failure: what happens if the cache fails, what does the app do to recover?
- transactions: can the cache and database get our of synch if the database or cache fail or if there is a timing window?
- cache access: how is the cache accessed and manipulated? Does it require significant programming, for instance a key value store type of interface requires significant work to get right when integrating with complex queries and then mapping those results onto application objects.
- programmer effort: really this is a sum of the above, how much work is it to get all of the details right?
Answering the above using the Memcached feature set (btw, there are a bunch of implementations so your mileage may vary), we get:
- cache invalidation: depending on the implementation a timer can be set
- update conflicts: no conflict detection
- cache failure: depends on the type of failure
- transactions: not supported
- cache access: programming is required, follows the CRUD code above
- programmer effort: high (my opinion, but even the basic code without factoring bigger issues of transactions is non-trivial)
As you can see there are lots of details to work out and sometimes the issues are discovered only after the application is deployed (sometimes weeks or months after the fact). The most common reason for caching is decreasing load on database resources, so if you don’t need to worry about that you can remove lots of complexity and chances for error in your application architecture.
One of the really nice aspects of NuoDB is that the caching layer is built into the database. Because of that you don’t need to add a separate caching layer to avoid load on the database, a NuoDB application can simply scale out the database tier with more Transaction Engines. NuoDB Transaction Engines guarantee the Atomicity, Consistency and Isolation properties of your data while the Storage Managers maintain the Durability – the combination is NuoDB’s ACID guarantee. You can have as many TEs that you need, NuoDB ensures that all of the TEs and your application servers see a transactionally consistent view of the database. As Trek mentioned, a TE automatically maintains the most recently used ATOMs so that access to your data remains fast.
No comparison is complete without answering the evaluation questions using NuoDB, so here we go:
- cache invalidation: least recently used items are evicted when memory is low
- update conflicts: one updater wins
- cache failure: applications automatically failover to another transaction engine
- transactions: fully transactional
- cache access: trivial, access is managed automatically
- programmer effort: easy. nothing additional beyond the database access that is already part of the application is necessary
So that’s it. NuoDB makes it easy to implement caching in your application because you just get it for free by using the database, but more importantly it implements caching that is transactionally consistent. Try it!