<?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>Random Musings of an Insane Mind &#187; Varnish</title>
	<atom:link href="http://cd34.com/blog/tag/varnish/feed/" rel="self" type="application/rss+xml" />
	<link>http://cd34.com/blog</link>
	<description>This is my blog, there are many others like it but this one is mine.</description>
	<lastBuildDate>Tue, 29 Jun 2010 04:22:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>DDOS attack mitigation</title>
		<link>http://cd34.com/blog/webserver/ddos-attack-mitigation/</link>
		<comments>http://cd34.com/blog/webserver/ddos-attack-mitigation/#comments</comments>
		<pubDate>Mon, 26 Apr 2010 06:02:58 +0000</pubDate>
		<dc:creator>cd34</dc:creator>
				<category><![CDATA[Webserver Software]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[ddos]]></category>
		<category><![CDATA[Nginx]]></category>
		<category><![CDATA[Varnish]]></category>

		<guid isPermaLink="false">http://cd34.com/blog/?p=937</guid>
		<description><![CDATA[Today we had a DDOS attack on one of our clients. They were running prefork with mod_php5 with a rather busy application. While we initially started filtering IP addresses using iptables and a few crudely hacked rules, we knew something had to be done that was a little more permanent. Moving to MPM-Worker with PHP [...]]]></description>
			<content:encoded><![CDATA[<p>Today we had a DDOS attack on one of our clients.  They were running prefork with mod_php5 with a rather busy application.  While we initially started filtering IP addresses using iptables and a few crudely hacked rules, we knew something had to be done that was a little more permanent.  Moving to MPM-Worker with PHP served with FastCGI seemed reasonable, but, looking at the history of the attacks on this machine, I believe Apache still would have been vulnerable since we cannot filter the requests early enough in Apache&#8217;s request handler.</p>
<p>Apache does have the ability to fight some DDOS attacks using <a href="http://www.modsecurity.org/">mod_security</a> and <a href="http://www.zdziarski.com/blog/?page_id=442">mod_evasive</a>, but, this particular attack was designed to affect apache prior to the place where these modules hook into the request.  This also precludes using fail2ban.  We could run mod_forensic or mod_logio to assist fail2ban, but, it is still a stopgap measure.</p>
<p>We could have used some Snort rules and tied those to iptables, but, that is a rather bad solution to the problem.</p>
<p>While we could have used <a href="http://varnish-cache.org/">Varnish</a>, their application would have had some issues.  <a href="http://stderr.net/apache/rpaf/">mod_rpaf</a> can help by adjusting the REMOTE_ADDR to take the value from X-Forwarded-For that Varnish sets.  mod_geoip actually inserts itself before mod_rpaf, so, we would have needed to make a modification to mod_geoip and recompiled it.  I&#8217;m not sure how Varnish would have handled <a href="http://ha.ckers.org/slowloris/">Slowloris</a> and we had to fix this now. </p>
<p>Putting them behind a Layer 7 load balancer would have isolated the origin server and handled the brunt of the attack on the load balancer, but, again we would have needed mod_rpaf and some modifications to their code.</p>
<p>In the end, Lighttpd and Nginx appeared to be the only documented solution.  After the conversion, we did find documentation that said Varnish and Squid were immune to Slowloris.  With Nginx or Lighttpd, we didn&#8217;t have IP address issues to contend with, it would be easy enough to modify the fastcgi config to pass the GEOIP information in the same request variable that their application expected.  We knew we had to run PHP under FastCGI, so, we might as well pick a tool where we can block the attack in the webserver without having to worry about firewall rules.  We did put a few firewall rules in place to block the larger offenders.</p>
<p>in the http { } section of our nginx config, we added:</p>
<pre>
    client_body_timeout 10;
    client_header_timeout 10;
    keepalive_timeout 10;
    send_timeout 10;
    limit_zone limit_per_ip $binary_remote_addr 16m;
</pre>
<p>and in the server { } section, we added:</p>
<pre>
    limit_conn limit_per_ip 5;
</pre>
<p>Since each server was expecting to handle one or two requests from each IP, this gave us a little headroom while solving the problem in the right place.</p>
<p>I believe Varnish would have held the connection and wouldn&#8217;t have sent a request to the backend which makes it fairly versatile as a tool to deal with DDOS attacks.  While I do like the ability to block certain requests in VCL, the methods listed to fight this type of attack appeared to favor a non-threaded webserver.  Varnish in front of Apache would have worked, but, we already knew we needed to move from Apache at some point with this client and this gave us an opportunity to shift them while under the gun.</p>
<p>Wouldn&#8217;t have had it any other way.</p>
]]></content:encoded>
			<wfw:commentRss>http://cd34.com/blog/webserver/ddos-attack-mitigation/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>WordPress Cache Plugin Benchmarks</title>
		<link>http://cd34.com/blog/scalability/wordpress-cache-plugin-benchmarks/</link>
		<comments>http://cd34.com/blog/scalability/wordpress-cache-plugin-benchmarks/#comments</comments>
		<pubDate>Thu, 04 Mar 2010 15:55:03 +0000</pubDate>
		<dc:creator>cd34</dc:creator>
				<category><![CDATA[Scalability]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[Varnish]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://cd34.com/blog/?p=900</guid>
		<description><![CDATA[A lot of time and effort goes into keeping a WordPress site alive when it starts to accumulate traffic. While not every site has the same goals, keeping a site responsive and online is the number one priority. When a surfer requests the page, it should load quickly and be responsive. Each addon handles caching [...]]]></description>
			<content:encoded><![CDATA[<p>A lot of time and effort goes into keeping a WordPress site alive when it starts to accumulate traffic.  While not every site has the same goals, keeping a site responsive and online is the number one priority.  When a surfer requests the page, it should load quickly and be responsive.  Each addon handles caching a little differently and should be used in different cases.</p>
<p>For many sites, page caching will provide decent performance.  Once your sites starts receiving comments, or people log in, many cache solutions cache too heavily or not enough.  As many solutions as there are, it is obvious that WordPress underperforms in higher traffic situations.</p>
<p>The list of caching addons that we&#8217;re testing:</p>
<p>* <a href="http://wordpress.org/extend/plugins/db-cache/">DB Cache</a> (version 0.6)<br />
* <a href="http://wordpress.org/extend/plugins/db-cache-reloaded/">DB Cache Reloaded</a> (version 2.0.2)<br />
* <a href="http://wordpress.org/extend/plugins/w3-total-cache/">W3 Total Cache</a> (version 0.8.5.1)<br />
* <a href="http://wordpress.org/extend/plugins/wp-cache/">WP Cache</a> (version 2.1.2)<br />
* <a href="http://wordpress.org/extend/plugins/wp-super-cache/">WP Super Cache</a> (version 0.9.9)<br />
* <a href="http://wordpress.org/extend/plugins/wp-widget-cache/">WP Widget Cache</a> (version 0.25.2)<br />
* <a href="http://wordpress.org/extend/plugins/wp-file-cache/">WP File Cache</a>(version 1.2.5)<br />
* <a href="http://github.com/pkhamre/wp-varnish">WP Varnish</a> (in beta)<br />
* <a href="http://cd34.com/blog/scalability/wordpress-varnish-and-edge-side-includes/">WP Varnish ESI Widget</a> (in beta)</p>
<h2>What are we testing?</h2>
<p>* Frontpage hits<br />
* httpload through a series of urls</p>
<p>We take two measurements.  The cold start measurement is taken after any plugin cache has been cleared and Apache2 and MySQL have been restarted.  A 30 second pause is inserted prior to starting the tests.  We perform a frontpage hit 1000 times with 10 parallel connections.  We then repeat that test after Apache2 and the caching solution have had time to cache that page.  Afterwards, http_load requests a series of 30 URLs to simulate people surfing other pages.  Between those two measurements, we should have a pretty good indicator of how well a site is going to  perform in real life. </p>
<h2>What does the Test Environment look like?</h2>
<p>* Debian 3.1/Squeeze VPS<br />
* Linux Kernel 2.6.33<br />
* Single core of a Xen Virtualized Xeon X3220 (2.40ghz)<br />
* 2gb RAM<br />
* CoW file is written on a Raid-10 System using 4x1tb 7200RPM Drives<br />
* Apache 2.2.14 mpm-prefork<br />
* PHP 5.3.1<br />
* <a href="http://svn.automattic.com/wpcom-themes/test-data.2008-12-22.xml">WordPress Theme Test Data</a><br />
* Tests are performed from a Quadcore Xeon machine connected via 1000 Base T on the same switch and /24 as the VPS machine</p>
<p>This setup is designed to replicate what most people might choose to host a reasonably popular wordpress site.</p>
<h2><a name="tldr">tl;dr Results</a></h2>
<p>If you aren&#8217;t using Varnish in front of your web site, the clear winner is W3 Total Cache using Page Caching &#8211; Disk (Enhanced), Minify Caching &#8211; Alternative PHP Cache (APC), Database Caching &#8211; Alternative PHP Cache (APC).  </p>
<p>If you can use Varnish, WP Varnish would be a very simple way to gain quite a bit of performance while maintaining interactivity.  WP Varnish purges the cache when posts are made, allowing the site to be more dynamic and not suffer from the long cache delay before a page is updated.</p>
<p>W3 Total Cache has a number of options and sometimes settings can be quite detrimental to site performance.  If you can&#8217;t use APC caching or Memcached for caching Database queries or Minification, turn both off.  W3 Total Cache&#8217;s interface is overwhelming but the plugin author has indicated that he&#8217;ll be making a new &#8216;Wizard&#8217; configuration menu in the next version along with Fragment Caching.</p>
<p>WP Super Cache isn&#8217;t too far behind and is also a reasonable alternative.</p>
<p>Either way, if you want your site to survive, you need to use a cache addon.  Going from 2.5 requests per second to 800+ requests per second makes a considerable difference in the usability of your site for visitors.  Logged in users and search engine bots still see uncached/live results, so, you don&#8217;t need to worry that your site won&#8217;t be indexed properly.</p>
<h2>Results</h2>
<style>
.tborder { border:1px solid #000; }
.th { background-color: #ccc; }
.teven { background-color: #ddd; }
.tdnum { text-align: right; }
.trecommend { background-color: #cfc; }
.thonmen { background-color: #ffc; }
.tsmall { font-size: 8pt; }
</style>
<p>Sorted in Ascending order in terms of higher overall performance</p>
<table class="tborder">
<tr class="th">
<td>Addon</td>
<td>Apachebench</td>
<td colspan="2">Cold Start<br />Warm Start</td>
<td>http_load</td>
<td colspan="2">Cold Start<br />Warm Start</td>
</tr>
<tr class="th">
<td></td>
<td>Req/Second</td>
<td>Time/Request</td>
<td>50% within x ms</td>
<td>Fetches/Second</td>
<td>Min First Response</td>
<td>Avg First Response</td>
</tr>
<tr>
<td>Baseline</td>
<td class="tdnum">4.97</td>
<td class="tdnum">201.006</td>
<td class="tdnum">2004</td>
<td class="tdnum">15.1021</td>
<td class="tdnum">335.708</td>
<td class="tdnum">583.363</td>
</tr>
<tr>
<td class="tdnum"></td>
<td class="tdnum">5.00</td>
<td class="tdnum">200.089</td>
<td class="tdnum">2000</td>
<td class="tdnum">15.1712</td>
<td class="tdnum">304.446</td>
<td class="tdnum">583.684</td>
</tr>
<tr class="teven">
<td>DB Cache</td>
<td class="tdnum">4.80</td>
<td class="tdnum">208.436</td>
<td class="tdnum">2087</td>
<td class="tdnum">15.1021</td>
<td class="tdnum">335.708</td>
<td class="tdnum">583.363</td>
</tr>
<tr class="teven">
<td class="tsmall">Cached all SQL queries</td>
<td class="tdnum">4.81</td>
<td class="tdnum">207.776</td>
<td class="tdnum">2091</td>
<td class="tdnum">15.1712</td>
<td class="tdnum">304.446</td>
<td class="tdnum">583.684</td>
</tr>
<tr>
<td>DB Cache</td>
<td class="tdnum">4.87</td>
<td class="tdnum">205.250</td>
<td class="tdnum">2035</td>
<td class="tdnum">14.1992</td>
<td class="tdnum">302.335</td>
<td class="tdnum">621.092</td>
</tr>
<tr>
<td class="tsmall">Out of Box config</td>
<td class="tdnum">4.94</td>
<td class="tdnum">202.624</td>
<td class="tdnum">2026</td>
<td class="tdnum">14.432</td>
<td class="tdnum">114.983</td>
<td class="tdnum">618.434</td>
</tr>
<tr class="teven">
<td>WP File Cache</td>
<td class="tdnum">4.95</td>
<td class="tdnum">201.890</td>
<td class="tdnum">2009</td>
<td class="tdnum">15.8869</td>
<td class="tdnum">158.597</td>
<td class="tdnum">549.176</td>
</tr>
<tr class="teven">
<td></td>
<td class="tdnum">4.99</td>
<td class="tdnum">200.211</td>
<td class="tdnum">2004</td>
<td class="tdnum">16.1758</td>
<td class="tdnum">99.728</td>
<td class="tdnum">544.107</td>
</tr>
<tr>
<td>DB Cache Reloaded</td>
<td class="tdnum">5.02</td>
<td class="tdnum">199.387</td>
<td class="tdnum">1983</td>
<td class="tdnum">15.0167</td>
<td class="tdnum">187.343</td>
<td class="tdnum">589.196</td>
</tr>
<tr>
<td class="tsmall">All SQL Queries Cached</td>
<td class="tdnum">5.03</td>
<td class="tdnum">200.089</td>
<td class="tdnum">1985</td>
<td class="tdnum">14.9233</td>
<td class="tdnum">150.145</td>
<td class="tdnum">586.443</td>
</tr>
<tr class="teven">
<td>DB Cache Reloaded</td>
<td class="tdnum">5.06</td>
<td class="tdnum">197.636</td>
<td class="tdnum">1968</td>
<td class="tdnum">14.9697</td>
<td class="tdnum">174.857</td>
<td class="tdnum">589.161</td>
</tr>
<tr class="teven">
<td class="tsmall">Out of Box config</td>
<td class="tdnum">5.08</td>
<td class="tdnum">196.980</td>
<td class="tdnum">1968</td>
<td class="tdnum">15.181</td>
<td class="tdnum">257.533</td>
<td class="tdnum">587.737</td>
</tr>
<tr>
<td>Widgetcache</td>
<td class="tdnum">6.667</td>
<td class="tdnum">149.903</td>
<td class="tdnum">1492</td>
<td class="tdnum">15.0264</td>
<td class="tdnum">245.332</td>
<td class="tdnum">602.039</td>
</tr>
<tr>
<td class="tdnum"></td>
<td class="tdnum">6.72</td>
<td class="tdnum">148.734</td>
<td class="tdnum">1487</td>
<td class="tdnum">15.1887</td>
<td class="tdnum">299.65</td>
<td class="tdnum">598.017</td>
</tr>
<tr class="teven">
<td>W3 Total Cache</td>
<td class="tdnum">153.45</td>
<td class="tdnum">65.167</td>
<td class="tdnum">60</td>
<td class="tdnum">133.1898</td>
<td class="tdnum">8.916</td>
<td class="tdnum">85.7177</td>
</tr>
<tr class="teven">
<td class="tsmall">DB Cache off, Page Caching with Memcached</td>
<td class="tdnum">169.46</td>
<td class="tdnum">59.011</td>
<td class="tdnum">57</td>
<td class="tdnum">188.4</td>
<td class="tdnum">9.107</td>
<td class="tdnum">50.142</td>
</tr>
<tr>
<td>W3 Total Cache</td>
<td class="tdnum">173.49</td>
<td class="tdnum">57.639</td>
<td class="tdnum">52</td>
<td class="tdnum">108.898</td>
<td class="tdnum">7.668</td>
<td class="tdnum">86.4077</td>
</tr>
<tr>
<td class="tsmall">DB Cache off, Minify Cache with Memcached</td>
<td class="tdnum">189.76</td>
<td class="tdnum">52.698</td>
<td class="tdnum">48</td>
<td class="tdnum">203.522</td>
<td class="tdnum">8.122</td>
<td class="tdnum">43.8795</td>
</tr>
<tr class="teven">
<td>W3 Total Cache</td>
<td class="tdnum">171.34</td>
<td class="tdnum">58.364</td>
<td class="tdnum">50</td>
<td class="tdnum">203.718</td>
<td class="tdnum">8.097</td>
<td class="tdnum">44.1234</td>
</tr>
<tr class="teven">
<td class="tsmall">DB Cache using Memcached</td>
<td class="tdnum">190.01</td>
<td class="tdnum">52.269</td>
<td class="tdnum">48</td>
<td class="tdnum">206.187</td>
<td class="tdnum">8.186</td>
<td class="tdnum">42.4438</td>
</tr>
<tr>
<td>W3 Total Cache</td>
<td class="tdnum">175.29</td>
<td class="tdnum">57.048</td>
<td class="tdnum">48</td>
<td class="tdnum">87.423</td>
<td class="tdnum">7.515</td>
<td class="tdnum">107.973</td>
</tr>
<tr>
<td class="tsmall">Out of Box config</td>
<td class="tdnum">191.15</td>
<td class="tdnum">52.314</td>
<td class="tdnum">47</td>
<td class="tdnum">204.387</td>
<td class="tdnum">8.288</td>
<td class="tdnum">43.217</td>
</tr>
<tr class="teven">
<td>W3 Total Cache</td>
<td class="tdnum">175.29</td>
<td class="tdnum">57.047</td>
<td class="tdnum">51</td>
<td class="tdnum">204.557</td>
<td class="tdnum">8.199</td>
<td class="tdnum">42.9365</td>
</tr>
<tr class="teven">
<td class="tsmall">Database Cache using APC</td>
<td class="tdnum">191.19</td>
<td class="tdnum">52.304</td>
<td class="tdnum">48</td>
<td class="tdnum">200.612</td>
<td class="tdnum">8.11</td>
<td class="tdnum">44.6691</td>
</tr>
<tr>
<td>W3 Total Cache</td>
<td class="tdnum">114.02</td>
<td class="tdnum">87.703</td>
<td class="tdnum">49</td>
<td class="tdnum">114.393</td>
<td class="tdnum">8.206</td>
<td class="tdnum">82.0678</td>
</tr>
<tr>
<td class="tsmall">Database Cache Disabled</td>
<td class="tdnum">191.76</td>
<td class="tdnum">52.150</td>
<td class="tdnum">49</td>
<td class="tdnum">203.781</td>
<td class="tdnum">8.095</td>
<td class="tdnum">42.558</td>
</tr>
<tr class="teven">
<td>W3 Total Cache</td>
<td class="tdnum">175.80</td>
<td class="tdnum">56.884</td>
<td class="tdnum">51</td>
<td class="tdnum">107.842</td>
<td class="tdnum">7.281</td>
<td class="tdnum">87.2761</td>
</tr>
<tr class="teven">
<td class="tsmall">Database Cache Disabled, Minify Cache using APC</td>
<td class="tdnum">192.01</td>
<td class="tdnum">52.082</td>
<td class="tdnum">50</td>
<td class="tdnum">205.66</td>
<td class="tdnum">8.244</td>
<td class="tdnum">43.1231</td>
</tr>
<tr>
<td>W3 Total Cache</td>
<td class="tdnum">104.90</td>
<td class="tdnum">95.325</td>
<td class="tdnum">51</td>
<td class="tdnum">123.041</td>
<td class="tdnum">7.868</td>
<td class="tdnum">74.5887</td>
</tr>
<tr>
<td class="tsmall">Database Cache Disabled, Page Caching using APC</td>
<td class="tdnum">197.55</td>
<td class="tdnum">50.620</td>
<td class="tdnum">46</td>
<td class="tdnum">210.445</td>
<td class="tdnum">7.907</td>
<td class="tdnum">41.4102</td>
</tr>
<tr class="teven">
<td>WP Super Cache</td>
<td class="tdnum">336.88</td>
<td class="tdnum">2.968</td>
<td class="tdnum">16</td>
<td class="tdnum">15.1021</td>
<td class="tdnum">335.708</td>
<td class="tdnum">583.363</td>
</tr>
<tr class="teven">
<td class="tsmall">Out of Box config, Half On</td>
<td class="tdnum">391.59</td>
<td class="tdnum">2.554</td>
<td class="tdnum">16</td>
<td class="tdnum">15.1712</td>
<td class="tdnum">304.446</td>
<td class="tdnum">583.684</td>
</tr>
<tr>
<td>WP Cache</td>
<td class="tdnum">161.63</td>
<td class="tdnum">6.187</td>
<td class="tdnum">12</td>
<td class="tdnum">15.1021</td>
<td class="tdnum">335.708</td>
<td class="tdnum">583.363</td>
</tr>
<tr>
<td></td>
<td class="tdnum">482.29</td>
<td class="tdnum">20.735</td>
<td class="tdnum">11</td>
<td class="tdnum">15.1712</td>
<td class="tdnum">304.446</td>
<td class="tdnum">583.684</td>
</tr>
<tr class="teven">
<td>WP Super Cache</td>
<td class="tdnum">919.11</td>
<td class="tdnum">1.088</td>
<td class="tdnum">3</td>
<td class="tdnum">190.117</td>
<td class="tdnum">1.473</td>
<td class="tdnum">47.9367</td>
</tr>
<tr class="teven">
<td class="tsmall">Full on, Lockdown mode</td>
<td class="tdnum">965.69</td>
<td class="tdnum">1.036</td>
<td class="tdnum">3</td>
<td class="tdnum">975.979</td>
<td class="tdnum">1.455</td>
<td class="tdnum">9.67185</td>
</tr>
<tr class="thonmen">
<td>WP Super Cache</td>
<td class="tdnum">928.45</td>
<td class="tdnum">1.077</td>
<td class="tdnum">3</td>
<td class="tdnum">210.106</td>
<td class="tdnum">1.468</td>
<td class="tdnum">43.8167</td>
</tr>
<tr class="thonmen">
<td class="tsmall">Full on</td>
<td class="tdnum">970.45</td>
<td class="tdnum">1.030</td>
<td class="tdnum">3</td>
<td class="tdnum">969.256</td>
<td class="tdnum">1.488</td>
<td class="tdnum">9.78753</td>
</tr>
<tr class="teven">
<td>W3 Total Cache</td>
<td class="tdnum">1143.94</td>
<td class="tdnum">8.742</td>
<td class="tdnum">2</td>
<td class="tdnum">165.547</td>
<td class="tdnum">0.958</td>
<td class="tdnum">56.7702</td>
</tr>
<tr class="teven">
<td class="tsmall">Page Cache using Disk Enhanced</td>
<td class="tdnum">1222.16</td>
<td class="tdnum">8.182</td>
<td class="tdnum">3</td>
<td class="tdnum">1290.43</td>
<td class="tdnum">0.961</td>
<td class="tdnum">7.15632</td>
</tr>
<tr class="trecommend">
<td>W3 Total Cache</td>
<td class="tdnum">1153.50</td>
<td class="tdnum">8.669</td>
<td class="tdnum">3</td>
<td class="tdnum">165.725</td>
<td class="tdnum">0.916</td>
<td class="tdnum">56.5004</td>
</tr>
<tr class="trecommend">
<td class="tsmall">Page Caching &#8211; Disk Enhanced, Minify/Database using APC</td>
<td class="tdnum">1211.22</td>
<td class="tdnum">8.256</td>
<td class="tdnum">2</td>
<td class="tdnum">1305.94</td>
<td class="tdnum">0.948</td>
<td class="tdnum">6.97114</td>
</tr>
<tr class="teven">
<td>Varnish ESI</td>
<td class="tdnum">2304.18</td>
<td class="tdnum">0.434</td>
<td class="tdnum">4</td>
<td class="tdnum">349.351</td>
<td class="tdnum">0.221</td>
<td class="tdnum">28.1079</td>
</tr>
<tr class="teven">
<td></td>
<td class="tdnum">2243.33</td>
<td class="tdnum">0.44689</td>
<td class="tdnum">4</td>
<td class="tdnum">4312.78</td>
<td class="tdnum">0.152</td>
<td class="tdnum">2.09931</td>
</tr>
<tr class="trecommend">
<td>WP Varnish</td>
<td class="tdnum">1683.89</td>
<td class="tdnum">0.594</td>
<td class="tdnum">3</td>
<td class="tdnum">369.543</td>
<td class="tdnum">0.155</td>
<td class="tdnum">26.8906</td>
</tr>
<tr class="trecommend">
<td></td>
<td class="tdnum">3028.41</td>
<td class="tdnum">0.330</td>
<td class="tdnum">3</td>
<td class="tdnum">4318.48</td>
<td class="tdnum">0.148</td>
<td class="tdnum">2.15063</td>
</tr>
</table>
<h2>Test Script</h2>
<pre>
#!/bin/sh

FETCHES=1000
PARALLEL=10

/usr/sbin/apache2ctl stop
/etc/init.d/mysql restart
apache2ctl start
echo Sleeping
sleep 30
time ( \
echo First Run; \
ab -n $FETCHES -c $PARALLEL http://example.com/; \
echo Second Run; \
ab -n $FETCHES -c $PARALLEL http://example.com/; \
\
echo First Run; \
./http_load -parallel $PARALLEL -fetches $FETCHES wordpresstest; \
echo Second Run; \
./http_load -parallel $PARALLEL -fetches $FETCHES wordpresstest; \
)
</pre>
<h2>URL File for http_load</h2>
<pre>

http://example.com/

http://example.com/2010/03/hello-world/

http://example.com/2008/09/layout-test/

http://example.com/2008/04/simple-gallery-test/

http://example.com/2007/12/category-name-clash/

http://example.com/2007/12/test-with-enclosures/

http://example.com/2007/11/block-quotes/

http://example.com/2007/11/many-categories/

http://example.com/2007/11/many-tags/

http://example.com/2007/11/tags-a-and-c/

http://example.com/2007/11/tags-b-and-c/

http://example.com/2007/11/tags-a-and-b/

http://example.com/2007/11/tag-c/

http://example.com/2007/11/tag-b/

http://example.com/2007/11/tag-a/

http://example.com/2007/09/tags-a-b-c/

http://example.com/2007/09/raw-html-code/

http://example.com/2007/09/simple-markup-test/

http://example.com/2007/09/embedded-video/

http://example.com/2007/09/contributor-post-approved/

http://example.com/2007/09/one-comment/

http://example.com/2007/09/no-comments/

http://example.com/2007/09/many-trackbacks/

http://example.com/2007/09/one-trackback/

http://example.com/2007/09/comment-test/

http://example.com/2007/09/a-post-with-multiple-pages/

http://example.com/2007/09/lorem-ipsum/

http://example.com/2007/09/cat-c/

http://example.com/2007/09/cat-b/

http://example.com/2007/09/cat-a/

http://example.com/2007/09/cats-a-and-c/
</pre>
]]></content:encoded>
			<wfw:commentRss>http://cd34.com/blog/scalability/wordpress-cache-plugin-benchmarks/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Using Varnish to assist with AB Testing</title>
		<link>http://cd34.com/blog/webserver/using-varnish-to-assist-with-ab-testing/</link>
		<comments>http://cd34.com/blog/webserver/using-varnish-to-assist-with-ab-testing/#comments</comments>
		<pubDate>Fri, 26 Feb 2010 01:48:49 +0000</pubDate>
		<dc:creator>cd34</dc:creator>
				<category><![CDATA[Webserver Software]]></category>
		<category><![CDATA[abtest]]></category>
		<category><![CDATA[analytics]]></category>
		<category><![CDATA[Varnish]]></category>

		<guid isPermaLink="false">http://cd34.com/blog/?p=896</guid>
		<description><![CDATA[While working with a recent client project, they mentioned AB Testing a few designs. While I enjoy statistics, we looked at Google&#8217;s Website Optimizer to track trials and conversions. After some internal testing, we opted to use Funnels and Goals rather than the AB or Multivariate test. I had little control over the origin server, [...]]]></description>
			<content:encoded><![CDATA[<p>While working with a recent client project, they mentioned AB Testing a few designs.  While I enjoy statistics, we looked at Google&#8217;s Website Optimizer to track trials and conversions.  After some internal testing, we opted to use Funnels and Goals rather than the AB or Multivariate test.  I had little control over the origin server, but I did have control over the front-end cache.</p>
<p>Our situation reminded me of a situation I encountered years ago.  A client had an inhouse web designer and a subcontracted web designer.  I felt the subcontracted web designer&#8217;s design would convert better.  The client wasn&#8217;t completely convinced, but agreed to running two designs head to head.  However, their implementation of the test biased the results.</p>
<h2>What went wrong?</h2>
<p>Each design was run for a week, in series.  While this provided ample time for gathering data, the inhouse designer&#8217;s design ran during a national holiday with a three day weekend, and the subcontractor&#8217;s design ran the following week.  Internet traffic patterns, the holiday weekend, weather, sporting events, TV/Movie premieres, etc. added so many variables which should have invalidated the results.</p>
<p>Since Google&#8217;s AB Testing has session persistence and splits traffic between the AB tests, we need to emulate this behavior.  When people run AB tests in series rather than parallel, or, switch pages with a cron job or some other automated method, I cringe.  A test at 5pm EST and 6pm EST will yield different results.  At 5pm EST, your target audience could be driving home from work.  At 6pm EST they could be sitting down for dinner.</p>
<h2>How can Varnish help?</h2>
<p>If we allow Varnish to select the landing page/offer page outside the origin server&#8217;s control, we can run both tests run at the same time.  An internet logjam in Seattle, WA would affect both tests evenly.  Likewise, a national or worldwide event would affect both tests equally.  Now that we know how to make sure the AB Test is fairly balanced, we have to implement it.</p>
<p>Redirection sometimes plays havoc on browsers and spiders, so, we&#8217;ll rewrite the URL within Varnish using some Inline C and VCL.  Google uses javascript and a document.location call to send some visitors to the B/alternate page.  Users that have javascript disabled, will only see the Primary page.</p>
<p>Our Varnish config file contains the following:</p>
<pre>
sub vcl_recv {
  if (req.url == "/") {
    C{
      char buff[5];
      sprintf(buff,"%d",rand()%2 + 1);
      VRT_SetHdr(sp, HDR_REQ, "\011X-ABtest:", buff);
    }C
    set req.url = "/" req.http.X-ABtest "/" req.url;
  }
}
</pre>
<p>We&#8217;ve placed our landing pages in /1/ and /2/ directories on our origin server.  The only page Varnish intercepts is the index page at the root of the site.  Varnish randomly chooses to serve the index.html page from /1/ or /2/, internally rewrites our URL and serves it from the cache or the origin server.  Since the URL rewriting is done within vcl_recv, subsequent requests for the page don&#8217;t hit the origin.  The same method can be used to test landing pages that aren&#8217;t at the root of your site by modifying the if (req.url == &#8220;&#8221;) { condition.</p>
<p>You can test multipage offers by placing additional pages within the /1/ and /2/ directories on your origin along with the signup form.  Unlike Google&#8217;s AB Test, Varnish does not support session persistence.  Reloading the root page will result in the surfer alternating between both test pages.  Subsequent pages need to be loaded from /1/ or /2/ based on which landing page was selected.</p>
<p>When doing any AB Test, change as few variables as possible, document the changes, and analyze the difference between the results.  Running at least 1000 views of each is an absolute minimum.  While Google&#8217;s Multivariate test provides a lot more options, a simple AB test between two pages or site tours can give some insight into what works rather easily.</p>
<p>If you cannot use Google&#8217;s AB Test or the Multivariate Test, using their Funnels and Goals tool will still allow you to do AB Testing.</p>
]]></content:encoded>
			<wfw:commentRss>http://cd34.com/blog/webserver/using-varnish-to-assist-with-ab-testing/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Varnish VCL, Inline C and a random image</title>
		<link>http://cd34.com/blog/webserver/varnish-vcl-inline-c-and-a-random-image/</link>
		<comments>http://cd34.com/blog/webserver/varnish-vcl-inline-c-and-a-random-image/#comments</comments>
		<pubDate>Thu, 18 Feb 2010 23:48:35 +0000</pubDate>
		<dc:creator>cd34</dc:creator>
				<category><![CDATA[Webserver Software]]></category>
		<category><![CDATA[inline c]]></category>
		<category><![CDATA[Varnish]]></category>
		<category><![CDATA[vcl]]></category>
		<category><![CDATA[vcl_recv]]></category>

		<guid isPermaLink="false">http://cd34.com/blog/?p=884</guid>
		<description><![CDATA[While working with the prototype of a site, I wanted to have a particular panel image randomly chosen when the page was viewed. While this could be done on the server side, I wanted to move this to Varnish so that Varnish&#8217;s cache would be used rather than piping the request through each time to [...]]]></description>
			<content:encoded><![CDATA[<p>While working with the prototype of a site, I wanted to have a particular panel image randomly chosen when the page was viewed.  While this could be done on the server side, I wanted to move this to Varnish so that Varnish&#8217;s cache would be used rather than piping the request through each time to the origin server.</p>
<p>At the top of /etc/varnish/default.vcl</p>
<pre>C{
  #include &lt;stdlib.h&gt;
  #include &lt;stdio.h&gt;
}C
</pre>
<p>and our vcl_recv function gets the following:</p>
<pre>
  if (req.url ~ "^/panel/") {
    C{
      char buff[5];
      sprintf(buff,"%d",rand()%4);
      VRT_SetHdr(sp, HDR_REQ, "\010X-Panel:", buff);
    }C
    set req.url = regsub(req.url, "^/panel/(.*)\.(.*)$", "/panel/\1.ZZZZ.\2");
    set req.url = regsub(req.url, "ZZZZ", req.http.X-Panel);
  }
</pre>
<p>The above code allows for us to specify the source code in the html document as:</p>
<pre>
&lt;img src="/panel/random.jpg" width="300" height="300" alt="Panel Image"/&gt;
</pre>
<p>Since we have modified the request uri in vcl_recv before the object is cached, subsequent requests for the same modified URI will be served from Varnish&#8217;s cache, without requiring another fetch from the origin server.  Based on the other VCL and preferences, you can specify a long expire time, remove cookies, or do ESI processing.  Since the regexp passes the extension through, we could also randomly choose .html, .css, .jpg or any other extension you desire.</p>
<p>In the directory panel, you would need to have   </p>
<pre>
/panel/random.0.jpg
/panel/random.1.jpg
/panel/random.2.jpg
/panel/random.3.jpg
</pre>
<p>which would be served by Varnish when the url /panel/random.jpg is requested.</p>
<p>Moving that process to Varnish should cut down on the load from the origin server while making your site look active and dynamic.</p>
]]></content:encoded>
			<wfw:commentRss>http://cd34.com/blog/webserver/varnish-vcl-inline-c-and-a-random-image/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Django CMS to support Varnish and Akamai ESI</title>
		<link>http://cd34.com/blog/framework/django-cms-to-support-varnish-and-akamai-esi/</link>
		<comments>http://cd34.com/blog/framework/django-cms-to-support-varnish-and-akamai-esi/#comments</comments>
		<pubDate>Fri, 18 Dec 2009 22:50:00 +0000</pubDate>
		<dc:creator>cd34</dc:creator>
				<category><![CDATA[Framework]]></category>
		<category><![CDATA[akamai]]></category>
		<category><![CDATA[cms]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[esi]]></category>
		<category><![CDATA[pylons]]></category>
		<category><![CDATA[Varnish]]></category>

		<guid isPermaLink="false">http://cd34.com/blog/?p=870</guid>
		<description><![CDATA[Many years ago I ran into a situation with a client where the amount of traffic they were receiving was crushing their dynamically created site. Computation is always the enemy of a quick pageload, so, it is very important to do as little computation as possible when delivering a page. While there are many ways [...]]]></description>
			<content:encoded><![CDATA[<p>Many years ago I ran into a situation with a client where the amount of traffic they were receiving was crushing their dynamically created site.  Computation is always the enemy of a quick pageload, so, it is very important to do as little computation as possible when delivering a page.</p>
<p>While there are many ways to put together a CMS, high traffic CMS sites usually involve caching or lots of hardware.  Some write static files which are much less strenuous, but, you lose some of the dynamic capabilities.  Fragment caching becomes a method to make things a bit more dynamic as <a href="http://masonhq.com/">MasonHQ</a> does with their page and block structure.  <a href="http://code.google.com/p/django-blocks/">Django-blocks</a> was surely influenced by this or reinvented this method.</p>
<p>In order to get the highest performance out of a CMS with a page and block method, I had considered writing a filesystem or inode linklist that would allow the webserver to assemble the page by following the inodes on the disk to build the page.  Obviously there are some issues here, but, if a block was updated by a process, it would automatically be reassembled.  This emulates a write-through cache and would have provisions for dynamic content to be mixed in with the static content on disk.  Assembly of the page still takes more compute cycles than a static file but is significantly less than dynamically creating the page from multiple queries.</p>
<p>That design seriously limits the ability to deploy the system widely.  While I can control the hosting environment for personal projects, the CMS couldn&#8217;t gain wide acceptance.  While Varnish is a rather simple piece of software to install, it does limit deploy-ability, but, provides a significant piece of the puzzle due to Edge Side Includes (ESI).  If the CMS gets used beyond personal and small deployments, Akamai supports Edge Side Includes as well.</p>
<p>Rather than explain ESI, <a href="http://www.trygve-lie.com/blog/entry/esi_explained_simple">ESI Explained Simply</a> contains about the best writeup I&#8217;ve seen to date to explain how ESI can be used.</p>
<p>The distinction here is using fragment caching controlled by ESI to represent different zones on the page.  As a simple example, lets consider our page template contains an article and a block with the top five articles on the site.  When a new post is added, we can expire the block that contains the top five articles so that it is requested on the next page fetch.  Since the existing article didn&#8217;t change, the interior ESI included block doesn&#8217;t need to be purged.  This allows the page to be constructed on the Edge rather than on the Origin server.</p>
<p>As I have worked with a number of PHP frameworks, none really met my needs so I started using Python frameworks roughly two years ago.  For this CMS, I debated using Pylons or Django and ended up choosing <a href="http://www.djangoproject.com/">Django</a>.  Since both can be run behind WSGI compliant servers, we&#8217;ve opened ourselves up to a number of potential solutions.  Since we are running Varnish in front of our Origin server, we can run Apache2 with mod_wsgi, but, we&#8217;re not limited to that configuration.  At this point, we have a relatively generic configuration the CMS can run on, but, there are many other places we can adapt the configuration for our preferences.</p>
<p>Some of the potential caveats:<br />
* With <a href="http://varnish.projects.linpro.no/">Varnish</a> or <a href="http://www.akamai.com/">Akamai</a> as a frontend, we need to pay closer attention to X-Forwarded-For:<br />
* Web logs won&#8217;t exist because Varnish is serving and assembling the pages (There is a trick using ESI that could be employed if logging was critical)<br />
* ESI processed pages with Varnish are not compressed.  This is on their <a href="http://varnish.projects.linpro.no/wiki/PostTwoShoppingList">wishlist</a>.</p>
<p>Features:<br />
* Content can exist in multiple categories or tags<br />
* Flexible URL mapping<br />
* Plugin architecture for Blocks and Elements<br />
* Content will maintain revisions and by default allow comments and threaded comments</p>
<p>Terms:<br />
* Template &#8211; the graphical layout of the page with minimal CMS markup<br />
* Element &#8211; the graphical template that is used to render a Block<br />
* Block &#8211; a module that generates the data rendered by an Element<br />
* Page &#8211; a Page determined by a Title, Slug and elements<br />
* Content &#8211; The actual data that rendered by a block</p>
<p>Goals:<br />
* Flexible enough to handle something as simple as a personal blog, but, also capable of powering a highly trafficed site.<br />
* Data storage of common elements to handle publishing of content and comments with the ability to store information to allow threaded comments.  This would allow the CMS to handle a blog application, a CMS, or, a forum.<br />
* A method to store ancillary data in a model so that upgrades to the existing database model will not affect developed plugins.<br />
* Block system to allow prepackaged css/templating while allowing local replacement without affecting the default package.<br />
* Upgrades through pypy or easy_install.<br />
* Ability to add CDN/ESI without needing to modify templates.  The system will run without needing to be behind Varnish, but, its full power won&#8217;t be realized without Varnish or Akamai in front of the origin server.<br />
* Seamless integration of affiliate referral tracking and conversion statistics</p>
<p>At this point, the question in my mind was whether or not to start with an existing project and adapt it or start from scratch.  At this point, the closest Django CMS I could find was Django-Blocks and I do intend to look it over fairly closely, but, a cursory look showed the authors were taking it in a slightly different direction than I anticipated.  I&#8217;ll certainly look through the code again, but, the way I&#8217;ve envisioned this, I think there are some fundamental points that clash.</p>
<p>As I already have much of the database model written for an older PHP CMS that I wrote, I&#8217;m addressing some of the shortcomings I ran across with that design and modifying the models to be a little more generic.  While I am sure there are proprietary products that currently utilize ESI, I believe my approach is unique and flexible enough to power everything from a blog to a site or forums or even a classified ads site.</p>
]]></content:encoded>
			<wfw:commentRss>http://cd34.com/blog/framework/django-cms-to-support-varnish-and-akamai-esi/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>No ESI processing, first char not &#8216;</title>
		<link>http://cd34.com/blog/infrastructure/no-esi-processing-first-char-not/</link>
		<comments>http://cd34.com/blog/infrastructure/no-esi-processing-first-char-not/#comments</comments>
		<pubDate>Wed, 02 Dec 2009 03:26:49 +0000</pubDate>
		<dc:creator>cd34</dc:creator>
				<category><![CDATA[Web Infrastructure]]></category>
		<category><![CDATA[edge side include]]></category>
		<category><![CDATA[esi]]></category>
		<category><![CDATA[Varnish]]></category>

		<guid isPermaLink="false">http://cd34.com/blog/?p=837</guid>
		<description><![CDATA[After installing Varnish 2.0.5 on a machine, ESI Includes didn&#8217;t work. When using varnishlog, the first error that occurred when debugging was: No ESI processing, first char not &#8216;< ' 12 SessionClose &#8211; timeout 12 StatSess &#8211; 124.177.181.149 50662 4 0 0 0 0 0 0 0 12 SessionOpen c 68.212.183.136 60087 66.244.147.44:80 12 ReqStart [...]]]></description>
			<content:encoded><![CDATA[<p>After installing Varnish 2.0.5 on a machine, ESI Includes didn&#8217;t work.  When using varnishlog, the first error that occurred when debugging was:</p>
<p>No ESI processing, first char not &#8216;< '</p>
<pre>
   12 SessionClose &#8211; timeout
   12 StatSess     &#8211; 124.177.181.149 50662 4 0 0 0 0 0 0 0
   12 SessionOpen  c 68.212.183.136 60087 66.244.147.44:80
   12 ReqStart     c 68.212.183.136 60087 409391565
   12 RxRequest    c GET
   12 RxURL        c /esi.html
   12 RxProtocol   c HTTP/1.1
   12 RxHeader     c Host: cd34.colocdn.com
   12 RxHeader     c User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2b4) Gecko/20091124 Firefox/3.6b4
   12 RxHeader     c Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
   12 RxHeader     c Accept-Language: en-us,en;q=0.5
   12 RxHeader     c Accept-Encoding: gzip,deflate
   12 RxHeader     c Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
   12 RxHeader     c Keep-Alive: 115
   12 RxHeader     c Connection: keep-alive
   12 RxHeader     c X-lori-time-1: 1259718658980
   12 RxHeader     c Cache-Control: max-age=0
   12 VCL_call     c recv
   12 VCL_return   c lookup
   12 VCL_call     c hash
   12 VCL_return   c hash
   12 VCL_call     c miss
   12 VCL_return   c fetch
   12 Backend      c 14 cd34_com cd34_com
   12 ObjProtocol  c HTTP/1.1
   12 ObjStatus    c 200
   12 ObjResponse  c OK
   12 ObjHeader    c Date: Wed, 02 Dec 2009 01:50:59 GMT
   12 ObjHeader    c Server: Apache
   12 ObjHeader    c Vary: Accept-Encoding
   12 ObjHeader    c Content-Encoding: gzip
   12 ObjHeader    c Content-Type: text/html
   12 TTL          c 409391565 RFC 120 1259718659 0 0 0 0
   12 VCL_call     c fetch
   12 TTL          c 409391565 VCL 43200 1259718659
   12 ESI_xmlerror c No ESI processing, first char not &#8216;< '
   12 TTL          c 409391565 VCL 0 1259718659
   12 VCL_info     c XID 409391565: obj.prefetch (-30) less than ttl (-1), ignored.
   12 VCL_return   c deliver
   12 Length       c 68
   12 VCL_call     c deliver
   12 VCL_return   c deliver
   12 TxProtocol   c HTTP/1.1
   12 TxStatus     c 200
   12 TxResponse   c OK
   12 TxHeader     c Server: Apache
   12 TxHeader     c Vary: Accept-Encoding
   12 TxHeader     c Content-Encoding: gzip
   12 TxHeader     c Content-Type: text/html
   12 TxHeader     c Content-Length: 68
   12 TxHeader     c Date: Wed, 02 Dec 2009 01:50:59 GMT
   12 TxHeader     c X-Varnish: 409391565
   12 TxHeader     c Age: 0
   12 TxHeader     c Via: 1.1 varnish
   12 TxHeader     c Connection: keep-alive
   12 TxHeader     c X-Cache: MISS
   12 ReqEnd       c 409391565 1259718659.088263512 1259718659.127703667 0.000059366 0.039401770 0.000038385
   12 Debug        c "herding"
</pre>
<p>ESI received significant performance enhancements in 2.0.4 and 2.0.5 so, it seemed something was incompatible.  Downgrading to 2.0.3 and using the VCL from another machine still resulted in ESI not working.</p>
<p>In this case, mod_deflate was running on the backend which was causing the issue.  However, in reading the source code, it appears that message could also occur if your ESI include wasn&#8217;t handing back properly formed XML/HTML content.  If your include doesn&#8217;t contain valid content and is only returning a small snippet, you might consider passing:</p>
<pre>
-p esi_syntax=0x1
</pre>
<p>on the command line that starts Varnish.</p>
<p>The changes in Varnish address the issue of ESI being enabled on binary content.  Since the first character isn&#8217;t an < in almost all binary files (jpg, mpg, gif) and isn't the start of most .css/.js files, varnish doesn't need to spend extra time checking those files for includes.  While you can and should selectively enable esi processing, this is just an added safeguard and a performance boost to compensate for vcl that might have an esi directive on static/binary content.</p>
<p>Since Varnish 2.0.3 now worked properly with the new machine, we upgraded to Varnish 2.0.5 which introduced a very odd issue:</p>
<pre>
[Tue Dec 01 20:58:11 2009] [error] [client 66.244.147.40] File does not exist: /gfs/www/cd/cd34.com/index.htmlt
[Tue Dec 01 20:58:13 2009] [error] [client 66.244.147.40] File does not exist: /gfs/www/cd/cd34.com/index.html7
[Tue Dec 01 20:58:24 2009] [error] [client 66.244.147.40] File does not exist: /gfs/www/cd/cd34.com/index.html\xfa
[Tue Dec 01 20:59:01 2009] [error] [client 66.244.147.40] File does not exist: /gfs/www/cd/cd34.com/index.html\xb5
[Tue Dec 01 20:59:06 2009] [error] [client 66.244.147.40] File does not exist: /gfs/www/cd/cd34.com/index.html\xe7
[Tue Dec 01 20:59:07 2009] [error] [client 66.244.147.40] File does not exist: /gfs/www/cd/cd34.com/index.html\xd4
[Tue Dec 01 20:59:08 2009] [error] [client 66.244.147.40] File does not exist: /gfs/www/cd/cd34.com/index.html\x1c</pre>
<p>This generated 404s on the piece of the page that contained the ESI include.  Downgrading to 2.0.4 fixed the issue and the issue appears to already be fixed in Trunk.  <a href="http://varnish.projects.linpro.no/ticket/585">Varnish Ticket #585</a></p>
<p>Varnish 2.0.4 and mod_deflate disabled addressed the two issues that prevented ESI from working correctly on this new installation.</p>
]]></content:encoded>
			<wfw:commentRss>http://cd34.com/blog/infrastructure/no-esi-processing-first-char-not/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Converting to a Varnish CDN with WordPress</title>
		<link>http://cd34.com/blog/scalability/converting-to-a-varnish-cdn-with-wordpress/</link>
		<comments>http://cd34.com/blog/scalability/converting-to-a-varnish-cdn-with-wordpress/#comments</comments>
		<pubDate>Sun, 11 Oct 2009 18:57:49 +0000</pubDate>
		<dc:creator>cd34</dc:creator>
				<category><![CDATA[Scalability]]></category>
		<category><![CDATA[cdn]]></category>
		<category><![CDATA[Varnish]]></category>
		<category><![CDATA[website performance]]></category>

		<guid isPermaLink="false">http://cd34.com/blog/?p=813</guid>
		<description><![CDATA[While working with Varnish I decided to try an experiment. I knew that Varnish could assist sites, but, it has never been easy to run Varnish on a shared virtual or clustered virtual host. VPS or Dedicated servers are no problem because you can do some configuration. However, in this case, I wanted to see [...]]]></description>
			<content:encoded><![CDATA[<p>While working with Varnish I decided to try an experiment.  I knew that Varnish could assist sites, but, it has never been easy to run Varnish on a shared virtual or clustered virtual host.  VPS or Dedicated servers are no problem because you can do some configuration.  However, in this case, I wanted to see if we could use Varnish to emulate a CDN, and if so, how difficult would it be for wordpress.</p>
<p>As it turns out, WordPress has a particular capability built in that handles media uploads.  In the admin, under Settings, Miscellaneous, there are two values.  One that asks where uploads should be stored.  That path is a relative path under your blog&#8217;s home directory.  The second is the URL that points to that path.  In most cases you need to leave this blank, but, we can use that to point the URL for images to use the CDN.</p>
<p>Settings, Miscellaneous</p>
<p>Store uploads in this folder: wp-content/uploads<br />
Full URL path to files: http://cd34.colocdn.com/blog/wp-content/uploads</p>
<p>Second, all of the images that have been already posted need to have their URLs modified.  Since I am a command line guy, I executed the following command in MySQL.</p>
<pre>
update wp_posts set post_content=replace(post_content,'http://cd34.com/blog/wp-content/uploads/','http://cd34.colocdn.com/blog/wp-content/uploads/');
</pre>
<p>According to the Yahoo YSlow plugin, my blog went from a 72 to a 98 out of 100 with this and a few other modifications.   The site does appear to be much snappier as well.</p>
]]></content:encoded>
			<wfw:commentRss>http://cd34.com/blog/scalability/converting-to-a-varnish-cdn-with-wordpress/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ESI Widget Issues in the Varnish, ESI, WordPress experiment</title>
		<link>http://cd34.com/blog/scalability/esi-widget-issues-in-the-varnish-esi-wordpress-experiment/</link>
		<comments>http://cd34.com/blog/scalability/esi-widget-issues-in-the-varnish-esi-wordpress-experiment/#comments</comments>
		<pubDate>Mon, 27 Jul 2009 01:41:16 +0000</pubDate>
		<dc:creator>cd34</dc:creator>
				<category><![CDATA[Scalability]]></category>
		<category><![CDATA[esi]]></category>
		<category><![CDATA[Varnish]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://cd34.com/blog/?p=729</guid>
		<description><![CDATA[The administration interface is quite simple. When the widget is installed, drag it to the Sidebar, then, drag any widgets that you want displayed to the ESI Widget Sidebar. Current issues: * When a user is logged in and comments on a post, their &#8216;login&#8217; information is left on the page if they are the [...]]]></description>
			<content:encoded><![CDATA[<p>The administration interface is quite simple.  When the widget is installed, drag it to the Sidebar, then, drag any widgets that you want displayed to the ESI Widget Sidebar.</p>
<p><a href="http://cd34.colocdn.com/blog/wp-content/uploads/2009/07/esi-widget.png"><img src="http://cd34.colocdn.com/blog/wp-content/uploads/2009/07/esi-widget-300x205.png" alt="esi-widget" title="esi-widget" width="300" height="205" class="aligncenter size-medium wp-image-730" /></a></p>
<p>Current issues:<br />
* When a user is logged in and comments on a post, their &#8216;login&#8217; information is left on the page if they are the first person to hit the page when Varnish caches the page.  If someone is logged in and visits a post page and the page hasn&#8217;t been previously cached, the html that shows their login status is cached, though, new visitors see the information, but lack the credentials.</p>
<p>Addons that don&#8217;t work properly:<br />
* Any poll application (possible solution to wrap widget in an ESI block)<br />
* Any stat application (unless they convert to a webbug tracker, this probably cannot be fixed easily)<br />
* Any advertisement/banner rotator that runs internal.  OpenX will work, as will most non-plugin<br />
* Any postcount/postviews addon<br />
* CommentLuv?<br />
* ExecPHP (will cache the output, but does work)<br />
* Manageable</p>
<p>Any plugin that does something at the time of the post or comment phase, that isn&#8217;t dependent on the logged in data should work without a problem.  If it requires a login, or uses the IP address to determine whether a visitor has performed an action, will have a problem due to the excessive caching.  For sites where the content is needed to be served quickly and there aren&#8217;t many comments, ESI Widget would work well.</p>
<p>Because of the way Varnish works, you wouldn&#8217;t necessarily have to run Varnish on the server running WordPress.  Point the DNS at the Varnish server and set the backend for the host to your WordPress server&#8217;s IP address and you can have a Varnish server across the country caching your blog.</p>
]]></content:encoded>
			<wfw:commentRss>http://cd34.com/blog/scalability/esi-widget-issues-in-the-varnish-esi-wordpress-experiment/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>WordPress, Varnish and Edge Side Includes</title>
		<link>http://cd34.com/blog/scalability/wordpress-varnish-and-edge-side-includes/</link>
		<comments>http://cd34.com/blog/scalability/wordpress-varnish-and-edge-side-includes/#comments</comments>
		<pubDate>Wed, 22 Jul 2009 19:34:29 +0000</pubDate>
		<dc:creator>cd34</dc:creator>
				<category><![CDATA[Scalability]]></category>
		<category><![CDATA[esi]]></category>
		<category><![CDATA[Varnish]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://cd34.com/blog/?p=723</guid>
		<description><![CDATA[While talking about WordPress and it&#8217;s abysmal performance in high traffic situations to a client, we started looking back at Varnish and other solutions to keep their machine responsive. Since most of the caching solutions generate a page, serve it and cache it, posts and comments tend to lag behind the cache. db-cache does work [...]]]></description>
			<content:encoded><![CDATA[<p>While talking about WordPress and it&#8217;s abysmal performance in high traffic situations to a client, we started looking back at Varnish and other solutions to keep their machine responsive.  Since most of the caching solutions generate a page, serve it and cache it, posts and comments tend to lag behind the cache.  db-cache does work around this by caching the query objects so that the pages can be generated more quickly and does expire the cache when tables are updated, but, its performance is still lacking.  Using APC&#8217;s opcode cache or memcached just seemed to add complexity to the overall solution.</p>
<p>Sites like <a href="http://perezhilton.com/">perezhilton.com</a> appear to run behind multiple servers running Varnish, use wp-cache, move the images off to a CDN which results in a 3 request per second site with an 18 second pageload.  Varnish&#8217;s cache always shows an age of 0 meaning Varnish is acting more as a load balancer than a front-end cache.</p>
<p>Caching isn&#8217;t without its downside.  Your weblogs will not represent the true traffic.  Since Varnish intercepts and serves requests before they get to the backend, those hits never hit the log. Forget pageview/postview stats (even with addons) because the addon won&#8217;t get loaded except during caching.  Certain Widgets that rely on cookies or IP addresses will need to be modified.  A workaround is to use a Text Box Widget and do an ESI include of the widget.  For this client, we needed only some of the basic widgets.  The hits in the apache logs will come from an IP of 127.0.0.1.  Adjust your <a href="/blog/infrastructure/varnish-and-apache2/">apache configuration</a> to show the X-Forwarded-For IP address in the logs.  If you truly need statistics, you&#8217;ll need to use something like Google Analytics.  Put their code outside your page elements so that waiting for that javascript to load doesn&#8217;t slow down the rendering in the browser.</p>
<p>The test site, <a href="http://varnish.cd34.com/">http://varnish.cd34.com/</a> is running Varnish 2.0.4, Apache2-mpm-prefork 2.2.11, Debian/Testing, WordPress 2.8.2.  I&#8217;ve loaded the default .xml import for testing templates so that there were posts with varied dates and construction in the site.  To replicate the client&#8217;s site, the following Widgets were added the sidebar:  Search, Archives, Categories, Pages, Recent Posts, Tag Cloud, Calendar.  Calendar isn&#8217;t in the existing site, but, since it is a very &#8216;expensive&#8217; SQL query to run, it made for a good benchmark.</p>
<p>The demo site is running on:</p>
<pre>
model name	: Intel(R) Celeron(R) CPU 2.40GHz
stepping	: 9
cpu MHz		: 2400.389
cache size	: 128 KB
</pre>
<p>with a Western Digital 80gb 7200RPM IDE drive.  Since all of the benchmarking was done on the same machine without any config changes taking place between tests, our benchmarks should represent as even a test base as we can expect.</p>
<p>Regrettably, our underpowered machine couldn&#8217;t run the benchmark with 50 concurrent tests, nor, could it run the benchmarks with the Calendar Widget enabled.  In order to get apachebench to run, we had to bump the number of requests down and reduce the number of concurrent tests.</p>
<p>These results are from Apache without Varnish.</p>
<pre>
Server Software:        Apache
Server Hostname:        varnish.cd34.com
Server Port:            80

Document Path:          /
Document Length:        43903 bytes

Concurrency Level:      10
Time taken for tests:   159.210 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      4408200 bytes
HTML transferred:       4390300 bytes
Requests per second:    0.63 [#/sec] (mean)
Time per request:       15921.022 [ms] (mean)
Time per request:       1592.102 [ms] (mean, across all concurrent requests)
Transfer rate:          27.04 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    2   7.0      0      25
Processing: 14785 15863 450.2  15841   17142
Waiting:     8209 8686 363.4   8517    9708
Total:      14785 15865 451.4  15841   17142

Percentage of the requests served within a certain time (ms)
  50%  15841
  66%  15975
  75%  16109
  80%  16153
  90%  16628
  95%  16836
  98%  17001
  99%  17142
 100%  17142 (longest request)
</pre>
<p>Normally we would have run the Varnish enabled test without the Calendar Widget, but, I felt confident enough to run the test with the widget in the sidebar.  Varnish was configured with a 12 hour cache (yes, I know, I&#8217;ll address that later) and the ESI Widget was loaded.</p>
<pre>
Server Software:        Apache
Server Hostname:        varnish.cd34.com
Server Port:            80

Document Path:          /
Document Length:        45544 bytes

Concurrency Level:      50
Time taken for tests:   18.607 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      457980000 bytes
HTML transferred:       455440000 bytes
Requests per second:    537.44 [#/sec] (mean)
Time per request:       93.034 [ms] (mean)
Time per request:       1.861 [ms] (mean, across all concurrent requests)
Transfer rate:          24036.81 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   1.8      0      42
Processing:     1   92  46.2    105     451
Waiting:        0   91  45.8    104     228
Total:          2   93  46.0    105     451

Percentage of the requests served within a certain time (ms)
  50%    105
  66%    117
  75%    123
  80%    128
  90%    142
  95%    155
  98%    171
  99%    181
 100%    451 (longest request)
</pre>
<p>As you can see, even with the aging hardware, we went from .63 requests per second to 537.44 requests per second.  </p>
<p>But, more about that 12 hour cache.  The ESI Widget uses an Edge Side Include to include the sidebar into the template.  Rather than just cache the entire page, we instruct Varnish to cache the page and include the sidebar.  As a result, when a person surfs the site and goes from the front page to a post page, the sidebar doesn&#8217;t need to be regenerated when they go to the 2nd page.  With wp-cache, it would have regenerated the sidebar Widgets and then cached the resulting page.  Obviously, that 12 hour cache is going to affect the usability of the site, so, ESI widget purges the sidebar, front page and post page any time a post is updated or deleted or commented on.  Voila, even with a long cache time, we are presented with a site that is dynamic and not delayed until wp-cache&#8217;s page cache expires.  As this widget is a concept, I&#8217;m sure a little intelligence can be added to prevent the excessive purging in some cases, but, it does handle things reasonably well.  There are some issues not currently handled with the ESI including how to handle users that are logged for comments.  With some template modifications, I think those pieces can be handled with ESI to provide a lightweight method for the authentication portion.</p>
<p>While I have seen other sites mention Varnish and other methods to keep your wordpress installation alive in high traffic, I believe this approach is a step in the right direction.  With the <a href="http://cd34.com/esi-widget/">ESI widget</a>, you can focus on your site, and let the server do the hard work.  This methodology is based on a CMS that I have contemplated writing for many years, though, using Varnish rather than static files.</p>
<p>It is a concept developed in roughly four hours including the time to write the widget and do the benchmarking.  It isn&#8217;t perfect, but does address the immediate needs of the one client.  I think we can consider this concept a success.</p>
<p>If you don&#8217;t have the ability to modify your system to run Varnish, then you would be limited to running wp-cache and db-cache.  If you can connect to a memcached server, you might consider running <a href="http://fairyfish.com/2008/03/13/enable-memcached-for-your-wordpress/">Memcached for WordPress</a> as it will make quite a difference as well.</p>
<p>This blog site, http://cd34.com/blog/ is not running behind Varnish.  To see the Varnish enabled site with ESI Widget, go to <a href="http://varnish.cd34.com/">http://varnish.cd34.com/</a></p>
<p>Software Mentioned:</p>
<p>* <a href="http://varnish.projects.linpro.no/">Varnish</a> <a href="http://varnish.projects.linpro.no/wiki/ESIfeatures">ESI</a> and <a href="http://varnish.projects.linpro.no/wiki/VCLSyntaxPurge">Purge</a> and Varnish&#8217;s suggestions for helping <a href="http://varnish.projects.linpro.no/wiki/VarnishAndWordPress">WordPress</a><br />
* <a href="http://wordpress.org/">WordPress</a><br />
* <a href="http://wordpress.org/extend/plugins/wp-cache/">wp-cache</a><br />
* <a href="http://wordpress.org/extend/plugins/db-cache/">db-cache</a></p>
<p>Sites used for reference:</p>
<p>* <a href="http://blog.darkhax.com/2009/06/08/supercharge-wordpress">Supercharge WordPress</a><br />
* <a href="http://jimmyg.org/blog/2009/ssi-memcached-nginx.html">SSI, Memcached and Nginx</a> (with mentions of a Varnish/ESI configuration)</p>
<p>Varnish configuration used for ESI-Widget:</p>
<pre>
backend default {
.host = "127.0.0.1";
.port = "81";
}

sub vcl_recv {
 if (req.request == "PURGE") {
     purge("req.url == " req.url);
 }

 if (req.url ~ "\.(png|gif|jpg|ico|jpeg|swf|css|js)$") {
    unset req.http.cookie;
  }
  if (!(req.url ~ "wp-(login|admin)")) {
    unset req.http.cookie;
  }
}

sub vcl_fetch {
   set obj.ttl = 12h;
   if (req.url ~ "\.(png|gif|jpg|ico|jpeg|swf|css|js)$") {
      set obj.ttl = 24 h;
   } else {
      esi;  /* Do ESI processing */
   }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://cd34.com/blog/scalability/wordpress-varnish-and-edge-side-includes/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Varnish and Nginx with Joomla</title>
		<link>http://cd34.com/blog/webserver/varnish-and-nginx-with-joomla/</link>
		<comments>http://cd34.com/blog/webserver/varnish-and-nginx-with-joomla/#comments</comments>
		<pubDate>Sun, 28 Jun 2009 17:01:30 +0000</pubDate>
		<dc:creator>cd34</dc:creator>
				<category><![CDATA[Webserver Software]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[joomla]]></category>
		<category><![CDATA[Nginx]]></category>
		<category><![CDATA[Varnish]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://cd34.com/blog/?p=685</guid>
		<description><![CDATA[Recently we had a client that had some performance issues with a Joomla installation. The site wasn&#8217;t getting an incredible amount of traffic, but, the traffic it was getting was just absolutely overloading the server. Since the machine hadn&#8217;t been having issues before, the first thing we did was contact the client and ask what [...]]]></description>
			<content:encoded><![CDATA[<p>Recently we had a client that had some performance issues with a Joomla installation.  The site wasn&#8217;t getting an incredible amount of traffic, but, the traffic it was getting was just absolutely overloading the server.</p>
<p>Since the machine hadn&#8217;t been having issues before, the first thing we did was contact the client and ask what had changed.  We already knew the site and database that was using most of the CPU time, but, the bandwidth graph didn&#8217;t suggest that it was traffic overrunning the server.  Our client rescued this client from another hosting company because the site was unusable in during prime time.  So, we&#8217;ve inherited a problem.  During the move, the site was upgraded from 1.0 to 1.5, so, we didn&#8217;t even have a decent baseline to revert to.</p>
<p>The stopgap solution was to move the .htaccess mod_rewrite rules into the apache configuration which helped somewhat.  We identified a few sections of the code that were getting hit really hard and wrote a mod_rewrite rule to serve those images direct from disk &#8212; bypassing Joomla serving those images through itself.  This made a large impact and at least got the site responsive enough that we could leave it online and work through the admin to figure out what had gone wrong.</p>
<p>Some of the modules that had been enabled contributed to quite a bit of the performance headache.  One chat module generated 404s every second for each person logged in to see if there were any pending messages.  Since Joomla is loaded for each 404 file, this added quite a bit of extra processing.  Another quick modification to the configuration eliminated dozens of bad requests.  At this point, the server is responsive, the client is happy and we make notes in the trouble ticket system and our internal documentation for reference.</p>
<p>Three days later the machine alerts and our load problem is back.  After all of the changes, something is still having problems.  Upon deeper inspection, we find that portions of the system dealing with the menus are being recreated each time.  There&#8217;s no built in caching, so, the decision is to try Varnish.  Varnish has worked in the past for WordPress sites that have gotten hit hard, so, we figured if we could cache the images, css and some of the static pages that don&#8217;t require authentication, we can get the server to be responsive again.</p>
<p>Apart from the basic configuration, our varnish.vcl file looked like this:</p>
<pre>
sub vcl_recv {
  if (req.http.host ~ "^(www.)?domain.com$") {
     set req.http.host = "domain.com";
  }

 if (req.url ~ "\.(png|gif|jpg|ico|jpeg|swf|css|js)$") {
    unset req.http.cookie;
  }
}

sub vcl_fetch {
 set obj.ttl = 60s;
 if (req.url ~ "\.(png|gif|jpg|ico|jpeg|swf|css|js)$") {
      set obj.ttl = 3600s;
 }
}
</pre>
<p>To get the apache logs to report the IP, you need to modify the VirtualHost config to log the <a href="/blog/infrastructure/varnish-and-apache2/">forwarded IP</a>.</p>
<p>The performance of the site after running Varnish in front of Apache was quite good.  Apache was left with handling only .php and the server is again responsive.  It runs like this for a week or more without any issues and only a slight load spike here or there.</p>
<p>However, Joomla doesn&#8217;t like the fact that every request&#8217;s REMOTE_ADDR is 127.0.0.1 and some addons stop working.  In particular an application that allows the client to upload .pdf files into a library requires a valid IP address for some reason.  Another module to add a sub-administration panel for a manager/editor also requires an IP address other than 127.0.0.1.  </p>
<p>With some reservation, we decide to switch to Nginx + FastCGI which removes the reverse proxy and should fix the IP address problems.</p>
<p>Our configuration for Nginx with Joomla:</p>
<pre>
server {
        listen 66.55.44.33:80;
	server_name  www.domain.com;
 	rewrite ^(.*) http://domain.com$1 permanent;
}
server {
        listen 66.55.44.33:80;
	server_name  domain.com;

	access_log  /var/log/nginx/domain.com-access.log;

	location / {
		root   /var/www/domain.com;
		index  index.html index.htm index.php;

           if ( !-e $request_filename ) {
             rewrite (/|\.php|\.html|\.htm|\.feed|\.pdf|\.raw|/[^.]*)$ /index.php last;
             break;
           }

	}

	error_page   500 502 503 504  /50x.html;
	location = /50x.html {
		root   /var/www/nginx-default;
	}

	location ~ \.php$ {
		fastcgi_pass   unix:/tmp/php-fastcgi.socket;
		fastcgi_index  index.php;
		fastcgi_param  SCRIPT_FILENAME  /var/www/domain.com/$fastcgi_script_name;
		include	fastcgi_params;
	}

        location = /modules/mod_oneononechat/chatfiles/ {
           if ( !-e $request_filename ) {
             return 404;
           }
        }
}
</pre>
<p>With this configuration, Joomla was handed any URL for a file that didn&#8217;t exist.  This was to allow the Search Engine Friendly (SEF) links.  The second 404 handler was to handle the oneononechat module which looks for messages destined for the logged in user.</p>
<p>With Nginx, the site is again responsive.  Load spikes occur from time to time, but, the site is stable and has a lot less trouble dealing with the load.  However, once in a while the load spikes, but, the server seems to recover pretty well.</p>
<p>However, a module called Rokmenu which was included with the template design appears to have issues.  Running php behind FastCGI sometimes gives different results than running as mod_php and it appears that Rokmenu is relying on the path being passed and doesn&#8217;t normalize it properly.  So, when the menu is generated, with SEF on or off, urls look like /index.php/index.php/index.php/components/com_docman/themes/default/images/icons/16&#215;16/pdf.png.</p>
<p>Obviously this creates a broken link and causes more 404s.  We installed a fresh Joomla on Apache, imported the data from the copy running on Nginx, and Apache with mod_php appears to work properly.  However, the performance is quite poor.</p>
<p>In order to troubleshoot, we made a list of every addon and ran through some debugging.  With apachebench, we wrote up a quick command line that could be pasted in at the ssh prompt and decided upon some metrics.  Within minutes, our first test revealed 90% of our performance issue.  Two of the addons required compatibility mode because they were written for 1.0 and hadn&#8217;t been updated.  Turning on compatibility mode on our freshly installed site resulted in 10x worse performance.  As a test, we disabled the two modules that relied on compatibility mode and turned off compatibility mode and the load dropped immensely.  We had disabled SEF early on thinking it might be the issue, but, we found the performance problem almost immediately.  Enabling other modules and subsequent tests showed marginal performance changes.  Compatibility mode was our culprit the entire time.</p>
<p>The client started a search for two modules to replace the two that required compatibility mode and disabled them temporarily while we moved the site back to Apache to fix the url issue in Rokmenu.  At this point, the site was responsive, though, pageloads with lots of images were not as quick as they had been with Nginx or Varnish.  At a later point, images and static files will be served from Nginx or Varnish, but, the site is fairly responsive and handles the load spikes reasonably well when Googlebot or another spider hits.</p>
<p>In the end the site ended up running on Apache because Varnish and Nginx had minor issues with the deployment.  Moving to Apache alternatives doesn&#8217;t always fix everything and may introduce side-effects that you cannot work around.</p>
]]></content:encoded>
			<wfw:commentRss>http://cd34.com/blog/webserver/varnish-and-nginx-with-joomla/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
