Movable Type 4 and 5 Are Painfully Slow: How to Speed Things Up
I've used Movable Type since version 2.*, and I have been disappointed with the slowness exhibited by the default install of each new major version. MT3 brought the horribly configured spam lookup plugins, for example - quite capable of bringing any reasonably sized server to its knees under even a moderate level of automated spam submissions. The time taken for the lookups is too long and the processing too intensive; once the server starts to lag behind incoming automated spam, then it's a downward spiral and down goes the site. This situation hasn't improved in MT4 and 5, so I tend to implement my own, much more efficient solution to that problem and turn off the default anti-spam plugins.
In MT3, that was enough. The administrative back-end was acceptably responsive even after I had accumulated thousands of posts. My general rule of thumb for casual or inside users - such as administrators, customer support, and so forth - is that no page should ever take more than a second to start delivering content to the requesting browser. If it takes more than three to four seconds for a page to at least mostly render for these users, then you have usability issues. The standards for customers and readers on the front end of a site should be much more stringent. For a site to feel snappy and fast on a broadband connection, a page has to be mostly rendered and there in front of the user within a half-second or so of clicking the link to go there. There may be widgets, additional Javascript files, AJAX calls, and other similar things still loading at that point, but the user sees the page and is made happy the perception that it loaded rapidly.
Under these terms, MT3 was snappy once the spam lookup issue was dealt with. When I use the MT4 or 5 administrative interface, however, I am not a happy user. It is painfully slow - and yet, conceptually and from a user's perspective, it is doing exactly the same things as it did before. For a user with an established site, this is like being smacked on the nose with a newspaper: here you are upgrading to the shiny new version, and every page takes seconds to appear. The MT4 and 5 back end feel sticky and slightly slow on a new installation, but for an existing site with hundreds or thousands of posts it can take 10-15 seconds to load template or entry management pages in the back end - and that's with a dedicated server and MySQL query caching turned on.
So what can be done? Here's the list.
Things that Should Already Be In Place
You should already be running on a dedicated server that allows you greater control than a shared server does. If you're up for the minor level of technical know-how required to get Movable Type running on an old-style web hosting provider, then you may as well try running a server on Amazon's EC2. It's roughly the same cost in dollars and cents, and you gain a far greater ability to control your hosting environment.
If you are using dynamic publishing or publishing static PHP pages in Movable Type, then you should have a PHP accelerator such as APC installed on your server. Setting it up is easy, and it speeds up PHP execution times considerably.
Additionally, you should be using MySQL as the database, and the query cache should be turned on. There are plenty of resources out there to explain how to check and how to switch it on if it isn't already. It's just a few extra lines in the MySQL configuration file, most environments will set it on by default, and it makes a large difference.
When running Movable Type 4.35 on a small EC2 Fedora Core 14 instance with the MySQL query cache turned on, and 7,000 posts and 30 templates of varying sorts in the database, it takes 10-15 seconds to load the Manage Entries or Blog Templates page. That is brutal and unusable. In MT3.*, with the same number of posts and templates, the equivalent pages had fast loading times.
Deep Six the Spam Plugins
It is only helpful to remove the default spam settings if you have comments turned off, or have implemented a better way of eliminating the spam problem. Otherwise it's probably better for most small blogs to suffer slow comments and the risk of the server falling over than for admins to be forced to clean up after the spambots. Some experimentation may find a middle ground between the extremes of many spam lookups that slow the site down or perhaps even overload the server and no spam protection leading to lots of spam comments.
Assuming you want to do this, here is how. Under the "Tools" pulldown in the Moveable Type administration navigation is an option for "Plugins". Navigate there and change the following settings in the SpamLookup plugin set, selecting each plugin in turn to open its information panel:
- Lookups: Click on "Settings", switch all of the radio buttons to "Off", clear the text area, and then save.
- Links: Click on "Settings", uncheck all of the checkboxes, and save.
- Keyword Filter: clear the text areas and then save.
In the past I've found that the biggest issue is the Lookups module. If it is completely turned off, then it's usually fine to leave a modest number of link checks, keywords, or whitelisted IP addresses in the other plugins - they don't start to be a real issue until the number of items in their configuration settings become large.
Install Memcached
Memcached is a cache server that holds items in memory for fast-as-possible retrieval. If you've been following along at home and set up Movable Type on an EC2 Fedora Core server as outlined in one of my previous posts, then installation of the basics is as follows:
yum install memcached php-pecl-memcache
You will also need to install one of the Perl modules for memcached, such as this one through the CPAN tool:
cpan >install Cache::Memcached::Fast
You should edit the /etc/init.d/memcached file to boost the memory allocated to memcached as the default is far too low for most production uses. These configuration directives are near the top of the file already - you're just setting the values. This gives it 512M of memory, allows 20,480 concurrent connections, and limits it to listening to connections from the local machine only. This should be more than enough for most single-server Movable Type installations.
PORT=11211 USER=memcached MAXCONN=20480 CACHESIZE=512 OPTIONS="-l 127.0.0.1"
Now make sure that memcached is set to run automatically, and picks up the changed configuration:
chkconfig --add memcached chkconfig --level 2345 memcached on /etc/init.d/memcached restart
Lastly, you have to configure Movable Type to use memcached. This is simple enough - just add a few lines to your mt-config.cgi file.
MemcachedDriver Cache::Memcached::Fast MemcachedNamespace my_ MemcachedServers 127.0.0.1:11211
The MemcachedNamespace directive is not strictly necessary if you're only going to be using memcached with Movable Type and no other applications - but always specifying a namespace is a good habit to get into. That value is added to the name of cached items, ensuring that they won't collide with those of other applications.
On my EC2 Fedora Code server, running memcached in this configuration reduces my load times for the slowest pages from 10-15 seconds to 6-7 seconds. This is still frustrating and next to unusable, but it is a move in the right direction.
One thing that is worth noting for those folk unused to caching systems in their blogs: if you make changes directly to the database, they may not appear in the Movable Type back end until you clear the caches by restarting memcached. Further, if you don't clear the caches, your changes may get overwritten in the database by the older cached version. Not knowing this can lead to all sorts of issues and confusion.
Install mod_fcgid
mod_fcgid is a faster mod_cgi for Apache 2, and will considerably speed up execution of the *.cgi files in a Movable Type installation. (It can also be configured to take the place of APC as an accelerator for PHP code execution, but I don't touch on that topic here). Again, if you're using an EC2 server as outlined previously, just run the following commands to install mod_fcgid and the other necessary items such as fcgi-perl.
yum install fcgi fcgi-perl mod_fcgid /etc/init.d/httpd restart
Once installed you can drop an .htaccess file in your cgi-bin directory (probably /var/www/cgi-bin unless you've changed the default webroot layout), and add the following instructions. They tell Apache to use mod_fcgid instead of mod_cgi for the *.cgi files in your Movable Type installation.
<FilesMatch "^.*.cgi$"> SetHandler fcgid-script </FilesMatch>
You may have issues with pages timing out for a site with many entries, especially when publishing a new entry. I found that adding the following lines to the default configuration file at /etc/httpd/conf.d/fcgid.conf solved this issue:
IPCConnectTimeout 20 IPCCommTimeout 300
Finally, you may have to add this line to your mt-config.cgi file:
LaunchBackgroundTasks 0
I saw no issues running Movable Type without the LaunchBackgroundTasks directive, but running under mod_fastcgi, a different option for speeding up cgi file execution in Apache, does require it. You lose nothing of importance by adding the directive, so this is perhaps a case of better safe than sorry.
Using mod_fcgid in conjunction with memcached saw the time to load the Manage Entries page on my multi-thousand entry MT4 instance cut down to an average of 2.5 seconds or so. This is still slow by any objective measure, but it is a large improvement over the initial state of affairs, and brings it into the realm of the usable.
Optimize the Dashboard
The Movable Type dashboard includes two types of news in a box on the right, as well as a flash display of comment and post statistics. Provided you're prepared to keep up with announcements of important security upgrades on your own time, and don't care too much about pretty displays of how much you and your audience are posting, then you can disable all of these items with suitable directives in mt-config.cgi:
LearningNewsURL disable NewsboxURL disable StatsCachePublishing Off StatsCacheTTL 0
This change makes the dashboard for my MT4.35 instance load in 1.2 to 1.5 seconds rather than 4 to 5 seconds. It has no effect on any of the other back-end pages, of course, but this is a worthwhile gain since I view the dashboard every time I log in. Note that if you're running under mod_fcgid, then you'll have to restart Apache if you want to see these and other, similar configuration changes reflected immediately.
/etc/init.d/httpd restart
A Note on How I'm Measuring Load Times
I use the Net panel in the Firebug plugin for Firefox to measure page load times; it provides a good benchmark for comparing improvements, and it helps you gain a sense of whether a page appears slow because (a) the first file is taking forever to be generated and passed over the network, or (b) there are twenty other important files (Javascript, CSS, necessary background images, and so forth) that must be loaded immediately and so slow down rendering to a crawl. Or both.
The load times I give in this post are only for the initial page itself, not the following CSS, Javascript, and whatever else might be going on. The secondary loads shouldn't be too important to the apparent page load speed for Movable Type, at least once you've loaded each file once and given it a chance to cache. It's a different story if those files are kicking off heavy Javascript processing and DOM-manipulation tasks as soon as they load, of course. Which leads us to the next item in the list of things to try.
Disable Codepress
Codepress is involved in editing templates in the Movable Type back end; depending on your browser version and machine, disabling it can speed things up considerably. Unfortunately, it didn't make that much of a difference for me, and even if it did, it would only speed up template editing - nothing else. If you want to give it a try, here's a good guide.
In essence, you want to edit /mt-static/mt.js by replacing the following function assignments - I've snipped the contents for length, but this block of code starts at line 2368 in MT4.35:
eventIframeLoaded: function( event ) { ... }, // obj can by a textarea id or a string (code) edit: function( obj, language ) { ... },
The new code looks like this:
eventIframeLoaded: function( event ) { this.editor = this.iframe.contentWindow.CodePress; /* ugly bug in codepress, if setCode is called with nothing then it breaks */ if ( this.textarea.value != '' ) this.editor.setCode( this.textarea.value ); this.toggleOff(); }, edit: function( obj, language ) { if ( obj ) { var el = DOM.getElement( obj ); this.textarea.value = ( el ) ? el.value : obj; } if ( !this.textarea.disabled ) return; this.textarea.disabled = false; },
Those trailing commas after the braces are important - skip them at your peril. Also, don't forget to keep a backup of the original mt.js file just in case you decide that you prefer things the way they were before.