<?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>Library &#38; Information Services &#187; performance</title>
	<atom:link href="http://sites.middlebury.edu/lis/tag/performance/feed/" rel="self" type="application/rss+xml" />
	<link>http://sites.middlebury.edu/lis</link>
	<description>We Bring Knowledge to You</description>
	<lastBuildDate>Fri, 24 May 2013 14:57:22 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Weekly Web Development Round-up October 10-21, 2011</title>
		<link>http://sites.middlebury.edu/lis/2011/10/21/weekly-web-development-round-up-october-10-21-2011/</link>
		<comments>http://sites.middlebury.edu/lis/2011/10/21/weekly-web-development-round-up-october-10-21-2011/#comments</comments>
		<pubDate>Fri, 21 Oct 2011 21:00:28 +0000</pubDate>
		<dc:creator>Matthew La France</dc:creator>
				<category><![CDATA[LIS Staff Interest]]></category>
		<category><![CDATA[Campus Map]]></category>
		<category><![CDATA[Drupal]]></category>
		<category><![CDATA[middmedia]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[Web Application Development]]></category>

		<guid isPermaLink="false">http://sites.middlebury.edu/lis/?p=26964</guid>
		<description><![CDATA[To give our colleagues a better idea of what’s changed in our web applications each week, we’ll be preparing this quick list for publication each Friday. Not all of the details of each change are included below, but we’ll be &#8230; <a href="http://sites.middlebury.edu/lis/2011/10/21/weekly-web-development-round-up-october-10-21-2011/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>To give our colleagues a better idea of what’s changed in our web applications each week, we’ll be preparing this quick list for publication each Friday. Not all of the details of each change are included below, but we’ll be happy to answer any questions you might have in the comments.<br />
<span id="more-26964"></span></p>
<p><strong>Main site and mobile site speed improvements<br />
</strong></p>
<p><strong></strong>Our <a href="http://www.middlebury.edu/">main website</a> and <a href="http://m.middlebury.edu/">mobile website</a> make fabulous use of data feeds from blogs, calendars, Twitter, and other sources to provide up-to-date news and information to users of the sites. Some pages in the main site have as many as 3 feeds in the carousel at the bottom of the page and another 2 feeds in sidebars. The mobile site displays 7 feeds on its home page for desktop users.</p>
<p>Unfortunately displaying all of these feeds on the site was causing performance problems for users when those feeds needed to be refreshed.  Even if the blog system returns each feed in under a second, that time adds up and was making users wait for 10 seconds or more for some pages to load.</p>
<p>We are happy to announce that we have now resolved this issue by piping all of our data-feed access through a system we call <a href="https://github.com/middlebury/FetchProxy">FetchProxy</a>. FetchProxy sits between Drupal and the source of the data feeds and keeps a fresh copy of the feed always available so that Drupal never has to sit and wait for feeds. Pages that once took more than 10 seconds to load, now load in 1-2 seconds. You can <a href="https://github.com/middlebury/FetchProxy/blob/master/README.md">read more about FetchProxy on Github</a>.</p>
<p><strong>Campus Map</strong></p>
<p>We&#8217;ve updated the interface for our <a href="http://www.middlebury.edu/about/campus/campusmap/interactive">Campus Map</a> with the help of designers in College Communications. New features include a list of locations with quick icons to help you find special locations, a search interface, an improved photo gallery, and more special filters which allow you to scope the locations on the map. For instance, you can get a <a href="http://www.middlebury.edu/about/campus/campusmap/interactive?field_location_depts_value_many_to_one=All&amp;term_node_tid_depth%5B%5D=44048">map of all the locations on campus with Wireless</a>.</p>
<p><strong>MiddMedia</strong></p>
<p>A permalink is now available for each file in MiddMedia. You can access it for a particular video you click the “Embed Code &amp; URLs” next to any video you are browsing in MiddMedia and click on the “Click here to view and/or download this file.”. Alternately you can construct this URL like this “http://middmedia.middlebury.edu/middmedia/view/dir/[the directory where the file is located]/file/[the name of the file with its extension]</p>
<p>Example: http://middmedia.middlebury.edu/middmedia/view/dir/lafrance/file/go.mp4</p>
<p>This is useful if you want to reference your video without embedding it elsewhere.</p>
]]></content:encoded>
			<wfw:commentRss>http://sites.middlebury.edu/lis/2011/10/21/weekly-web-development-round-up-october-10-21-2011/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Website Performance: Pressflow, Varnish, Oh-My!</title>
		<link>http://sites.middlebury.edu/lis/2010/05/17/website-performance-pressflow-varnish-oh-my/</link>
		<comments>http://sites.middlebury.edu/lis/2010/05/17/website-performance-pressflow-varnish-oh-my/#comments</comments>
		<pubDate>Mon, 17 May 2010 18:33:00 +0000</pubDate>
		<dc:creator>Adam Franco</dc:creator>
				<category><![CDATA[LIS Staff Interest]]></category>
		<category><![CDATA[Central Systems & Network Services]]></category>
		<category><![CDATA[Drupal]]></category>
		<category><![CDATA[Enterprise Applications]]></category>
		<category><![CDATA[Middlebury]]></category>
		<category><![CDATA[MIIS]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[User Services]]></category>
		<category><![CDATA[Web Application Development]]></category>
		<category><![CDATA[website]]></category>

		<guid isPermaLink="false">http://sites.middlebury.edu/lis/?p=23170</guid>
		<description><![CDATA[Executive summary: We&#8217;ve migrated from core Drupal-6 to Pressflow, a back-port of Drupal-7 performance features. Using Pressflow allows us to cache anonymous web-requests (about 77% of our traffic) for 5-minutes and return them right from memory. While this vastly improves &#8230; <a href="http://sites.middlebury.edu/lis/2010/05/17/website-performance-pressflow-varnish-oh-my/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<h4>Executive summary:</h4>
<p>We&#8217;ve migrated from core Drupal-6 to Pressflow, a back-port of Drupal-7 performance features. Using Pressflow allows us to cache anonymous web-requests (about 77% of our traffic) for 5-minutes and return them right from memory. While this vastly improves the amount of traffic we can handle as well as the speed of anonymous page-loads it does mean that anonymous users may not see new versions of content for at most 5 minutes. Traffic for logged-in users will always continue to flow directly through to Drupal/Pressflow and will always be up-to-the-instant-fresh. </p>
<p>Read on for more details about what has change and where we are at with regard to website performance.</p>
<p><span id="more-23170"></span></p>
<hr />
<h4>Background</h4>
<p>When we first launched the new Drupal website back in February we went through some growing pains that necessitated code fixes (<a href="http://sites.middlebury.edu/lis/2010/02/08/website-improvements-1/">Round 1</a> and <a href="http://sites.middlebury.edu/lis/2010/02/12/website-improvements-3-better-performance/">Round 2</a>) as well as the addition of an extra web-server host and database changes (<a href="http://sites.middlebury.edu/lis/2010/02/18/website-improvements-4-previews/">Round 2</a>). </p>
<p>These improvements brought our site up to acceptable performance levels, but I was concerned that we might run into performance problems if the college ended up <a href="http://www.nytimes.com/2007/02/21/education/21wikipedia.html">in the news</a> and thousands of people suddenly went to view our site. </p>
<p>At DrupalCon a few weeks ago <a href="http://sites.middlebury.edu/lis/2010/04/21/drupalcon-2010-day0-performance/">I attended a Drupal Performance Workshop</a> where I learned a number of techniques that can be used to scale Drupal sites to be able to handle internet-scale traffic &#8212; not Facebook or Google-level traffic, but that of <a href="https://wiki.fourkitchens.com/display/PF/Who+uses+Pressflow">The Grammys, Economist, or World Bank</a>. </p>
<p>Since before the launch of the new site we were already making use of <a href="http://en.wikipedia.org/wiki/PHP_accelerator">optcode-caching via APC</a> to speed code execution and were doing data caching with <a href="http://memcached.org/">Memcache</a> to reduce the load on the database. This system-architecture is far more performant than a baseline setup, but we still could only handle a sustained average of 20 requests each second before the web-host started becoming fully loaded. While this double our normal average of 10-requests per second, it is not nearly enough headroom to feel safe from traffic spikes.</p>
<div id="attachment_23209" class="wp-caption aligncenter" style="width: 610px"><a href="http://sites.middlebury.edu/lis/files/2010/05/Page-Caching-Drupal-Memcache.png"><img src="http://sites.middlebury.edu/lis/files/2010/05/Page-Caching-Drupal-Memcache.png" alt="Diagram of the execution flow through the web-host using normal Drupal page caching." title="Page Caching - Drupal and Memcache" width="600" class="size-full wp-image-23209" /></a><p class="wp-caption-text">Request flow through our Drupal web-host prior to May 13th; using normal Drupal page-caching stored in Memcache. Click for full-size.</p></div>
<h4>Switching to Pressflow</h4>
<p>Last week we switched from the standard Drupal-6.16 to <a href="http://pressflow.org/">Pressflow-6.16.77</a>, a version of Drupal 6 that has had a number of the performance-related improvements from Drupal-7 back-ported to it. Code changes in Pressflow such as dropping legacy PHP4 support and using only MySQL enable Pressflow execute about 27% faster than Drupal, a useful improvement but not enough to make a huge difference were we to get double or triple our normal traffic. </p>
<p>For us, the most important difference between Pressflow and Drupal-6 is that sessions are &#8216;lazily&#8217; created. This means that rather than creating a new &#8216;session&#8217; on the server to hold user-specific information on the first page each user sees on the website, Pressflow instead only creates the session when the user hits a page (such as the login page) that actually has user-specific data to store. This change makes it very easy to differentiate between anonymous requests (no session cookies) and authenticated requests (that have session cookies) and enables the next change, Varnish page caching.</p>
<h4>Varnish Page Caching</h4>
<p>Varnish is a <a href="http://en.wikipedia.org/wiki/Reverse_proxy">reverse-proxy server</a> that runs on our web hosts and can return pages and images from its own in-memory cache so that they don&#8217;t have to execute in Drupal/Pressflow every single time. The default rule in Varnish is that if there are any cookies in the request, then the request is for a particular user and should be transparently passed through to the back-end (Drupal/Pressflow). If there are no cookies in the request, then Varnish assumes correctly that it is an anonymous  request and tries to respond from its cache without bothering the back-end.</p>
<div id="attachment_23218" class="wp-caption aligncenter" style="width: 610px"><a href="http://sites.middlebury.edu/lis/files/2010/05/Page-Caching-Varnish.png"><img src="http://sites.middlebury.edu/lis/files/2010/05/Page-Caching-Varnish.png" alt="Request flow through our Drupal/Pressflow web-host after May 13th; using the Varnish proxy-server for caching. Click for full-size." title="Page Caching - Varnish" width="600" class="size-full wp-image-23218" /></a><p class="wp-caption-text">Request flow through our Drupal/Pressflow web-host after May 13th; using the Varnish proxy-server for caching. Click for full-size.</p></div>
<p>Since about 77% of our traffic is non-authenticated traffic, Varnish only sends about 30% of the total requests through to Apache/PHP/Drupal: all authenticated requests and anonymous requests where the cache hasn&#8217;t been refreshed in the past 5 minutes. Were we to have a large spike in anonymous traffic, virtually all of this increase would be served directly from Varnish&#8217;s cache, preventing any load-increase on Apache/PHP/Drupal or the back-end MySQL database. In my tests against our home-page varnish was able to easily handle more than 10,000 requests each second with the limiting factor being network speed rather than Varnish.</p>
<div id="attachment_23249" class="wp-caption aligncenter" style="width: 610px"><a href="http://sites.middlebury.edu/lis/files/2010/05/Varnish-histogram.png"><img src="http://sites.middlebury.edu/lis/files/2010/05/Varnish-histogram.png" alt="A histogram of requests to the website. Y-axis is the number of requests, X-axis is the time to return requests, &#39;|&#39; requests were handled by Varnish&#39;s cache and &#39;#&#39; were passed through to Drupal. The majority of our requests are being handled quickly by Varnish while a smaller portion are being passed-through to Drupal." title="Varnish-histogram" width="600" class="size-full wp-image-23249" /></a><p class="wp-caption-text">A histogram of requests to the website. Y-axis is the number of requests, X-axis is the time to return requests, '|' requests were handled by Varnish's cache and '#' were passed through to Drupal. The majority of our requests are being handled quickly by Varnish while a smaller portion are being passed-through to Drupal.</p></div>
<h4>MySQL Improvements</h4>
<p>During the scheduled downtime this past Sunday, Mark updated our MySQL server and installed the <a href="http://www.innodb.com/products/innodb_plugin/">InnoBase InnoDB Plugin</a>, a high-performance storage engine for MySQL that can provide twice the performance of the built-in InnoDB engine in MySQL for the types of queries done by Drupal.</p>
<p>Last week Mark and I also went through our database configuration and verified that the important parameters were tuned correctly.</p>
<p>As the MySQL database is not currently the bottleneck that limits our site performance these improvements will likely have a minor (though wide-spread) effect. Were our authenticated traffic to further increase (due to more people editing for instance) these improvements will be more important.</p>
<h4>Where We Are Now</h4>
<p>At this point the website should be able to handle at least 20,000 requests/second of anonymous users (10,000 on each of two web-hosts) at the same time that it is handling up to 40 requests/second from authenticated users (20 on each of two web-hosts). </p>
<p>While it is impossible to accurately translate these request rates into the number of users we can support visiting the site, a very rough estimation would be to divide the number of requests/second by 10 (a guess at the average number of requests needed for each page view) to get a number of page-views that can be handled each second. <a href='#note1'>(1)</a></p>
<p>In addition to how many requests can be handled, how fast the requests are returned is also important. Our current response times for un-cached pages usually falls between 0.5 seconds and 2 seconds. If pages take much longer than 2 seconds, the site can &#8220;feel slow&#8221;. For anonymous pages cached in Varnish response times range from 0.001 seconds to 0.07 seconds, much faster than Apache/Drupal can do and more than fast enough for anything we need.</p>
<p>The last performance metric that we are concerned with is about the time it takes for the page to be usable by the viewer. Even if they receive all of the files for a page in only 0.02 seconds, it may still take their browser several seconds to parse these files, execute javascript code, and turn them into a displayable graphic. Due to these factors, my testing has shown that most pages on our site take between 1 and 3 seconds for users to feel that our pages are loaded. For authenticated users, this stretches to 2-4 seconds.</p>
<p>Finally please be aware that, anonymous users see pages that may be cached for up to 5 minutes. While this is fine for the vast majority of our content, there are a few cases where we may need to have the content shown be up-to-the-second fresh. We will address these few special cases over the coming months.</p>
<h4>Future Performance Directions</h4>
<p>Now that we have our caching system in place our system architecture is relatively complete for our current performance needs. While we may do a bit of tuning on various server parameters, our focus now shifts to PHP and Javascript code optimization to further improve server-side and client-side performance respectively. </p>
<p>One big impact on javascript performance (and hence perceived load-time) is that we currently have to include two separate versions of the <a href="http://jquery.com/">jQuery Javascript Library</a> due to different parts of the site relying on different versions. Phasing out the older version will reduce almost by half the amount of code that the browser has to parse.</p>
<h4>Additional Notes</h4>
<p><a name="note1"></a><strong>(1)</strong> As people browse the site their browser needs to load the main HTML page as well as make separate requests for Javascript files, style-sheet (CSS) files, and every image. After these have been loaded the first time, [most] browsers will cache these files locally and only request them again after 5 minutes or if the user clears their browser cache. CSS files and images that haven&#8217;t been seen before will need to be loaded as new pages are browsed to.  For example, the first time someone loads the <a href="http://www.middlebury.edu/athletics/">Athletics</a> page, it requires about 40 requests to the server for a variety of files. A subsequent click on the <a href="http://www.middlebury.edu/arts/">Arts</a> page would require an additional 13 requests, while a click back to the <a href="http://www.middlebury.edu/athletics/">Athletics</a> page would require on 1 additional request as the images would still be cached in the browser. </p>
]]></content:encoded>
			<wfw:commentRss>http://sites.middlebury.edu/lis/2010/05/17/website-performance-pressflow-varnish-oh-my/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DrupalCon 2010 Trip Report &#8211; Day 3</title>
		<link>http://sites.middlebury.edu/lis/2010/04/26/drupalcon-2010-day3/</link>
		<comments>http://sites.middlebury.edu/lis/2010/04/26/drupalcon-2010-day3/#comments</comments>
		<pubDate>Mon, 26 Apr 2010 14:07:50 +0000</pubDate>
		<dc:creator>Ian McBride</dc:creator>
				<category><![CDATA[LIS Staff Interest]]></category>
		<category><![CDATA[Areas and Workgroups]]></category>
		<category><![CDATA[Conference Reports]]></category>
		<category><![CDATA[conferences]]></category>
		<category><![CDATA[Drupal]]></category>
		<category><![CDATA[Enterprise Applications]]></category>
		<category><![CDATA[Nutch]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[RDF]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[Semantic Web]]></category>
		<category><![CDATA[solr]]></category>
		<category><![CDATA[Web Application Development]]></category>

		<guid isPermaLink="false">http://sites.middlebury.edu/lis/?p=22892</guid>
		<description><![CDATA[After attending a conference, I usually think, &#8220;Wow, we&#8217;re so far ahead here at Middlebury!&#8221; Not this time! DrupalCon was incredibly helpful in demonstrating all of the ways we can improve our site with better performance, better search, better content, &#8230; <a href="http://sites.middlebury.edu/lis/2010/04/26/drupalcon-2010-day3/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>After attending a conference, I usually think, &#8220;Wow, we&#8217;re so far ahead here at Middlebury!&#8221; Not this time! DrupalCon was incredibly helpful in demonstrating all of the ways we can improve our site with better performance, better search, better content, and better code. I&#8217;m also really excited about the upcoming release of Drupal 7 and both confident we can move our site onto this new version and eager to use all the new features.</p>
<p>Here are the highlights from the last day:<span id="more-22892"></span></p>
<ul>
<li>All of <a href="http://sf2010.drupal.org/conference/sessions">the conference sessions are now available to watch online</a>.</li>
<li>Librarians might be particularly interested in <a href="http://sf2010.drupal.org/conference/sessions/shh-drupal-powered-library-site">Shh! This is a (Drupal-powered) Library Website</a>, though I suggest skipping the first 27 minutes as those presenters cover topics not relevant to our setup.</li>
<li>The tech team at the White House is contributing back to the community the work they&#8217;ve done to make the Drupal perform better under high load and the NY State Senate is working to provide an out-of-the-box Drupal configuration for State governments. Whatever your personal politics, I hope you&#8217;ll agree that it&#8217;s neat to see the government using free resources and then improving them for the rest of the community.</li>
<li>The Node Access module in Drupal 7 includes a feature that will allow us to remove the &#8220;core hack&#8221; from Monster Menus, which will allow it to be an accepted module in the Drupal community and help it get adopted by other Drupal users.</li>
<li>Drupal 7 allows you to build form fields with &#8220;states&#8221;. For instance, a group of field for taking credit card information could have the state &#8220;expanded&#8221; if a checkbox labeled &#8220;pay online&#8221; is checked. This will help us build easier to use interfaces.</li>
<li>We can combine the <a href="http://lucene.apache.org/solr/">Apache Solr</a> project with the <a href="http://lucene.apache.org/nutch">Apache Nutch</a> project to create a local search crawler and indexer, like the Google Search Appliance, but with a lot more room for us to expand and a lot less configuration to provide <a href="http://facetedsearch.davidlesieur.com/faceted_search">faceted search</a>.</li>
<li>The next database abstraction layer for Drupal 7 uses PHP&#8217;s PDO library, which will support MySQL, postgres, SQLite, MSSQL, and Oracle as database back ends. There are also huge improvements in database replication, allowing us to have a true &#8220;hot standby&#8221; server, support for prepared statements, transactions, a query builder, and a lot of other stuff that our Banner programmers take for granted.</li>
<li>While still in its very early stages, there are a number of Drupal projects working on support for various NoSQL platforms, including MongoDB. These systems promise to improve performance by removing some of the technical limitations imposed by storing information in &#8220;tables&#8221; in databases. Not quite ready for wide use in production, but expect to see a lot more of this in a few years.</li>
<li>Much of the HTML code printed by code modules in Drupal 7 will use RDF markup. This provides additional information about the elements on the page that are intended for the browser and search engines to use. For example, the text &#8220;Price: $9.99&#8243; won&#8217;t get picked up by a search engine as a price, but &#8220;Price: <code>$&lt;span class="field-item even" property="product:listPrice"&gt;9.99&lt;/span&gt;</code>&#8221; allows the search engine to display that information as a price next to the page listing.</li>
</ul>
<p>Read on for more notes on each of these points.</p>
<p><!--more--></p>
<h3>Node Access in Drupal 7 (Notes by Ian)</h3>
<p><a href="http://sf2010.drupal.org/conference/sessions/node-access-drupal-7">Watch the presentation</a></p>
<p>In the current version of Drupal, changes to the user permissions to access a piece of content can only truly happen through the core of the software, meaning that our custom modules to Drupal are limited in what they can do to control access. With Drupal 7, we get a new hook, hook_node_access(), that allows any module to define CRUD permissions (Create, Read, Update, Delete), on any node and for any other module to then modify those permissions. I&#8217;ll back up for a second and explain that when a Drupal page loads, the software core gets first crack at doing whatever it needs to do and then all of the modules get a change to modify it, using hooks, in an order defined by the site administrator. Any module that implements hook_node_access() will run that function on all nodes and, if it is the last module to implement that function, will have the final say on who can do what with a node.</p>
<p>This is very important for us, because this is exactly the type of thing Monster Menus needs to do. MM introduces &#8220;pages&#8221; to Drupal, which the core of the software doesn&#8217;t know anything about. In MM, all nodes are assigned to a page and then permissions are set on the page. So in Drupal 7, MM will be able to run hook_node_access() to tell the system, &#8220;these nodes being loaded right now belong to this page and here&#8217;s who has each of these permissions on them&#8221;. Right now this is all done with a large amount of heavy lifting that taxes the system. The hope is that, by opening up access to these functions, Drupal 7 will improve site performance and let us do more.</p>
<p>There are some costs to doing this. The query builder in Drupal 7 doesn&#8217;t know that things need to be run through the node access logic, so it is a requirement that you add a tag of &#8220;node_access&#8221; to any query that is run against the node table. Failure to do this is a security violation in Drupal and will get your module flagged by the security team. This is a bit silly, since we need to do this for every query against the node table, why doesn&#8217;t the system just add it for us? The presenter said that a patch to Drupal to provide that would likely get approved, but the design philosophy behind the decision is that it&#8217;s, &#8220;not the API&#8217;s responsibility to tell you how to code correctly&#8221;. The new node_access hook also only works on single nodes, you can&#8217;t run a whole list of them through it, so there is a chance of poor performance for pages that need to load a bunch of nodes and need to execute these functions on all of them.</p>
<h3>Instant Dynamic Forms with #states (Notes by Ian)</h3>
<p><a href="http://sf2010.drupal.org/conference/sessions/instant-dynamic-forms-states">Watch the presentation</a></p>
<p>Drupal 7 adds the &#8220;#states&#8221; form API element which allows us to define behavior for a form specific to a current &#8220;state&#8221; of the form. For instance, a field could become required depending on whether a checkbox elsewhere on the form is checked or unchecked. You can <a href="http://d7.drupalexamples.info/form_example/states">try out an example of this behavior</a>.</p>
<p>Naturally, these examples are really trivial, but this is a framework with a lot of power in it. The other nice thing about using #states to build forms in Drupal 7 is that all of the JavaScript is created by the forms engine. This makes forms easier to build and less prone to bugs. I hate having to debug JavaScript, so I&#8217;m happy to hand off that responsibility to the software.</p>
<p>One potential issue is that the form is rebuilt by the server after every action by the user. If you click a checkbox, the server gets a notice, rebuilds the entire form, and sends it back to you. This makes the form more secure: only the server can decide what elements are part of the form, but potentially very resource intensive. Our Page Settings form already takes a while to load the first time. If it has to load multiple times in between user actions I can see people starting to get frustrated. We&#8217;ll have to wait and see.</p>
<h3>Web Crawling and Search with Nutch and Solr (Notes by Ian)</h3>
<p><a href="http://sf2010.drupal.org/conference/sessions/how-build-jobs-aggregation-search-engine-nutch-apache-solr-and-views-3-about">How to build a Jobs Aggregation Search Engine with Nutch, Apache Solr and Views 3 in about an hour</a></p>
<div id="attachment_22899" class="wp-caption aligncenter" style="width: 510px"><a href="http://sites.middlebury.edu/lis/files/2010/04/Solr-Nutch_Search_Architecture.png"><img class="size-full wp-image-22899" title="Solr-Nutch_Search_Architecture" src="http://sites.middlebury.edu/lis/files/2010/04/Solr-Nutch_Search_Architecture.png" alt="Solr-Nutch Architecture (Diagram by Adam)" width="500" /></a><p class="wp-caption-text">Solr-Nutch Architecture (Diagram by Adam)</p></div>
<p>Apache Solr is a search engine and Apache nutch is a crawler that can be used to populate that search engine. Using these tools together, we can build a local search repository that indexes all the same sites our Google Search Appliance does, but allows us to extend the search experience by adding facets and localized search. Both Solr and Nutch are also available in cloud configurations, meaning that we can offload the processing of these actions if they grow beyond what our local staff and servers can manage.</p>
<p>The biggest advantage of using Solr as a search engine with Drupal is that the two are closely integrated through the <a href="http://drupal.org/project/apachesolr">Apache Solr Drupal module</a>. Rather than use a search crawler that goes through the site, Drupal will periodically send off highly structured data to the Solr search repository, including all of the metadata associated with a node. For instance, we have a node in the site for every staff job descriptions with fields listed for department, position number, and level. A crawler just sees these as plain text, but Drupal sends each field off to Solr as part of the index. So when you search for &#8220;Programmer&#8221; you can filter by level, department, or location. Though it isn&#8217;t mentioned anywhere in the documentation, I learned that these filters are automatically set up for any content type field that is a radio button, checkbox, or drop down menu. For other fields, we can build our own filters.</p>
<p>It&#8217;s true that these services emulate what we already have with our Google Search Appliance. We&#8217;ll be meeting later this week to discuss our search strategy and determine whether it will be beneficial to set up this infrastructure, extend how we use the GSA, both, or neither. I&#8217;m glad I attended this session before trying to make that decision!</p>
<h3>Databases: the Next Generation (Notes by Ian)</h3>
<p><a href="http://sf2010.drupal.org/conference/sessions/databases-next-generation">Watch the presentation</a></p>
<p>The big announcement in this session was that the database abstraction layer in Drupal 7 will use PHP&#8217;s PDO libraries, meaning that Drupal 7 can run with MySQL, postgres, SQLite, MSSQL or Oracle as a database backend. Currently, it can run using MySQL or (with some reservations) postgres. Microsoft also announced at the conference that they have supplied a beta drive for MSSQL to the PHP project and are engaged in improving the driver to access their database, rather than relying on the volunteer community to provide it.</p>
<p>This opens up a lot of features that I bet our Banner programmers would be surprised to learn we didn&#8217;t have in Drupal (since these have been common in the PL/SQL environment forever):</p>
<ul>
<li>Prepared statements</li>
<li>Transactions</li>
<li>Named placeholders for variables in statements</li>
<li>Merge and truncate</li>
<li>Return a result set as any object type</li>
<li>Multi-insert statements</li>
<li>Full master/slave replication support for multiple failover servers</li>
</ul>
<p>The importance of that last point can&#8217;t be overstated. Right now, if our primary database server fails, we can switch over to our backup server. However, MySQL servers can only replicate data in one way, so we can&#8217;t allow you to modify data on the backup server because it will never be written back to the primary server. However, the database abstraction layer is so basic right now that we can&#8217;t differentiate between a query that is writing to the database and one that&#8217;s just reading from the database in our code. So, we solved this by denying our web server permission to execute write statements on the backup server. When the failover occurs, you can try to write data, but you&#8217;ll get a warning and our error log will start piling up the errors too. This isn&#8217;t ideal and the added functionality in Drupal 7&#8242;s database abstraction layer solves this problem.</p>
<p>This was also one of those sessions where I was impressed by the amount of knowledge in the room. A fairly esoteric question was asked about prepared statements: where are they prepared? In the code? By the database? It turns out that, in PHP, the answer is different for each database driver. The MySQL driver prepares the query before passing it off to the database, so it&#8217;s done in C code on the web server. The Oracle driver passes the query to the database to prepare, then fetches the parameters from the web server. The Oracle preparation is more precise and less error prone since the database is doing it, but introduces latency since another request is needed to the web server to get the parameter information.</p>
<h3>MongoDB &#8211; Humongous Drupal (Notes by Ian)</h3>
<p><a href="http://sf2010.drupal.org/conference/sessions/mongodb-humongous-drupal">Watch the presentation</a></p>
<p><a href="http://www.mongodb.org/">MongoDB</a> is a key-value index database that can be used to improve performance for very, very high volume sites. The claim is that storing information on the filesystem using key-value pairs allows it to be access more quickly than storing information in tables, like RDBMS (MySQL, MSSQL, Oracle) do. Since there is no schema, data can be added easily (just append) and indexed on any key. Since it&#8217;s just files, the database can be replicated easily as well. Here&#8217;s an example of a few rows from a MongoDB file:</p>
<pre>{<span>"name"</span> : <span>"mongo"</span> , <span>"_id"</span> : ObjectId(<span>"497cf60751712cf7758fbdbb"</span>)}
{<span>"x"</span> : 3 , <span>"_id"</span> : ObjectId(<span>"497cf61651712cf7758fbdbc"</span>)}
{<span>"x"</span> : 4 , <span>"j"</span> : 1 , <span>"_id"</span> : ObjectId(<span>"497cf87151712cf7758fbdbd"</span>)}
{<span>"x"</span> : 4 , <span>"j"</span> : 2 , <span>"_id"</span> : ObjectId(<span>"497cf87151712cf7758fbdbe"</span>)}</pre>
<p>The same structure in an RDBMS might use three separate tables, one to store x, one for j, and one for name. Depending on how x and j are related, there might be a fourth table involved. This is important for Drupal because all the fields used by content types are stored in separate tables. For our job descriptions, we have a table to store the title of the description, another to store the department for the description, another to store the level for the description and so on. When the node is printed to the page, all of these tables need to be access by joining them together, which can become a resource intensive task. Under high load, this causes problems, particularly in MySQL.</p>
<p>The work being done on MongoDB for Drupal is still in its very early stages and probably won&#8217;t be ready for widespread use for over a year. Right now they have some of the query functions used in Drupal core implemented, but not all of them and not necessarily through the database abstraction layer, meaning that any module using MongoDB with Drupal needs to be rewritten at this time. For those few sites that have enough visitors to warrant using this, that might be an acceptable trade off, but not for us. &#8220;NoSQL&#8221; systems like MongoDB will be one of the most interesting developments in web software this decade. We&#8217;ll have to see how this develops in parallel with the traditional RDBMS systems.</p>
<h3>Scalable infrastructure for Whitehouse.gov (Notes by Adam)</h3>
<p>Frank Febrarro of Phase 2 technology, part of the team that developed Whitehouse.gov, gave a session titled <a href="http://sf2010.drupal.org/conference/sessions/providing-scalable-infrastructure-whitehousegov">Providing a Scalable Infrastructure for Whitehouse.gov</a>. This session talked about all of the techniques used to ensure both that the site would be able to handle the huge visitor load, as well as be extremely secure from defacement and highly available.</p>
<ul>
<li>Infrastructure build-out took a team of the same size and the same amount of time as the development work.</li>
<li>Tested by turning off servers and services to see how the system reacts.</li>
<li>They found that targeting read and write queries to different database servers with MySQL_Proxy worked great in development, but fell down under their heavy load testing. They ended up having to patch Drupal core (by running PressFlow) to enable retargeting from within Drupal.</li>
<li>They run two complete data centers, a production data-center and a disaster-recovery data-center. The disaster recovery data-center also includes development environments and complete data replication so that they can continue operations with a complete loss of the production data center.</li>
<li>The hosts are all RHEL and provisioned with Puppet (60+ servers). They use SELinux to lock down access to files and executables within the hosts and use AIDE to report on unauthorized file access. Puppet allows each type of server to be spawned exactly the same (ensuring that new servers are in audit compliance just like existing ones).</li>
<li>The Akamai content delivery network is used for three services: Site Accelerator (a reverse proxy for handling page caching), Net Storage for file serving, and Live Streaming. 90% of all traffic hits Akamai and doesn&#8217;t need to go through Drupal. Since they have under a hundred authenticated Admin and Editor users (no public users can log in) they have very low authenticated traffic and don&#8217;t need to scale authenticated access much.</li>
<li>PHP code and user files are all served from a NAS system mounted via NFS.</li>
<li>They run Memcache with the consistent hashing strategy that allows a node to fail and cache to still operate.</li>
<li>The database backend is MySQL Enterprise with InnoDB. The also use a RAM-based filesystem for temp-tables to improve the performance of file-sort operations.</li>
</ul>
<dl>
<dt>Database Replication:</dt>
<dd>They use both Master-Master replication as well as Master-Slave replication. The second master is a hot-swap of the primary master as well as handles all of the slave replication. This means that the primary master only has to handle some reads, all writes, and replicating to a single &#8216;slave&#8217;.</dd>
<dt>Monitoring</dt>
<dd>MySQL enterprise monitor, Nagios for infrastructure monitoring, Cacti for graphs.</dd>
<dt>Replication Monitoring:</dt>
<dd>Constantly writing to a file with a pool of active slaves, allowing PHP to switch where reads are going. Custom scripts remove slaves when replication fails, rebuild them, then move them back into the pool once they are repaired.</dd>
<dt>Environmental sync:</dt>
<dd>Changes to servers and files automatically sync to Akami as well as the disaster recovery site.</dd>
<dt>Hardware scaling:</dt>
<dd>Goal is to quickly scale horizontally. Puppet handles the provisioning details, new web servers and database slaves can be brought online in minutes.</dd>
<dt>Data scaling: </dt>
<dd>They receive 15,000+ Webform submissions every day. These are stored outside of the main Drupal database to make site restores much quick by not requiring the rebuilding of many GBs of data.</dd>
<dt>Development Process: </dt>
<dd>They create a branch per issue, then a branch per release &#8212; merging in completed issue fixes.</dd>
<dt>Release Process: </dt>
<dd>They run a full-featured staging environment that allows testing of all aspects of changes.</dd>
<dd>For the published data like Whitehouse visitors, data files are imported using the Drush command line tools.</dd>
</dl>
<h3>RDF in Drupal 7 (Notes by Adam)</h3>
<p>Exclamations of how the &#8220;<a href="http://en.wikipedia.org/wiki/Semantic_Web">semantic web</a>&#8221; is going to revolutionize the internet as we know it have been voiced for a decade. The session <a href="http://sf2010.drupal.org/conference/sessions/story-rdf-drupal7-and-what-it-means-web-large">&#8220;The story of RDF in Drupal 7 and what it means for the Web at large&#8221;</a> described how in the upcoming Drupal 7 semantic tags will be added to Drupal markup as HTML attributes (<a href="http://en.wikipedia.org/wiki/RDFa">RDFa</a>). These attributes will make it easier for machines to understand the meaning and context of words on the page. One example of this used in the description is of a bit of price text having the an RDF attribute <code>&lt;div class="field-item even" property="product:listPrice"&gt;9.99&lt;/div&gt;</code> enabling search engines to display that price in their results rather than just assuming that it is unstructured text. In my view, this change won&#8217;t be earth shattering for quite a while (another few years), but will make some things we currently do now (such as search and data re-purposing) work better without as much server-side programming. In the long run there may be bigger implications.</p>
<p>The second neat thing was a mention of an <a href="http://drupal.org/project/rdfproxy">RDF Proxy Module</a> that will enable Drupal to fetch and display content from remote sites via RDF searching. This is sort of like displaying RSS feeds on steroids. The big difference is that rather than being limited to an Feed that has one or more items of similar format, the RDF queries can grab individual or multiple data-elements from a remote page or many remote pages. Even better, these queries can be run against the normal human-consumable web pages rather than requiring a separate RSS or XML feed to be generated on the source site.</p>
<p>This session also showed the use of <a href="http://sites.middlebury.edu/lis/">Sindice Inspector</a>, a tool for viewing, navigating, and graphing the RDF data in a web page. They showed a cool example of a blog post with graphs linking the RDF data on multiple sites, but I wasn&#8217;t able to find a URL with such complex RDF data.</p>
]]></content:encoded>
			<wfw:commentRss>http://sites.middlebury.edu/lis/2010/04/26/drupalcon-2010-day3/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>DrupalCon 2010 Trip Report &#8211; Day 0</title>
		<link>http://sites.middlebury.edu/lis/2010/04/21/drupalcon-2010-day0-performance/</link>
		<comments>http://sites.middlebury.edu/lis/2010/04/21/drupalcon-2010-day0-performance/#comments</comments>
		<pubDate>Wed, 21 Apr 2010 08:22:38 +0000</pubDate>
		<dc:creator>Adam Franco</dc:creator>
				<category><![CDATA[LIS Staff Interest]]></category>
		<category><![CDATA[Areas and Workgroups]]></category>
		<category><![CDATA[caching]]></category>
		<category><![CDATA[Conference Reports]]></category>
		<category><![CDATA[conferences]]></category>
		<category><![CDATA[Drupal]]></category>
		<category><![CDATA[Enterprise Applications]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[Web Application Development]]></category>

		<guid isPermaLink="false">http://sites.middlebury.edu/lis/?p=22861</guid>
		<description><![CDATA[Here is an overview and some notes from the Drupal Scalability and Performance Workshop I attended before the start of the DrupalCon conference that Ian and I are attending in San Francisco. As the title suggests, this workshop was focused &#8230; <a href="http://sites.middlebury.edu/lis/2010/04/21/drupalcon-2010-day0-performance/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Here is an overview and some notes from the <a href="http://sf2010.drupal.org/conference/pre-conference-trainings/drupal-scalability-and-performance-workshop">Drupal Scalability and Performance Workshop</a> I attended before the start of the DrupalCon conference that Ian and I are attending in San Francisco. As the title suggests, this workshop was focused on making Drupal (and web-applications in general) run fast. Really fast. I hope to apply the techniques learned in this workshop over the next weeks and months to make our sites run fast enough to handle any traffic load that might be thrown at them, even were an event to occur that would send major public traffic to our sites.</p>
<p><em>Read on if you are interested in the performance and scalability of Drupal, MySQL databases, and web applications in general.</em></p>
<p><span id="more-22861"></span></p>
<p>After a two-hour overview of the various areas of application, server, database, and proxy configurations that can affect performance we spent much of the rest of the day deploying a basic Drupal installation on virtual machines and walking through the entirety of the discussed performance optimizations, running benchmarks at each stage.</p>
<h3>Benchmarking</h3>
<p>While many tools such as <a href="http://jakarta.apache.org/jmeter/">Apache JMeter</a> can be used to build complex test plans that more accurately simulate loads seen in production, the <a href="http://httpd.apache.org/docs/2.0/programs/ab.html">Apache Bench (<code>ab</code>)</a> tool is a very simple way to benchmark the effect a change has on the performance of a single page. This is critical for determining if a change that has performance implications increases or decreases the speed at which pages are served. Apache Bench can be run from the command line with arguments for the number of requests to make, the number of concurrent requests to run at the same time, and the URL of the page to test:</p>
<pre>ab -n 1000 -c 50 http://host.example.edu/drupal/</pre>
<p>As well, a cookie (copied from an authenticated session) can be used to measure the responsiveness for pages that require authentication:</p>
<pre>ab -n 1000 -c 50 -C 'SESSd1e57edd95f34cfedb49c219e55ddf26=f35afe5e50caf15cba72c448afe72f81'  http://host.example.edu/drupal/some/page/</pre>
<h3>Code Profiling</h3>
<p>Once slow pages are identified, the location of performance issues can be determined by code profiling.</p>
<p>The FourKitchens wiki has <a href="https://wiki.fourkitchens.com/display/PF/Code+profiling+and+load+testing+Pressflow+on+CentOS+5">a good page</a> on how to profile Drupal code using XDebugToolkit and generate traces like the one below that help us developers to easily see where in the PHP code most of the processing time is spent.<br />
<div id="attachment_22869" class="wp-caption aligncenter" style="width: 310px"><a href="http://sites.middlebury.edu/lis/files/2010/04/cg-1.png"><img src="http://sites.middlebury.edu/lis/files/2010/04/cg-1-300x250.png" alt="A code trace weighted by execution time." title="xdebug trace" width="300" height="250" class="size-medium wp-image-22869" /></a><p class="wp-caption-text">A code trace weighted by execution time.</p></div></p>
<h3>MySQL Database Tuning</h3>
<p>The first step in setting up a high-performing MySQL database server is to swap out the built-in InnoDB engine with the <a href="http://www.innodb.com/wp/products/innodb_plugin/">plug-in version</a> from InnoBase (a subsidiary of Oracle). The InnoDB Plugin performs two or more times faster than the built-in InnoDB engine and is a fully compatible drop-in replacement. (Packages of the InnoDB Plugin for RHEL are available as part of the <a href='http://blog.famillecollet.com/pages/Config-en'>Remi YUM Repository</a>). Other InnoDB engine implementations such as <a href="https://launchpad.net/percona-xtradb">XtraDB from Percona</a> add additional performance improvements and configuration abilities, but the InnoBase InnoDB plugin is itself a big win.</p>
<p>With the InnoDB Plugin installed, next up is tuning the configuration parameters of the database. In general, all of the configuration tuning is done to ensure that appropriate caches, data, indexes, and table-metadata all remain resident in system RAM rather than requiring the database server to load these from hard disk. For details, see my example <a href='http://sites.middlebury.edu/lis/files/2010/04/my.cnf_.txt'>my.cnf </a> configuration file with notes as well as these step-by-step <a href="https://wiki.fourkitchens.com/display/PF/MySQL+configuration+and+tuning">tuning instructions from Four Kitchens</a>.</p>
<p>One side note that came up in the workshop was the performance differences between the MyISAM engine and the InnoDB engine. The &#8216;conventional wisdom&#8217; is that the older, simpler, MyISAM engine is higher performing for read queries than the InnoDB engine since it has less overhead taken up by ensuring data integrity. What was discussed in the workshop is that this supposed edge of the MyISAM engine only actually applies in a tiny subset of cases: where the server is severely memory constrained (such as on small slice of a shared host) or where the data set is massive and cannot be reasonably held in RAM (such as some multi-terabyte reporting databases). Because the MyISAM engine is designed as a file-based engine and the InnoDB engine is designed to hold data in memory, it was said that in cases where much or all of the data and indexes can be held in memory the InnoDB engine will always out-perform the MyISAM engine &#8212; even on simple select statements.</p>
<h3>Opcode Caching</h3>
<p>One performance improvement we already have in place for most of our web applications is to cache compiled PHP &#8216;opcodes&#8217; in RAM using the <a href="http://php.net/manual/en/book.apc.php">PHP APC extension</a> so that PHP scripts don&#8217;t need to be read off of the hard disk and compiled each page load.</p>
<p>Having APC enabled also allows very lightweight page-load statistics monitoring to be done with the Drupal Devel-Performance module, giving use summary statistics of the actual page-load times that users are getting from the production webservers.</p>
<p><em>Note: APC &lt;= 3.0 has an issue where the entire cache is cleared if it becomes full.</em></p>
<h3>Memcache</h3>
<p>The second performance improvement that we are already using is to use <a href="http://memcached.org/">Memcache</a> and the <a href="http://drupal.org/project/memcache">Drupal Memcache Module</a> to allow cached data to live in memory on the the webservers and not require queries the database server. Since the [MySQL] database server is generally the performance bottle neck and is hard to scale horizontally, even moving simple cache look-ups off of it can be a big performance improvement.</p>
<p><em>Note: Use the dev version of the Drupal Memcache Module so that one large memory bin (possibly spanning multiple machines) can be used rather than having to separate cache &#8216;tables&#8217; into multiple bins. The &#8216;stable&#8217; version of the module didn&#8217;t prefix the cache &#8216;tables&#8217;, resulting in excess clearing of cached data when unrelated data was cleared.</em></p>
<h3>PressFlow</h3>
<p><a href="http://pressflow.org/">PressFlow</a> is a Drupal distribution designed for high performance that has several differences from the main release of Drupal:</p>
<ul>
<li>Legacy support for PHP4 is dropped, allowing better performance in PHP5</li>
<li>Support for databases other than MySQL is dropped, allowing PressFlow to take advantage of higher-performance features than the lowest-common denominator would support</li>
<li>Rather than being created on the first web request, sessions are only created when data is stored in them. This &#8220;Lazy Session Creation&#8221; allows proxies like Squid and Varnish to differentiate between anonymous and authenticated traffic and only cache content for anonymous users</li>
<li>It allows splitting of read-queries to read-only slave databases, taking load off of the read-write master database.</li>
</ul>
<p>With these changes noted, PressFlow is a drop-in replacement for Drupal Core.<br />
<a href="http://fourkitchens.com/pressflow-makes-drupal-scale">See this page for more information on PressFlow.</a></p>
<h3>Varnish</h3>
<p><a href="http://varnish-cache.org/">Varnish</a> is a reverse proxy* that can be run on the web-host in front of the Apache webserver to cache content destined for anonymous users and return that cached data to other anonymous users from memory, without the cached requests ever having to be processed by Drupal code.</p>
<p>* A &#8220;Forward Proxy&#8221; is a proxy-server that usually sits close to the clients (often at an ISP) and caches requests coming from those clients to the broader internet. Varnish, as a &#8220;Reverse Proxy&#8221; sits close to the webserver (even on the same machine) and caches requests coming into it from the broader internet.</p>
<p>Since anonymous traffic is often orders of magnitude greater than authenticated traffic, serving pages for anonymous users from a cache before PHP code is even touched can result in huge speed improvements for anonymous users. The cache performance can be as high as ~5,000-10,000 pages per second compared to a max of about 100-300 pages per second for executed Drupal code, even with its internal page caching turned on. Authenticated users get a speed boost as well since the total traffic being processed through the Drupal PHP code drops.</p>
<p><a href="https://wiki.fourkitchens.com/display/PF/Configure+Varnish+for+Pressflow">This wiki page</a> has a configuration file for Varnish working with Drupal. The basic idea is that the presence of Google Analytics cookies is ignored for the purpose of determining if the traffic is authenticated or anonymous. If any other cookies are set, then Varnish assumes that the traffic is for an authenticated user and it passes the request through to Apache/Drupal and doesn&#8217;t cache the result when sending it back to the client. If no additional cookies are present, then a result from cache is returned if found.</p>
<p>One downside with varnish is that caching is based on Expire headers, meaning that anonymous users may see slightly stale content (often set to be refreshed every 5 minutes or so). The Drupal Varnish module includes options that allow much longer Expire times to be set and pages to be actively cleared from cache when they are changed, but at the cost of additional complexity. Were active cache clearing desired, this would likely involve a lot of testing to ensure that all caches are appropriately cleared in all cases of content change.</p>
<h3>Hudson</h3>
<p><a href="http://wiki.hudson-ci.org/display/HUDSON/Meet+Hudson">Hudson</a> is a continuous integration tool that can be used as a kind of cron-on-steroids, allowing nice features like statistics of cron-run execution times and emails sent to admins if cron-runs have failures. It also prevents cron-runs from stepping on each other if previous executions haven&#8217;t completed yet.</p>
<h3>Other modules and notes related to performance</h3>
<ul>
<li><a href="https://launchpad.net/mv">Materialized Views</a></li>
<li>Boost &#8211; Writes out Drupal pages as static HTML. Varnish is a vastly better solution, but not possible on some web hosting providers (not an issue for Middlebury).</li>
<li>Panels &#8211; Can allow caching of blocks and other content pieces even for authenticated users</li>
<li>Views &#8211; Can cache results, just be careful for views where there may be node-access restrictions</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://sites.middlebury.edu/lis/2010/04/21/drupalcon-2010-day0-performance/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
