New Infinite Machine and site design
Today I’m launching two things simultaneously: a new site design of quadpoint.org and a rewrite of Infinite Machine, the software behind quadpoint.org.
Old:

New:

Back in February, I implemented something I called ‘Infinite Caching’ in infmx. It was basically a feature that allowed for virtually infinite cache expire times. Thus, all of the pages on my site would stay in memory, completely rendered, and requests theoretically never hit the disk because the cache was always warm. Whenever a content update was made, I ran a little utility to update the cache asynchronously. I had a git hook set up to run the utility whenever I pushed into the production content repository, so that changes would show up soon right after the push. It was pretty slick, or so I thought.
A couple of months ago I got the idea of an even better caching scheme: the persistent cache. The idea was that static HTML pages should be generated and served by the webserver directly instead of inserting the pages into a memory cache and served by Django. I hacked a persistent cache implementation into my cache-updating utility in July.
Not even a week later I had an epiphany: why is my setup so complicated? Why am I running Django when all of my pages are pre-rendered and in a cache? My dynamic web application was actually just generating the same static content over and over. So a week after implementing the pcache, I started ripping out all of the dynamic bits and rewriting Infinite Machine to implement Jekyll’s interface. Jekyll has the same idea: produce static pages from formatted content. (Aside: I considered switching to Jekyll, but it lacks some of the features that I use in infmx, like breadcrumbs and intrawiki linking.) Now, infmx produces static content just like it did before, except it writes it all to an output directory on the filesystem that can be served up by a webserver. The only dependency on Django now is for the template engine, which is only required during document compilation, and not required on the server.
There are a few major (and obvious) benefits to this. Firstly, it’s static content served directly by the webserver. Even though I was previously serving pages straight from memcached, the fastcgi + django + python + memcached overhead was significant. The same content served from a static file is a full order of magnitude faster: ~800 requests/second for django+memcached versus 8000 requests/second with static. For a 6KB page, that’s over 50MB/s. In other words, I’ll saturate my network link before the webserver (nginx) becomes a bottleneck.
Second, no more Django on my server. That means one less thing to fail and one less thing to make sure is running when the box reboots. My deployment process is now much easier, too. To update, I basically do:
% infmx && ./deploy.sh prod
where deploy.sh is a simple wrapper around rsync to mirror my local copy to my server. Simple.
The takeaway is this: think hard about what you’re doing with your web application. In the early days of the web, everything was static HTML. Then, scripting languages like PHP came along and everything was dynamic. Now that browsers and JavaScript no longer suck, we’re converging to a reasonable hybrid of the two. Try to avoid doing anything ‘smart’ on the fly. Preprocess as much as you can and let your webserver do the work. For fancy dynamic things, JavaScript and a lightweight server-side backend work well.
