You are viewing pphaneuf

Previous Entry | Next Entry

A Few More Notes on HTTP

Smiling
Saturday, I attended BarCampMontreal3, which was quite fun. I figured that I should really practice my presentation skills, so Thursday, when I found out it was this Saturday (not the next one as I has thought!), I had to find something to talk about.

I figured there would be a lot of web developers in the audience, and having noticed that a lot of web application platforms tend to disable many HTTP features that helped the web scale to the level it has today, I thought I could share a few tips on how to avoid busting bandwidth caps, deliver a better user experience and overall try to avoid getting featured on uncov.

It was well received, mostly (see the slides), although it felt a bit like a university lecture for some (maybe the blackboard Keynote theme didn't help, and I was also one of the few with a strictly educational presentation that was also technical). Marc-André Cournoyer writes that just one simple trick visibly improved his loading time, so it's not just for those who get millions of visitors! Since at least one person thought that, I guess I should clarify or expand on a few things...

When running a small web site, there are two things we are after: fast loading time, and keeping our bandwidth usage low (if you're small, you probably don't have the revenue to pay for big pipes).

The best thing possible is, of course, for your server not to get a request at all. This is actually quite easy to do, and is accomplished by telling the client some amount of time that it can just assume that the resource it asked will not change. This is done by having a Cache-Control header with a "max-age" directive, like this (the number is in seconds):
Cache-Control: max-age=3600
This used to be done with the "Expires" header in previous versions of HTTP, but as it is error-prone, it is best to avoid it if you are generating these headers yourself (or you can use a well-known library to do it for you).

The main problem with this approach is that we live in a fast-moving world, and we want things to be as up-to-date as possible. If the home page of a news site had the Cache-Control header I just gave, the load would be greatly diminished, but so would the usefulness of the site! But there are some things that do not change all that often, CSS and JavaScript files, for example.

But there is another approach that leverages caching without compromising the freshness, cache validation. Here, the idea is that the web server gives out a small bit of information that is then used by the client to validate its cache. If the client has the resource already, it can perform a "conditional GET", where the server will only return the data if it is deemed invalid. If the data cached by the client is still valid, the server replies with a "not modified" status code (304, if you need to know), and does not return any data. There is still the cost of a round-trip to the server, but this technique can help cut down on bandwidth (as well as database usage, if you do it right) quite significantly.

This "small bit of information" can be either a last modification date, or an "entity tag" (ETag), which is literally a small string of your own choosing (note that both can be used at the same time, if you prefer). The last modification date is the one most people find the easiest to understand, but depending on your application, coming up with a last modification date could be difficult or less desirable. For example, a wiki application might only have a "latest version number" for a given wiki page, and would need a separate database query or an SQL join to get the modification date itself. In this case, the wiki application could use the version number as an entity tag to accomplish the same thing.

This is the most difficult to implement, because it can require changing the implementation of your application. What you need to do is cut the handling of a request in two: the header part, and the content part. In the header part, you need to generate the Last-Modified or the ETag (or both), and then, you compare those with the ones sent by the client. If they match what the client sent, you can simply skip generating the content entirely and return a "304 Not Modified" response status instead. If they do not match, then you keep going the normal way.

I heard that Ruby on Rails now has automatic support for ETag, which it generates by doing an MD5 digest of the rendered content. While this is better than nothing (it will definitely save on bandwidth), it is a bit brittle (if you have something like "generated at <put time here>" in your page, say), and it has already expended all the effort of generating a page, only to throw it away at the end. Ideally, generating the Last-Modified or the ETag would only require a fraction of the effort of generating the whole page. But still, even this naive implementation will save you possibly significant amounts of bandwidth!

Another technique is to make your content smaller, therefore needing less bandwidth to send it. This can be done with various tricks, varying from making your CSS and JavaScript smaller (for example, using Douglas Crockford's JSMin), to enabling on-the-fly compression on your web server.

A very good resource to learn more on this is on Yahoo! Exceptional Performance page, which has a list of rules to follow, and even have an easy to use tool (based on the excellent Firebug to tell you how your page is doing, based on those rules (their rule about ETags is a bit incorrect, though, as it usually only applies if you have a cluster of web servers, and can be fixed in a better way than just turning them off). They in fact made a presentation similar in spirit to mine at the last Web 2.0 Expo, of which they have a video on their site (slides). They even wrote a book on this subject!

Comments

( 13 comments — Leave a comment )
macournoyer.myopenid.com
Nov. 5th, 2007 10:04 pm (UTC)
Nice post Pierre and thx for the link,

but my site does get millions of visitors... per second

pphaneuf
Nov. 5th, 2007 10:11 pm (UTC)
Really? Whew, that's pretty cool, I didn't know you were so popular!
macournoyer.myopenid.com
Nov. 6th, 2007 12:42 am (UTC)
huh, I can't tell if you replied to my sarcasm by another sarcasm, so just to clarify:

That was totally fasle, I get an average of 3000 page loads and 1000 unique visitors per day on refactormycode, but I'm aiming the million per second by the end of the millenium
pphaneuf
Nov. 6th, 2007 01:58 am (UTC)
I figured you probably were being sarcastic, yes. :-)

When you hit a million unique visitors per day, email me, I'll help you out with some distributed storage and web cluster magic. ;-)
evildrgo
Nov. 6th, 2007 02:10 am (UTC)
I had no idea what you were talking about... Why is Barcamp always... Internet Internet Internet???

pphaneuf
Nov. 6th, 2007 02:23 am (UTC)
I actually tried to simplify something that's positively head-spinningly complicated, but is just too critical to everything. I knew a bunch of people wouldn't get it, but I figured I had at least 50% of web developers in the audience who'd be happy to know they can cut the monthly bandwidth bill of their newest web startup in half.

Why all the Internet stuff at BarCamp? Well, for one, the Internet is Kind Of A Big Deal these days, I guess (me, I just like nifty networking code!). The BarCamp description on Wikipedia says the following:
BarCamp is an international network of user generated conferences — open, participatory workshop-events, whose content is provided by participants — often focusing on early-stage web applications, and related open source technologies, social protocols, and open data formats. (emphasis mine)


Personally, while I did enjoy BarCampMontreal3, I personally could have used a more technically advanced event. Sometimes, a talk about yet another Web 2.0 app that half the people in the audience could do in a weekend and which has its idea lifted almost integrally from some other thing, is just not what I like.
evildrgo
Nov. 6th, 2007 02:38 am (UTC)
"Often focussing" is the word.. ok.. well that's two. I think next time I'll take Simon's challenge and talk about something on the chemistry front.

Either way. Your talk was good, and the event as a whole was kinda geeky fun...

pphaneuf
Nov. 6th, 2007 03:48 am (UTC)
Thanks!

True, other stuff is totally allowed. I very much enjoyed Christopher Hing's talk on hesitational happiness, myself. The Galacticast people were pretty interesting too.

Simon's right, of course, and you're supposed to "vote with your feet" if it's boring, and it's on you to pitch in and make it not boring!
cpirate
Nov. 6th, 2007 04:16 am (UTC)
The talk I did at BarCamp Montreal 1 was pretty much non-Internet related, and if I do another one it'll probably be on writing Firefox/Thunderbird extensions. Sure, they're only useful in the context of the Internet, but at least it's not Just Another Stupid Website. Still very, very geeky, but there's not a lot I can do about that.
pphaneuf
Nov. 6th, 2007 12:32 pm (UTC)
Heh, if I had more time, I had thought of doing a "C++ on Rails", just for fun. How geeky would that have been, eh? ;-)
pdage
Nov. 9th, 2007 01:09 pm (UTC)
Crap, that sounds like something that was right up my alley. We do get a ridiculous amount of visitors on our web site. It would have been fun to compare notes with others.
pphaneuf
Nov. 9th, 2007 02:41 pm (UTC)
The slides to my presentation are linked at the top, for what it's worth, and otherwise, you know how to get in touch with me. :-)

Also, I recommend that you look into Ruby, and the "Ruby on Rails" framework. It's a much better language and framework than PHP ever was (and likely, ever will be, due to the way the community works), very easy to learn and won't rot your brain like PHP will. ;-)
(Anonymous)
Nov. 24th, 2007 01:14 am (UTC)
Cheers
Thanks for the shout-out, Pierre. I've been recommending your BCM3 presentation to quite a few folks. Thanks for putting it up, too!

Cheers,
Kartik
( 13 comments — Leave a comment )

Latest Month

March 2009
S M T W T F S
1234567
891011121314
15161718192021
22232425262728
293031    
Powered by LiveJournal.com
Designed by Lilia Ahner