<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mozilla Web Development &#187; Bouncer</title>
	<atom:link href="http://blog.mozilla.com/webdev/category/bouncer/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.mozilla.com/webdev</link>
	<description>Everybody Likes Ninjas</description>
	<lastBuildDate>Wed, 01 Feb 2012 16:41:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>What happens when you click the Firefox download button?</title>
		<link>http://blog.mozilla.com/webdev/2010/05/07/what-happens-when-you-click-the-firefox-download-button/</link>
		<comments>http://blog.mozilla.com/webdev/2010/05/07/what-happens-when-you-click-the-firefox-download-button/#comments</comments>
		<pubDate>Fri, 07 May 2010 14:06:45 +0000</pubDate>
		<dc:creator>Fred Wenzel</dc:creator>
				<category><![CDATA[Blogroll]]></category>
		<category><![CDATA[Bouncer]]></category>
		<category><![CDATA[download]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[mirror]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/webdev/?p=970</guid>
		<description><![CDATA[In this cross-post from Fred's personal blog, he describes what's going on behind the scenes to ensure you can download Firefox as fast and conveniently as possible.]]></description>
			<content:encoded><![CDATA[<p class="crosspost">This is a cross-post of <a href="http://fredericiana.com/2010/05/07/what-happens-when-you-click-the-firefox-download-button/">an article</a> on Fred Wenzel&#8217;s blog <a href="http://fredericiana.com">fredericiana</a>.</p>
<p>Everybody knows Mozilla makes Firefox. But there is a lot more software at work here at Mozilla that you might not be aware of. For example: What happens when you go to <a href="http://getfirefox.com">getfirefox.com</a> and click on the <strong>download button</strong>?</p>
<p><img src="http://blog.mozilla.com/webdev/files/2010/05/directions.jpg" alt="" title="directions" width="240" height="180" class="alignright size-full wp-image-971" align="right" />By clicking on the button, you ask our servers to send you a specific file, for example: Firefox 3.6.3, for Windows, in German. On a small website, the server would just fetch the file and hand it to you. But if you need to handle millions of downloads a day like we do, a single server can&#8217;t handle it all by itself, so it gets more complicated. In order to provide you with downloads, updates, etc., as fast and conveniently as possible, Mozilla collaborates with a number of <a href="http://www.mozilla.org/community/mirrors.html">mirror providers</a> that have volunteered to host Firefox and other downloads on our behalf, thus sharing the load of our numerous downloads between a number of servers all over the world.</p>
<p>For some years now, we have been running a bundle of software called <a href="http://viewvc.svn.mozilla.org/vc/projects/bouncer/">&#8220;Bouncer&#8221;</a> to handle our downloads for us.</p>
<p>Bouncer consists of of three components: The user-facing <strong>bounce script</strong>, an <strong>administrative interface called Tuxedo</strong>, and a mirror checker called <strong>Sentry</strong>.</p>
<p>First, the <strong>bounce script</strong>. It is the only component the &#8220;ordinary user&#8221; gets to interact with. It essentially does the following after you click on a download link:</p>
<ul>
<li>It determines if the product you asked for exists.</li>
<li>Out of our list of mirrors, it picks one that has your file. Initially, it would pick one at random. Over the years, the logic has become more elaborate though: Meanwhile, it takes into account in what country you currently are, as well as how strong the mirrors are (stronger mirrors serve more downloads, weaker ones serve less).</li>
<li>A split-second later, Bouncer refers you to the server it decided on, and that server will send you the file you asked for.</li>
</ul>
<p>But wait, there is more! How does Bouncer know what products are available, for what operating systems, and in what languages? That&#8217;s where the <strong>admin interface</strong> comes in. We have a release engineering team who work hard every day to deliver the newest software versions to you in handy little packages. Previously, during every release, an engineer would manually tell Bouncer that a new version was available for download. But just last week, we improved this process by introducing a new interface to Bouncer, with a project called <a href="http://github.com/fwenzel/tuxedo/">Tuxedo</a>. The release engineering team can now, fully automatically, feed new versions into Bouncer at the time of release, with no manual intervention. With less time spent on repetitive tasks, we can spend more time making Firefox awesome.</p>
<p>Finally, the <strong>Sentry</strong> component is a script that periodically checks the health of our mirrors, and adjusts our settings accordingly. This is to ensure that a situation where you are forwarded to a mirror that is currently unavailable is very, very rare. So far, these mirror checks happen from Mozilla Headquarters, and therefore reflect the connectivity we get to the mirrors from here. In the future, we want to improve that by taking into account more how <em>our users&#8217; connectivity</em> is to the specific mirrors (for the geeks out there: <em>Network proximity != geographical proximity</em>), which has the potential to result in faster download times, less expenses for mirror providers, and general happiness.</p>
<p>As you can see, there are a lot of things happening behind the scenes before Firefox makes its way onto your computer at home, and we are constantly working on improving the way we are doing things. Plus, as always: Bouncer is completely <a href="http://github.com/fwenzel/tuxedo/">open source</a>, and we have a <a href="https://bugzilla.mozilla.org/buglist.cgi?query_format=advanced;product=Webtools;component=Bouncer;resolution=---">public bug tracker</a>, so if you notice any problems or see room for improvement, make sure to <a href="https://bugzilla.mozilla.org/enter_bug.cgi?product=Webtools&#038;component=Bouncer">let us know</a>.</p>
<p><em>Photo credit: <a href="http://www.flickr.com/photos/philliecasablanca/3263799851/">&#8220;directions&#8221;</a>, CC-by licensed by Phillie Casablanca.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/webdev/2010/05/07/what-happens-when-you-click-the-firefox-download-button/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bouncer Updates</title>
		<link>http://blog.mozilla.com/webdev/2007/08/16/bouncer-updates/</link>
		<comments>http://blog.mozilla.com/webdev/2007/08/16/bouncer-updates/#comments</comments>
		<pubDate>Thu, 16 Aug 2007 18:59:22 +0000</pubDate>
		<dc:creator>Mike Morgan</dc:creator>
				<category><![CDATA[Bouncer]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/webdev/2007/08/16/bouncer-updates/</guid>
		<description><![CDATA[Bouncer had a few updates last night: Database library rewritten to be lightweight and use memcache (see tests) Overall requests per second performance increased 2x Database usage down to about zero because of memcache To see the difference, I&#8217;ll show a couple of database graphs. Note that logging is still turned on, so there are [...]]]></description>
			<content:encoded><![CDATA[<p>Bouncer had a few updates last night:</p>
<ul>
<li><a href="https://svn.mozilla.org/projects/bouncer/1.0/trunk/php/lib/sdo.php">Database library</a> rewritten to be lightweight and use <a href="http://www.danga.com/memcached/">memcache</a> (<a href="https://svn.mozilla.org/projects/bouncer/1.0/trunk/tests/sdo.php">see tests</a>)</li>
<li>Overall requests per second performance increased 2x</li>
<li>Database usage down to about zero because of memcache</li>
</ul>
<p>To see the difference, I&#8217;ll show a couple of database graphs.  Note that logging is still turned on, so there are still database connections used for updating product and mirror counts.  We plan on disabling this in the future because these stats are backfilled from HTTP logs.</p>
<p>Pretty CPU graph:</p>
<p><img src="http://people.mozilla.org/~morgamic/cpu.png" alt="Database server CPU usage" height="241" width="597" /></p>
<p>Pretty traffic graph:</p>
<p><img src="http://people.mozilla.org/~morgamic/traffic.png" height="213" width="597" /></p>
<p>So CPU and traffic data was reduced significantly.  Here&#8217;s why:</p>
<ul>
<li> Bouncer is a special type of app &#8211; high amount of reads over a short period of time</li>
<li>The majority of these database reads are repeated over and over, especially recent releases (Firefox 2.0.0.6 for example)</li>
</ul>
<p>Again, database traffic flatlined during testing when logging was disabled so what you&#8217;re seeing is basically download count updates and the connections needed to run them.</p>
<p>To get an idea of exactly how much memcache is used, here are stats from memcache as of this morning (single server, after approximately 12 hours of usage):</p>
<ul>
<li>Gets: 29884170</li>
<li>Misses: 199515</li>
<li>Total Gets: 30083685</li>
<li>Hit %: 99.33679999641</li>
</ul>
<p>This means that of all queries, 99.33% were read from the cache.  Not bad.</p>
<p>This patch took two weeks longer than expected.  Challenges we faced:</p>
<ul>
<li><strong>Getting random mirror selection to work</strong> when not using &#8220;ORDER BY RAND()&#8221; as the way to randomize mirror selection &#8212; this was replaced by a simple hash and array sort algorithm that uses array values to weight overall probability of selection when combined with a random seed.  In general, random selection via SQL is inefficient and you&#8217;re better off using another method besides just RAND() &#8212; stored procedures, app code, whatever &#8212; but when you&#8217;re doing &#8220;ORDER BY RAND()&#8221; you&#8217;re in for some pain. Use EXPLAIN &#8212; it does not lie.</li>
<li><strong>Being stingy with MySQL connections.  </strong>The database library rewrite was required because we did not want to even connect to the database when memcache had all of our results cached.  However, mysql_real_escape_string() was used to escape queries and it requires an open database handle to work.  That meant that we had to only escape if we knew we were going to perform a query.  So we had to move cleaning of SQL inputs to inside the query callback function.  This was done by&#8230;</li>
<li><strong>Breaking away from the PHP4 mysql habit.  </strong>PHP 5.x has better support for this via <a href="http://www.php.net/mysqli">mysqli</a> but since we&#8217;re still on PHP4 for a little while, in order to mimic prepared statements without using a database interface we used a method much like what was <a href="http://trac.wordpress.org/ticket/4553">discussed among WordPress developers</a>.  It takes us from a connect() -&gt;clean -&gt; concatenate sql -&gt; query() approach to a prepared sql and args -&gt; query() -&gt; autoclean approach.</li>
</ul>
<p>Overall, this is another positive experience with memcache as a query cache.  We use the same method in AMO and plan on using it in other apps that will have to scale to any reasonable level.  It saves money in hardware and turns little apps that can sort-of do the job into supercharged workhorses.  Yay.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/webdev/2007/08/16/bouncer-updates/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

