vBulletin Performance Tuning
Users love vBulletin for its easy to use and feature-rich interface; sys admins hate it because it eats system resources like nothing else. This page looks at strategies for optimising vBulletin set-ups, including eAccelerator, memcache, MySQL tuning, and lighttpd.
For the past few year I've been involved with a very busy vBulletin community (and before then a moderately busy forum). Initially I was drafted in because the machines were struggling to cope with more than around 1,000 concurrent users online (although since vBulletin regards a client as being 'on' the forums if it has made a request within the last 15 minutes, this may only translate to around 20 requests per second), but I found myself sticking around, convinced that there was still room for improvement.
First, the machine stats
Web server- AMD Athlon(tm) 64 X2 Dual Core Processor 4200+
- 2 GB RAM
- RAID 1, SCSI disks
- 2 x Dual-Core AMD Opteron(tm) Processor 2214
- 4 GB RAM
- RAID 1, SCSI disks
It's hard to believe that these two powerhouses (if you're reading this article in 5 years time, you'll no doubt laugh at that description) were struggling to serve 20 requests per second. Load (as reported by uptime) was typically 4 - 5 on the database server, and 3 - 4 on the web server. Even during relatively quiet periods, both machines were still working hard.
Here are a few quick points, most of which are common knowledge, and are just as much about general Linux performance as vBulletin itself
- Tune MySQL
There's a nice little tool called tuner-primer.sh that will help you out here. If you're using a dedicated MySQL machine, get plenty of RAM - the more tables MySQL can cache in memory, the better.
- Use mod_deflate in Apache
Actually, this is something of a double-edged sword: gzipping pages increases server load, but cuts down on bandwidth and will produce noticeably faster loading times for users on slow connections (typical vBulletin html pages do tend to be rather large). It can be implemented either via the vBulletin admin control panel or via your Apache config file. Since gzipping content will decrease the transfer time, it should also result in the Apache child spending less time on the request.
- Use a PHP opcode cacher
The main players are eAccelerator, APC, and TurkCache. Some people strongly favour one over the other, but these opinions seem to be just bigotry; I haven't found any evidence that there is a significant performance difference between them.
- noatime
Mounting some or all of your filesystems with the noatime attribute will cut down on disk writes a little. The main partition to use this on would be /var, and perhaps /home (if you keep your web tree under /home)
- IDE Disks
If your machines use IDE disks, they may well not be running at optimal performance. Take a look at the hdparm utility.
- Store your CSS in an external file
This will give clients the opportunity to cache it. On the other hand, for clients who don't have it cached, it'll be an extra request hitting your server. You'll find this option in the Vbulletin admin CP
- Use Memcache
vBulletin supports the use of memcache for datastore items. More on this below
- Disk RAIDs
If you're feeling adventurous, you may want to consider one of the RAID types which improves read/write performance by splitting data over multiple disk.
- Turn stuff off
One of the biggest strains on the system is when clients use the vBulletin search feature. Under times of heavy load, it can be good idea to turn this off (via the admin CP). Another option would be to integrate in a Google search (specifying 'site:www.mydomain.com'), although this will result in slightly stale results
Other candidates for disabling would be the list of who's online; and 'who else is browsing this thread' and 'similar threads', both of which show at the foot of thread pages. To a much lesser extent you could also disable signatures and avatars. - MySQL replication
Consider using MySQL replication to offload some of the work to a slave. Replication is far from perfect, but it's better than nothing
. - KeepAlive
I generally turn this on, but lower the timeout to 5 seconds. Some sources suggest leaving it turned off. YMMV
- Mod Expires
Encourages the client browser to cache certain files
<FilesMatch "(jpg|jpeg|gif|js|css|png)">
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
</FilesMatch>
And now a few issues which warrant a more in-depth look ....
Lighttpd, Image Servers, and Fast CGI
The overhead for Apache to service a request is relatively high, due to the typically large number of modules being used (in particular PHP). By offloading static content to a separate server, the number of requests being served by Apache should drop significantly. With clients now only making one request per page from Apache, you can disable KeepAlive.
Lighttpd is a great choice for this. It's easy to install and configure, lightweight, and very fast. Lightttpd could be run on a separate machine, or on a different interface/port of the Apache box. You could even ditch Apache completely, and serve all content off Lighttpd (which supports PHP via FastCGI), but this has a couple of drawbacks: mod_rewrite compatibility can be problematic (important if you're using vBSEO), and I'm not aware of FastCGI being any quicker than mod_php. If anything, it's probably a little slower.
Migrating all static to a separate server requires a bit of work. You'd think vBulletin would make this easy (for images at least), but even after setting the image directory locations in the admin CP (under Styles & Templates), you'll still see a lot of hits for static content in the Apache logs. I never was able to get the smilies or vBSEO images migrated over to lighttpd (for the CSS, take a look in the 'style' database table)
Is it worth it? Perhaps, but don't expect wonders. Lighttpd certainly handled the static content effortlessly, making barely an indent on system resources, but the load on Apache showed very little improvement. Considering that the overhead of serving up static content is much smaller than the load caused by executing heavy PHP code, this perhaps wasn't surprising
Memcache and MySQL
vBulletin provides partial support for memcache, as an alternative location for the datastore. The datastore is used to cache frequently used, but rarely updated information - things like forum names and permissions. The default storage method for the datastore in the filesystem (on the webserver), so by using memcache on another box, you're reducing disk I/O. Well, maybe. If your web server has plenty of spare RAM, the kernel would probably end up caching the datastore items in memory anyway. By using memcache on a different machine you'd be freeing up a bit of RAM on the web server, but also introducing some latency (although not a significant amount if the memcache server was on the same network). By this logic there wouldn't be much point in running memcache on the web server either. Note also that since the datastore isn't stored in MySQL, switching to memcache wouldn't reduce load on your database server.
Is it possible to offload any of the SQL queries to memcache? Having looked at a couple of hours worth of vBulletin-generated SQL traffic, the anwer is "not easily". I did spot one of my plugins making a rather unnecessary query each time a page was requested, but for the core vBulletin, there doesn't seem much scope for caching without a major rewrite of the code/logic involved in some of the queries.
Because write queries (INSERT, UPDATE, REPLACE) tend to reduce performance more than read queries (writing causes the table (well in the case of MyISAM tables anyway) to be temporarily locked, and there are usually indexes to be updated), cutting down on these would be seem to be a profitable area for research. Most web applications are heavily orientated to reading from the database rather than writing, but with vBulletin performing at least two writes each time a thread is viewed (one to update the thread view count, another to update the session details), it's perhaps not surprising that vBulletin tends to be quite hard on your database (although it's worth nothing that the session table is of type MEMORY)
We could come up with a scheme whereby the view count and session details are stored in memcache and periodically written to MySQL in one go, but it seems like unnecessary hard work when MySQL already provides features to mitigate this problem:
concurrent_insert = 2
low_priority_updates = 1
delay_key_write = all
Google these options if you're unfamiliar with them
If you don't have the time or technical know-how to implement these solutions, I also offer Linux consultation and specifically vbulletin performance tuning
Services
Code
- Ghoti: IRC Client for X11
- Dialog Quiz
- Apache Fingerprinting: mod_pof
- mod_miserable (Apache)
- Website Performance Testing
- Firefox Toolbar Tutorial
- SEO Postcodes (OS Commerce)
vBulletin
Data
Fun Stuff
pete@linuxbox.co.uk
Linuxbox.co.uk