<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>http://www.nomitor.com/</id>
  <title>nomitor blog</title>
  <updated>2010-11-10T09:00:00Z</updated>
  <link rel="alternate" href="http://www.nomitor.com/" />
  
  <author>
    <name>nomitor</name>
    <uri>http://www.nomitor.com/</uri>
  </author>
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/nomitor" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="nomitor" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
    <id>tag:www.nomitor.com,2010-11-10:/blog/2010/11/10/gzip-support-for-amazon-web-services-cloudfront/</id>
    <title type="html">gzip support for Amazon Web Services CloudFront</title>
    <published>2010-11-10T09:00:00Z</published>
    <updated>2010-11-10T09:00:00Z</updated>
    <link rel="alternate" href="http://www.nomitor.com/blog/2010/11/10/gzip-support-for-amazon-web-services-cloudfront/" />
    <content type="html">&lt;p&gt;A common &lt;a href="http://developer.yahoo.com/performance/rules.html#gzip"&gt;best practice&lt;/a&gt; when building high performance web sites is to serve &lt;a href="http://en.wikipedia.org/wiki/Gzip"&gt;gzip&lt;/a&gt; compressed versions of content such as JavaScript or &lt;span class="caps"&gt;CSS&lt;/span&gt;. Combining gzip compression with a content delivery network (&lt;span class="caps"&gt;CDN&lt;/span&gt;) can dramatically increase the performance of your web site by serving smaller files to users from a location that is closer to them, thus reducing response time and making your sites load faster.&lt;/p&gt;
&lt;p&gt;Until now you have been able to support the &lt;span class="caps"&gt;CDN&lt;/span&gt; part of this best practice by using Amazon Web Services &lt;a href="http://aws.amazon.com/cloudfront/"&gt;CloudFront&lt;/a&gt;. However, unlike some other CDNs CloudFront did not support serving gzipped content in a standard manner by using the &lt;span class="caps"&gt;HTTP&lt;/span&gt; Accept-Encoding header that is sent by browsers to indicate their support for gzip compression. There were some &lt;a href="http://developer.amazonwebservices.com/connect/thread.jspa?messageID=107778"&gt;workarounds&lt;/a&gt; for this issue but they were far from optimal.&lt;/p&gt;
&lt;p&gt;With the recent announcement of &lt;a href="http://aws.typepad.com/aws/2010/11/amazon-cloudfront-support-for-custom-origins.html"&gt;Custom Origin&lt;/a&gt; support in CloudFront it is now possible to use the standard &lt;span class="caps"&gt;HTTP&lt;/span&gt; Accept-Encoding method for serving gzipped content if you are using a Custom Origin. Although not specifically mentioned in the release announcement you can verify this in the &lt;a href="http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/CustomOriginBestPractices.html"&gt;Custom Origins Best Practices&lt;/a&gt; section of the &lt;a href="http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/"&gt;CloudFront Developer Guide&lt;/a&gt;. CloudFront will now forward the Accept-Encoding &lt;span class="caps"&gt;HTTP&lt;/span&gt; header to your origin server where you can ensure the appropriate content is served based on the supported encodings. CloudFront will then cache multiple versions of this content, the uncompressed version and the gzipped version and serve these to clients depending on the value of their Accept-Encoding header for all future requests.&lt;/p&gt;
&lt;p&gt;To support this feature on your origin server it should be configured to compress content of the appropriate type when the Accept-Encoding header is present.&lt;/p&gt;
&lt;p&gt;For Apache 2.x this means ensuring &lt;code&gt;mod_deflate&lt;/code&gt; is loaded and the appropriate content types are sent to the &lt;code&gt;DEFLATE&lt;/code&gt; filter with the &lt;code&gt;AddOutputFilterByType&lt;/code&gt; directive.&lt;/p&gt;
&lt;p&gt;For nginx you need a configuration similar to the following:&lt;/p&gt;
&lt;pre&gt;gzip on;
gzip_http_version 1.0;
gzip_proxied any;
gzip_types text/css application/x-javascript;
gzip_vary on;&lt;/pre&gt;
&lt;p&gt;It&amp;#8217;s important to note that CloudFront will only make &lt;span class="caps"&gt;HTTP&lt;/span&gt;/1.0 requests to an origin server, thus the requirement for &lt;code&gt;gzip_http_version 1.0&lt;/code&gt; in the nginx configuration. This is also noted in the &lt;a href="http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/CustomOriginBestPractices.html"&gt;Custom Origins Best Practices&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>tag:www.nomitor.com,2009-07-29:/blog/2009/07/28/client-side-search-facebook-remember-the-milk/</id>
    <title type="html">Client-side Search: Facebook &amp; Remember The Milk</title>
    <published>2009-07-28T18:00:00Z</published>
    <updated>2009-07-28T18:00:00Z</updated>
    <link rel="alternate" href="http://www.nomitor.com/blog/2009/07/28/client-side-search-facebook-remember-the-milk/" />
    <content type="html">&lt;p&gt;A previous post discussed &lt;a href="/blog/2009/07/06/flickr-smugmug-facebook-photos/"&gt;image pre-loading and its impact on user perceived performance&lt;/a&gt;.  In this post we&amp;#8217;ll highlight a technique used by Facebook and Remember The Milk which implements search functionality entirely on the client (browser) side.&lt;/p&gt;
&lt;p&gt;Traditionally we&amp;#8217;re used to search as a server side function.  You visit Google, enter your query and Google&amp;#8217;s hundreds of thousands of machines collaborate to produce the most relevant results from the web.  Searching billions of documents within &lt;a href="http://glinden.blogspot.com/2009/02/jeff-dean-keynote-at-wsdm-2009.html"&gt;200 milliseconds&lt;/a&gt; is pretty impressive by any standard but despite Google&amp;#8217;s exemplary efforts there&amp;#8217;s a limit to how fast a server-side search can be given that a network connection is still involved.&lt;/p&gt;
&lt;p&gt;But what if the dataset being searched is relatively small?  Is there a need to run all searches on the server or could it be done in the user&amp;#8217;s browser?&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.facebook.com/"&gt;&lt;strong&gt;Facebook&lt;/strong&gt;&lt;/a&gt; implements client side search in at least two areas: the global site search in the top right hand corner, and the Inbox search.  Both of these search fields use a pre-loading technique which loads the user&amp;#8217;s entire friend list in a single &lt;span class="caps"&gt;HTTP&lt;/span&gt; request when the user clicks into the search field.  This saves Facebook from sending out unnecessary bytes if a user never performs any searches, yet still minimises the user&amp;#8217;s wait time as the required data would most likely have finished loading behind the scenes whilst they are typing their query.&lt;/p&gt;
&lt;p&gt;The data sizes involved are surprisingly small too.  With 226 friends the raw Javascript encoded version of my friend list is about 39kB but with gzip compression it arrives over the network as 10kB.  Additionally Facebook sets an Expires: header advising that my friend list can be stored for 1 week so unless my browser fills its cache I should be fetching this 10kB no more than once a week.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.rememberthemilk.com/"&gt;&lt;strong&gt;Remember The Milk&lt;/strong&gt;&lt;/a&gt; goes a step further by including the user&amp;#8217;s entire task list and associated metadata within the initial &lt;span class="caps"&gt;HTML&lt;/span&gt; load of the user&amp;#8217;s home page.&lt;/p&gt;
&lt;p&gt;The search box is then implemented as:&lt;/p&gt;
&lt;p style="text-align:center;"&gt;&lt;code&gt;&amp;lt;form onsubmit="control.updateListFilter(); return false;" action=""&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The result is that searches are near instantaneous as they execute entirely within the browser.  This is a huge boost to usability, especially for a time/task-management application.&lt;/p&gt;
&lt;p&gt;The most obvious question then is how large a user&amp;#8217;s task list might get, and the resultant impact on the initial load times of the user&amp;#8217;s home page.  If you consider a user with 1,000 tasks, and each task is roughly 500 bytes of raw &lt;span class="caps"&gt;JSON&lt;/span&gt;, then the initial page load is at least 500kB heavier but with gzip compression this would reduce to around 100kB of added weight.&lt;/p&gt;
&lt;p&gt;However with 10,000 tasks the compressed data size approaches the megabyte mark.  Whether this technique still improves the user experience really depends on the user&amp;#8217;s usage habits, though I suspect that if a user has 10,000 tasks in &lt;span class="caps"&gt;RTM&lt;/span&gt; they would probably be quite happy about trading off a longer initial load time for the ability to very quickly filter their monster task list. :-)&lt;/p&gt;
&lt;p&gt;Finally, with the entire task list loaded in browser there is the issue of updates &amp;#8211; what happens when a user adds, modifies, or deletes a task?&lt;/p&gt;
&lt;p&gt;A &lt;span class="caps"&gt;POST&lt;/span&gt; is performed to ensure the server state reflects the user&amp;#8217;s changes, and Javascript is returned which updates the in-browser state.  The following is a Firebug Net view of an &amp;#8220;Add Task&amp;#8221; operation:&lt;/p&gt;
&lt;p style="text-align:center;"&gt;&lt;img src='http://aa.c.nomcdn.net/assets/img/blog/firebug-net-rtm-v2.png' width='490' height='255' alt='Remember the Milk Firebug Net Panel'&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>tag:www.nomitor.com,2009-07-07:/blog/2009/07/06/flickr-smugmug-facebook-photos/</id>
    <title type="html">Flickr, SmugMug, and Facebook Photos</title>
    <published>2009-07-06T15:00:00Z</published>
    <updated>2009-07-06T15:00:00Z</updated>
    <link rel="alternate" href="http://www.nomitor.com/blog/2009/07/06/flickr-smugmug-facebook-photos/" />
    <content type="html">&lt;p&gt;I&amp;#8217;ve been a regular Flickr user since the beginning of 2006 and remain a loyal Flickr Pro member despite increasing usage of Facebook&amp;#8217;s photos amongst my friends.  Putting aside feature &amp;amp; design differences one noticeable difference between the two is in sheer speed of browsing.  I decided to compare Flickr, SmugMug and Facebook Photos as they illustrate 3 different approaches to photo browsing, with quite dramatic speed differences.&lt;/p&gt;
&lt;p&gt;Flickr takes a whole page approach to photos in that browsing from one photo in a Photostream, Set or Pool loads a whole new &lt;span class="caps"&gt;HTML&lt;/span&gt; page and its associated contents.&lt;/p&gt;
&lt;p&gt;SmugMug takes an &lt;span class="caps"&gt;AJAX&lt;/span&gt; approach.  Clicking a photo in the current album does not load a new &lt;span class="caps"&gt;HTML&lt;/span&gt; page but triggers two important &lt;span class="caps"&gt;HTTP&lt;/span&gt; requests:&lt;/p&gt;
&lt;p style="text-align:center;"&gt;&lt;img src='http://aa.c.nomcdn.net/assets/img/blog/firebug-net-smugmug-v2.png' width='580' height='288' alt='SmugMug Firebug Net Panel'&gt;&lt;/p&gt;
&lt;p&gt;The first is obviously the image requested by the user, the second is any associated comments.  Flickr in its whole page load approach can avoid the separate comment load request since it can directly embed comments into the page &lt;span class="caps"&gt;HTML&lt;/span&gt;, however that is still slower than the SmugMug &lt;span class="caps"&gt;AJAX&lt;/span&gt; approach because the page &lt;span class="caps"&gt;HTML&lt;/span&gt; has to be loaded before the browser knows what image to fetch.  SmugMug&amp;#8217;s &lt;span class="caps"&gt;AJAX&lt;/span&gt; approach enables it to avoid the &lt;span class="caps"&gt;HTML&lt;/span&gt; page load, and also to fetch the image and comments in parallel &lt;span class="caps"&gt;HTTP&lt;/span&gt; requests resulting in a snappier user experience.&lt;/p&gt;
&lt;p&gt;Facebook also takes an &lt;span class="caps"&gt;AJAX&lt;/span&gt; approach but goes one step further by preloading images.  Upon viewing the first image in an album a simple &lt;code&gt;((new Image()).src=...&lt;/code&gt; is used to preload the next image.  Simultaneously, an asynchronous request is made for the album&amp;#8217;s metadata which is returned as a JavaScript blob.  The metadata describes all images on the current page (of 20) which allows Facebook&amp;#8217;s javascript TaskQueue to begin preloading further ahead (at time of writing it preloads up to 4 images ahead of that currently being viewed).&lt;/p&gt;
&lt;p style="text-align:center;"&gt;&lt;img src='http://aa.c.nomcdn.net/assets/img/blog/firebug-net-facebook-photos-v2.png' width='580' height='389' alt='Facebook Photos Firebug Net Panel'&gt;&lt;/p&gt;
&lt;p&gt;The metadata also contains all comments &amp;amp; tags for every photo on the current page of the album.  The current page size is 20 so Facebook has potentially saved 19 &lt;span class="caps"&gt;HTTP&lt;/span&gt; requests by retrieving all comments &amp;amp; tags in one request if the user browses through every photo.  The tradeoff is freshness &amp;#8211; if a new comment or tag is added during the current browsing session they will not show up, though this would not seem to be a major issue given that in my experience the comment rate is very low on most photos.&lt;/p&gt;
&lt;p&gt;The end result is that when advancing from one image to the next the user waits for a single &lt;span class="caps"&gt;HTTP&lt;/span&gt; request for the image in the worst case, and in most cases does not have to wait at all since the images are typically preloaded.&lt;/p&gt;
&lt;p&gt;In my testing Flickr&amp;#8217;s &lt;span class="caps"&gt;HTML&lt;/span&gt; page alone takes roughly 1.5 seconds to load (450ms waiting for the server to respond, and upwards of 1000ms to load 17kB of &lt;span class="caps"&gt;HTML&lt;/span&gt;).  The exact times aren&amp;#8217;t as important here as the fact that, &lt;a href="http://en.wikipedia.org/wiki/Ceteris_paribus"&gt;ceteris paribus&lt;/a&gt;, advancing from one image to the next on Flickr is at the very least 1.5 seconds slower than SmugMug or Facebook.&lt;/p&gt;
&lt;p&gt;The pre-loading approach makes sense in some instances.  If the user is looking at an image within an album of photos from a birthday party they recently attended they&amp;#8217;re quite likely to browse through at least a few other images in the same album.  The tradeoff is that inevitably there will be some waste in preloaded bytes.  If you&amp;#8217;ve clicked into an album because one of your friends was photographed at a conference you probably won&amp;#8217;t be clicking through the other 500 photos of random strangers at the conference.&lt;/p&gt;
&lt;p&gt;We hope to continue highlighting real world examples of front-end techniques for improving web application performance.  If you know of other interesting examples please let us know by leaving a comment below.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>tag:www.nomitor.com,2009-06-17:/blog/2009/06/16/welcome-to-nomitor/</id>
    <title type="html">Welcome to nomitor</title>
    <published>2009-06-16T15:00:00Z</published>
    <updated>2009-06-16T15:00:00Z</updated>
    <link rel="alternate" href="http://www.nomitor.com/blog/2009/06/16/welcome-to-nomitor/" />
    <content type="html">&lt;p&gt;Hi there, and welcome to the &lt;a href="http://www.nomitor.com/"&gt;nomitor&lt;/a&gt; blog. We are a small, down to earth company based in &lt;a href="http://en.wikipedia.org/wiki/Sydney"&gt;Sydney, Australia&lt;/a&gt; currently in the development phase of a service that will enable you to monitor and improve the speed of your web sites as experienced by your users.&lt;/p&gt;
&lt;p&gt;Our goals for this blog are wide reaching but focused. We will be covering topics related to web performance and availability and how you can apply this information to make your sites measurably faster and more reliable. We will also keep you updated with the latest &lt;a href="http://www.nomitor.com/"&gt;nomitor&lt;/a&gt; developments.&lt;/p&gt;
&lt;p&gt;We aren&amp;#8217;t ready to launch yet, but if you are interested in improving the speed of your web sites and would like to help us test our service in the near future or would just like to know when we launch you can sign up for notifications on the &lt;a href="http://www.nomitor.com/"&gt;nomitor home page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to stay up to date with this blog you can &lt;a href="http://www.nomitor.com/blog/atom.xml"&gt;subscribe via &lt;span class="caps"&gt;RSS&lt;/span&gt;&lt;/a&gt; or follow our updates on &lt;a href="http://twitter.com/nomitor"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
</feed>

