Reply to comment


Speeding up mobile web applications

Posted on 30 April 2008 - 0:54

It's been nearly one month since I started full speed at Goojet, and I already learned a lot on the mobile web and J2ME.

One of the key issues in the mobile web is latency: connections are long to establish, and data transfer rates are low. Not everybody has a 3G phone nor an unlimited data plan.

Connection establishment latency can be mitigated in two ways:
  • Use persistent HTTP/1.1 connections. By reusing the same TCP socket for several HTTP requests, you save the non-negligible connection setup overhead. To achieve this, every request and response must carry a Content-Length header.
  • Open several connections in parallel when you have several items to load (e.g. images in a page). This might seem contradictory to the above, but a single connection doesn't use all the available bandwidth. There are lots of idle periods during connection establishement and data transfer, waiting for handshake packets on the slow link. So by opening several connections and handling them in parallel, more of the available bandwidth is actually used leading to shorter overall load time.
Having responsive connections is good to speed-up transfer, but even better is not to have to transfer data at all, both for response time and user phone bill. So HTTP cache headers must be handled with great care, which also means that the J2ME application has to implement an HTTP cache.

Cache headers for static resources like images or CSS files are most often handled by the web server itself, by means of Last-Modified and/or ETag headers. You have to be careful with ETags though in server farms, since some web servers include the file inode in it, which essentially makes its value different on every server for the same replicated resource, thus breaking the intented purpose.

Static resources can also benefit from using the Expires header, or better the HTTP/1.1 Cache-Control header that avoids the date parsing and clock synchronization issues associated to Expires. The use of versioned URLs even allows to set an infinite expiration date.

But cache headers for applications are way more tricky. There is often no concept of "last modified", and computing an etag that reflects the state of all the elements that contribute to the response is not always possible or would lead this concern to creep into all application layers.

So I've taken a different approach in the Goojet backend: when receiving the first byte of the response body, a servlet filter checks if the application has set cache headers. If not, the response is buffered so that we can compute a hash code once the application has finished producing it. We could have used MD5 for the hash, but it's a bit costly to compute and we don't need something cryptographically secure. So we use a 64 bit FNV-1 hash that is very fast to compute and has a low collision rate, even for small changes in the data.

The result is that even for highly dynamic responses, we are able to provide cache headers that allow the mobile application to issue conditional requests and download data only when actually needed.

All these techniques combined really make a difference to have a more responsive application and a lower phone bill!

Reply

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • Web page addresses and e-mail addresses turn into links automatically.

More information about formatting options


CAPTCHA
Please answer this question to show that you're not a stupid spam robot.
6 + 2 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.