From The Archives
Pseudo Namespaces With PHP and Memcached Revisited
created March 9, 2010 at 2:27 am
A while back I wrote about a way to keep data valid across multiple pages by invalidating cache keys. I have since thought of a better way to handle this.
The basic idea is that anytime you have child objects related to a parent object you can use a property of the parent object to invalidate the children. To make this more clear let's revisit the original problem: You are building a blog with a lot of users where each user posts a bunch of articles. The articles are paginated and cached per page. If the user adds a new article, all the items on the page will shift and we need a way to invalidate all the pages in cache.
The approach mentioned in my previous article involved having a namespace key that would store a random integer which would then be incremented when there is an update. This has a few problems:
- It is never 100% safe to rely on random numbers.
- If there is a cache failure on one server and the namespace key falls out of cache then there is a chance that the random number generated will lead to a key containing data that was in cache a while ago. Also on that same note incrementing the version could still contain stale data in cache.
- It creates unnecessary cache lookups.
- The namespace lookups have to happen before you can perform the initial lookup. Cache is fast, but like anything else it should only be used when necessary.
- It can cause cache contention issues.
- If many people are all trying to access the same key at the same time then the requests start to bubble up and the last one has to wait for the others to finish. This is more prevalent in this situation because if there are 10 pages of articles, each page would have its own unique cache key, but all 10 pages would share the same namespace key.
Enough with the problems, let's take a look at the solution:
This is overly simplified, but you can see how much cleaner and simpler this approach is. The lastArticleUpdate property contains a timestamp. This timestamp would get updated everytime the user adds/removes/updates an article. Since the user object is already required in order to get a page of articles in this example, you already have this property accessible.