owen

A thread on the support forum recently crossed my radar, wherein help is sought for a sick WordPress. It seems that the popularity of some blogs, especially those with high number of commenters, is causing issues on those servers.

Having recently gone through some operations to optimize the user experience on my blog, I have some personal involvement in trying to optimize my own site. I have a lot of control over my own server (I run this site on a VPS) so many of these changes were easy to implement. Some of them would still work if I was using shared hosting, and it still may be worthwhile to know these things when talking to a shared host if you can make any performance suggestions.

You can use these tips to keep your site running ultra-smooth, because keeping your server online is one of the more important aspects of running a web site.

The first question you may ask is: Can WordPress handle high traffic sites? Yes. Of course it can. Check out the list of high-profile WordPress users. So you know it can do it - how does it do it?

The number one thing you can probably do to improve your performance with WordPress is to install a page cache. A page cache renders a whole page (or most of it) to a file, and then when visitors request that page again, it is served from the file instead of executing the PHP and MySQL queries. This reduces the overall load on the server and can have a significant impact on your performance.

You can find an excellent page cache plugin for WordPress in WP-Cache 2. WP-Cache is installed as an advanced cache system in WordPress, which means it takes advantage of certain special hooks that only one plugin can use at a time. The installation of such a system is a little more complicated than a standard plugin, but really only amounts to adding a couple of extra files to your wp-content directory and telling WP-Cache to make some changes to your WordPress installation. You may need to set write permissions on certain files and directories to make this work.

When installed, WP-Cache will write static copies of the pages of your site into a directory on the server, and upon the second request, the static version will be served. When you write a new post, the cache is cleaned out and regenerated on each request, like normal. The same thing happens when vistors write comments. The nice thing about WP-Cache is that you need not have root access to your blog server in order to use it - just install the files in your site and run through the configuration as written. There are a couple of drawbacks, however.

There are some reported issues on Windows servers. I can’t verify these, but they might have been fixed in the last revision of the code. Also, if youre site is being hammered by comments, then the cache won’t stay on disk long enough to provide a real benefit. There is a hack you can make to prevent WP-Cache from cleaning the cache when a new comment is added, but then any new comments won’t appear on the page until after the time-based cache clearing.

Your site will also not properly produce content that changes on every page load unless you use WP-Cache’s special comment tags to mark that code. I haven’t had much success with those tags, but maybe you will.

When I first started hosting on this new server, it would go down pretty regularly. The SMS on my cell was receiving “Server Down!” messages every couple of hours. As it turns out, my server was not properly configured for the job it was trying to perform.

On thing that I needed to watch was the amount of swap space that was being used by the server. On my VPS, I was assigned 128MB of RAM and 256MB of swap space. With the configuration as it was, this was not enough. When traffic to the server was on teh uptake, more RAM was required to provide the database services that WordPress needs. Since there wasn’t enough RAM, MySQL would use swap space for memory, and that would slow down the whole system. In most cases, dipping too deeply into the swap would cause a cascade effect that would take down the server.

If you have permission, you can fiddle with your Apache and MySQL settings so that they consume less memory. I am not an exper at this, so you will want to do more research of your own. Primarily, you’ll want the server to only run as many threads as it can handle. Since the number of threads is loosely tied to the amount of memory used, changing the number of threads used could reduce your load.

Alternatively, add more RAM. This was the solution that worked for me. I doubled the capacity of RAM on my VPS, and suddenly the swap area became mostly untouched. My server has been steadily up ever since the change.

Another performance boost I was able to manage on my own system was installing an opcode cache.

When PHP (the script language in which WordPress is written) runs, the PHP interpreter first compiles the code into opcodes that the machine can directly execute. This process takes a bit of time, especially if the code footprint is very large, and over time it can add up since the opcodes are not stored, but recompiled every time a script is executed. WordPress happens to have a pretty decent sized code footprint, so this overhead can get pretty demanding on a smaller server.

To improve the response speed, an opcode cache can store the compiled opcodes. When a request is made for a page that has its compiled opcodes cached, and the page’s script hasn’t changed, then the pre-compiled opcodes are used instead of recompiling the script. This saves a ton of time.

On my server, heavy traffic times would take my server load up to about 3. After I installed APC my load has only gone above 1 when I’ve done something stupid on the server like create a rewrite rule with an infinite loop.

APC has a couple of caveats, of course. Using it with WP-Cache could be tricky. Mark has some things to say about using WP-Cache with APC that might interest you. I decided that I liked the full dynamic availability of my site more than the downsides of WP-Cache. Also, I was seeing more benefit from APC, anyway - my site was noticeably faster. And APC will affect other PHP applications positively as well. So it was all upsides for me with APC.

With the general methods out of the way, let’s look at a specific thing that we can change about WordPress to get a good performance boost.

MySQL provides a Query Cache that does the same thing for query results that APC does for compiled opcodes and WP-Cache does for whole rendered pages. The Query Cache stores the results of a query temporarily so that frequently used queries that have data that doesn’t change can be accessed more quickly.

To accomodate the MySQL Query Cache, the query has to be cacheable. Primarily, the query must be the same when you execute it the second time as when you executed it the first time in order to see any performance gains. Sadly, WordPress 2.0 doesn’t accomodate this very well.

Usually when any page is viewed in WordPress, the main Posts query is executed to determine at least what the blog should display. Depending on the request made by the browser, this query often returns the posts that populate the main section of your blog. This query is probably (hopefully) the most intense query that WordPress executes on your site.

The problem is that WordPress is constantly checking to see if any new posts are available for publication. If you future date a post (set the date for a date in the future so that WordPress holds off publishing the post until that time) this is the part of the post that excludes the posts from the future. So WordPress essentially asks, “Give me all posts that were posted before May 1, 2006 at 5PM.” And it changes that time every time it makes a new request.

Maybe you can see the problem. Because WordPress changes that query every minute, the query is different every time and the Query Cache doesn’t keep the cached data around. MySQL can’t benefit from any cached data for the most intense query that WordPress performs!

So, you need a plugin. Mark Jaquith (he’s got a lot of credit on this post, since a lot of the info I used came from research he did) wrote a plugin that allows the time to remain the same for longer periods. Unfortunately, it doesn’t look like it supports future posting very well, so if you do that frequently you might need to tweak Mark’s plugin. Check out his wp-hackers email that describes his process of discovery in more detail and even provides his MySQL configuration file, which could be useful for tuning your own MySQL installation.

Note that future versions of WordPress will no longer suffer from this ailment, since posts in WordPress 2.1 have a “status” that includes “future” which automatically excludes them from the main post query. I digress.

One of the big, big wasters of server energy are comment reporting plugins. These are the class of functions that tell you the last five commenters on each of the last five commented-on posts. These comment reporting plugins are the worst offenders for sucking up processor time and memory.

Primarily, these plugins stink because they often aren’t cached properly. If you’re using one of these plugins without using WP-Cache or some other page-caching system, you’ll probably at least want to cache just the comment report if possible. The report requires several complicated queries to function. If you’re including this in your sidebar with each page view, then you’re needlessly overburdening your server. Try installing WP-Cache, and if that doesn’t help, chuck that plugin entirely or get someone to code a cache into the one you use.

Finally, if you’re doing media-rich applications and serving large files, you might consider using two servers or a two-tiered approach to serving your files.

A lightweight http server (or even a hosted service for photos and videos) could serve your large files, freeing up the memory-hungry power processes of Apache for serving your dynamic pages. There’s no reason to reserve a ton of memory for features of Apache that you’re not going to use when you’re just serving plain files.

The most difficult part of setting up your server for such a thing may be installing both services on your server box. There are some suggestions online (see item 5, Separate Server for Static and Dynamic Content).

You can always host large files in an alternate location and map a subdomain to that location. For example, your blog might be at www.example.com, but your photos could be at photos.example.com. Not only might this save your server a little energy, but could also save you some money, since services exist that serve only files (no script) that are cheaper for storage than what you might need to pay to host those same files on your blog’s server. And then you don’t have to pay for huge photo storage at your blog’s host.

I know that A Small Orange offers non-scripting storage-only hosting, and I’ve found their service to be pretty reliable. You probably can find cheaper storage hosts out there, but remember that cheap does not equal good service.

As a postscript, I should note that no matter how intensely you optimize your server and the code, you’re still going to have trouble running WordPress on a server that is severely overloaded (in a shared environment) or doesn’t have enough resources to run your site. In that case, maybe it’s time to consider an upgrade or switching plans to a host that can provide more bang for your bank.

That about covers what I have to offer on the issue of WordPress performance, and it certainly isn’t the Omega guide. This would supercede most issues on my Codex page, which really needs revised to speak to using WordPress for specific applications (podcasting, video blogging, etc.) and provide benchmarks, like how much traffic can WordPress handle when hosted in certain conditions or what kind of service plan would best work for a site with a certain amount of traffic. Some of the stuff on there about network congestion is just silly.

If you have any performance tips (or corrections), please leave them in the comments so everyone can benefit.