Recently two of my articles reached the Digg frontpage at the same day. My web
server isn’t state of the art and it had to handle gigantic amounts of
traffic. But still it served pages to visitors swiftly thanks to a lot of
optimizations. This is how you can prevent heavy traffic from killing your
About this article
There are many things you can do to speed up your website. This article
focuses on practical things that I used, without any spending money on
additional hardware or commercial software.
In this article I assume that you’re already familiar with system
administration and hosting / creating websites. In examples I use Ubuntu, but
if you use another distro, just make some minor adjustments (like package
management) and it should work as well.
Beware, if you don’t know what you’re doing you could seriously mess up your
Cache PHP output
Every time a request hits your server, PHP has to do a lot of processing,
all of your code has to be compiled & executed for every single visit. Even
though the outcome of all this processing is identical for both visitor 21600
and 21601. So why not save the flat HTML generated for visitor 21600, and
serve that to 21601 as well? This will relieve resources of your web server
and database server because less PHP often means less database queries.
Now you could write such a system yourself but there’s a neat package in
PEAR called Cache_Lite that can do this for us, benefits:
it saves us the time of inventing the wheel
it’s been thoroughly tested
it’s easy to implement
it’s got some cool features like lifetime, read/write control, etc.
Installing is like taking candy from a baby. On Ubuntu I would:
With the PHP caching mechanism in place, we take away a lot of stress
from your CPU & RAM, but not from your disk. This can be solved by creating a
storage device with your system’s RAM, like this:
mkdir -p /var/www/www.mysite.com/ramdrive
mount -t tmpfs -o size=500M,mode=0744 tmpfs
Now the directory /var/www/www.mysite.com/ramdrive is not located on your
disk, but in your system’s memory. And that’s about 30 times faster : ) So why
not store your PHP cache files in this directory? You could even copy all
static files (images, css, js) to this device to minimize disk IO. Two
things to remember:
All files in your ramdrive are lost on reboot, so create a script to
restore files from disk to RAM
The ramdrive itself is lost on reboot, but you can add an entry to
/etc/fstab to prevent that
For example. I count the number of visits for every singe article. But instead
of updating a counter for an article every visit (which involves row locking
and a WHERE statement), I use simple and relativity performance-cheap SQL
INSERTS into a separate table.
The gathered data is processed every 5 minutes by a separate PHP script that’s
automatically run by my server. It counts the hits per article, then deletes
the gathered data and updates the grand totals in a separate field in my
article table. So finally accessing the hit count of an article takes no extra
processing time or heavy queries.
If you use MySQL, the default storage engine for tables is MyISAM. That
not ideal for a high traffic website because MyISAM uses table level locking,
which means during an UPDATE, nobody can access any other record of the same
table. It puts everyone on hold!
InnoDB however, uses Row level locking. Row level locking ensures that during
an UPDATE, nobody can access that particular row, until the locking
transaction issues a COMMIT.
phpmyadmin allows you to easily change the table type in the Operations tab.
Though it never caused me any problems, it’s wise to first create a backup of
the table you’re going to ALTER.
Use optimal field types
Wherever you can, make integer fields as small as possible. Nnot by changing
the length but by changing it’s actual integer type. The length is only used
So if you don’t need negative numbers in a column, always make a field
unsigned. That way you can store maximum values with minimum space (bytes).
Also make sure foreign keys have matching field types, and place indexes on
them. This will greatly speedup queries.
In phpmyadmin there’s a link Propose Table Structure. Take a look sometime,
it will try to tell you what fields can be optimized for your specific db
Never select more fields than strictly necessary. Sometimes when you’re lazy
you might do a:
even though a
would suffice. Normally that’s OK, but not when performance is your no.1
Tweak the MySQL config
Furthermore there are quite some things you can do to the my.cnf file, but
I’ll save that for another article as it’s a bit out of this article’s scope.
Save some bandwidth
Save some sockets first
Small optimizations make for big bandwidth savings when volumes are high. If
traffic is a big issue, or you really need that extra server capacity, you
could throw all CSS code into one big .css file. Do this with the JS code as
well. This will save you some Apache sockets that other visitors can use
for their requests. It will also give you better compression rations, should
I know what your thinking. No, don’t throw all the CSS and JS in the main
page. You still really want this separation to:
make use of the visitor’s browser cache. Once they’ve got your CSS, it
won’t be downloaded again
not pollute your HTML with that stuff
And now some bandwidth ; )
Limit the number of images on your site
Compress your images
Eliminate unnecessary whitespace or even compress JS with tools available
If you use PHP sessions to keep track of your logged in users, then you may
want to have a look at PHP’s function: session_set_save_handler. With
this function you can overrule PHP’s session handling system with you own
class, and store sessions in a database table or in Memcached.
Now a key attribute to success, is to make this table’s storage engine: MEMORY
(also known as HEAP). This stores all session information (should be tiny
variables) in the database server’s RAM. Taking away disk IO stress from your
web server, plus allowing to share the sessions with multiple web servers in
the future, so that if you’re logged in on server A, you’re also logged in on
server B, making it possible to load balance.
Sessions on tmpfs
If it’s too much of a hassle to store sessions in a MEMORY database, storing
session files on a ramdisk is also a good options to gain some performance.
Just make the /var/lib/php5 live in RAM. To learn exactly how to do this,
I’ve written another article called: Create turbocharged storage using tmpfs
Sessions in Memcached
I recently (22th June, 08) found another (better) way to store sessions in a
cluster-proof, resource-cheap way and dedicated a separate article on it
called: Enhance PHP session management.
Some other things to google on if you want even more:
tweak the apache config
turn off apache logging
Add ‘noatime’ in /etc/fstab on your web and data drives to prevent disk
writes on every read
These were imported from my old blog. Please use disqus below for new comments
on 2012-06-07 12:43:07
Thanks for the easy-to-understand and informative article.
on 2012-05-19 02:06:40
Great blog you have here.. It’s hard to find high quality writing like yours these days. I seriously appreciate individuals like you! Take care!!
on 2012-05-17 14:03:46
Thanks for the info :)
I really liked the advice of storing php sessions in a mysql table using memory engine and using it for load balancing.
on 2011-08-04 22:07:42
i have no idea how to do these things and it sounds great. Willing to hire you to help me if interested. :)
on 2011-04-10 01:56:29
Thank you for that advice - I think using a RAM disk would be a lot quicker and easier to set-up than trying to install and learn APC or any of the other caching libraries.
Also, I think it’s worth mentioning that Apache can be optimised to serve different kinds of requests from the same server; using lighttpd (instead of or alongside Apache) is also an option.
on 2011-04-01 09:52:06
Another good way to increase the number of page the server can render is to move all the ressources to S3 so the server only have to take care of rendering pages and not providing static content
Jesse R. Taylor
on 2011-02-24 19:01:04
Oops – meant to say &
quot;…see a significant performance boost from switching to InnoDB&
And I also forgot to say thanks for the useful post.
Jesse R. Taylor
on 2011-02-24 18:59:01
I was under the impression that MyISAM is faster for most use cases (which is why it’s the default), and that InnoDB is most useful when you’ve got a large number of parallel UPDATE/INSERTs going on in the same table. That is, even if you’ve got 10,000 people reading your website all at the same time, row-level locking isn’t going to make a bit of difference as far as read speeds – it’s only if you’ve got a large number of people editing content (e.g. a busy web forum, or image posting site, perhaps) that you’re going to see a significant performance boost from switching to MyISAM. And since most sites are doing much more SELECTing than UPDATE/INSERTing, MyISAM is generally a better choice. There are also other considerations, such as fulltext searching, which MyISAM can do, but not InnoDB; and MyISAM’s smaller resource usage. (Google for ‘myisam vs. innodb’ for more detailed comparisons)
Anyhow, I think in many cases, you might actually be doing more harm than good by switching to InnoDB.
on 2010-11-08 22:07:34
nice article. I’m going to have to try a few of these this week.
on 2010-10-16 18:11:26
try caching mysql slow queries in xcache - helps a lot ;) -&
on 2010-08-27 03:23:56
I want to use Cache PHP output. Thank for guide.
on 2010-08-03 13:44:25
Very good article
on 2010-07-08 01:53:23
Thank you! This script worked great for me. I’ve been search for about four hours and finally found
on 2010-02-23 21:25:02
@ Andrew: Exactly. It can be pretty rough, but there are nice wrappers out there that can make it a breeze: ldirectord is one. Just a perl script that reads a simplified config file, and feeds lvs (using the ipvsadm command) the rules that are needed to balance the traffic.
If you want something slower but easier, have a look at pound. That doesn't rewrite IP packets at kernel level, but just forwards level 7 traffic. So yeah: slower, but easier and in some cases (different networks/whatever) the only option.
on 2010-02-23 21:00:31
Hi Kevin.. It looks as if that is exactly what I am after. Thank you. I assume this is what you mean.. http://www.linuxvirtualserver.org/whatis.html
on 2010-02-21 16:27:42
@ Andrew: Not sure if I really understand your question. But if you mean: What's the best way to scale webservers, the answer is there is none. It really depends on your specific situation. But if money is an issue: there's a lot you can do with lvs. So that means a linux based loadbalancer dividing traffic between as many webservers as you like. There are many other ways but lvs is very powerful considering it costs nothing, and is kernel-based.
on 2010-02-04 15:32:31
Thank for your article.
As far as performance goes, what would you suggest is the best way to add another server into the apache mix?
Would it be installing a private cloud with eucalytus? Perhaps an ubuntu cluster - more for reliabilty really? What about that old SETI concept, the cluster of workstations COW? Does that exist in any form today?
on 2010-01-27 10:04:42
I am a newbie in blogging and I am really impressed by the above given article. I ll try to implemented most of things from this article to my website to save money
on 2010-01-07 18:47:30
@ Matt Kukowski &
amp; Tom: Thanks for chiming in!
on 2010-01-06 18:05:35
Memcached does have some interesting advantages/disadvantages.
Memcached is best used for high read/low write situations. However sessions are re-written every script execution which means it's faster to store your sessions in a DB. However if you have data sets that update infrequently, then it's better to use Memcached.
A problem I've also discovered with Memcached is when using multiple Memcached servers (using the php binary, not the pecl module) and one of those servers looses connectivity, Apache starts throwing segfaults. This includes cases where you flush 1 Memcached server, but not all of them.
on 2009-12-16 10:35:08
To optimize your MySQL queries further, use the LIMIT claus.
e.g. SELECT username FROM table WHERE id='1' LIMIT 1
That way MySQL will end the query as soon as the WHERE claus is satisfied and with 1 record (or how ever many records you will need)
Also, always use Persistant MySQL connections like pconnect()…
on 2009-10-17 23:18:13
awesome tips. your website has been a pot of gold for me, keep up the good work!
on 2009-10-09 14:52:22
excelant article nicely done
on 2009-09-17 12:10:22
@ DV: Yeah like I said, I should probably redo this again some time cause the article is more than 2 years old now : )
on 2009-09-08 18:47:03
I don't know if anyone has mentioned it yet, but nginx is an excellent webserver for those in need to save memory/CPU while serving max amount of users. I use nginx in conjunction with php-fpm and xcache, and things fly.
This is a great article!
on 2009-08-22 17:49:28
@ Julius Beckmann: Yeah like I said, I should probably redo this again some time cause the article is almost 2 years old now.
on 2009-08-12 15:04:54
Nice article, some of the mentioned techniqes might be too much for a normal Admin but there are some nice ideas in there.
You did not mention PHP Op-Code Cachers like APC and XCache - They can reduce the load by simply installing them and let them cache your PHP Scripts.
Also your MyISAM and InnoDB tipp is no general fact, it has to be selected wisely on your setup and website.
You also forget to mention moving static files to Amazon S3 cloud or simply using Lighttpd or Nginx for static files.
on 2009-08-12 12:14:32
@ brant: that's nice of you thanks! :) Though some things are already outdated again. I think I'm going to have to do another version some day.
on 2009-08-04 15:54:13
I rarely make comments on blogs, but this article was so good I had to. It touches on a lot of different areas that can take you months to fully optimize. I know, because it took me quite a few months until i was satisfied.
Not only are these good tips for heavy traffic'd sites, but good tips in general for a speedy and responsive website.
on 2009-07-15 14:02:39
@ ephman: write about things like this and you will : ) chicken-egg situation ; )
on 2009-07-10 06:01:22
ha ha i wish i had the traffic on my blog to worry about things like this! :)
M A Hossain Tonu
on 2009-05-24 10:21:26
I must say that this will be a useful article for large projects.
This could be good part of server load balancing.
on 2009-02-01 21:57:51
@ brainextender: Didn't know that, thanks for the headsup!
on 2009-01-27 17:05:48
Indeed a nice article an congratulation for your digg positions.
Just to mention it. tmpfs is allowed to use virtual memory to swap pages back to disk. May be you dont want that? ramfs won't behave itself in that manner.
if you've enough ram your files are cached by os (here ubuntu).
Check free command. So there is no need to put them in a ramdisk. iostat will show no disk activity then.
on 2008-11-20 16:47:49
Excellent……….:) it make more people happy.
Dilli R. Maharjan
on 2008-05-16 11:43:15
Great Share, I will definately put these ideas into practice.
on 2008-02-27 12:21:31
A few tips for MySQL checks: http://hackmysql.com/mysqlreport has an excellent reporting tool for looking at your logs.
Also: on the note of using deflate in apache: most webservers have CPU to spare but no memory to spare and thus mod_deflate might be handy (connections are handled faster etc and thus apache can handle requests more quickly, thus reducing the concurrent load)
on 2008-02-12 06:40:05
eAccelerator is the BIZ NIZ!!!! awesome article!
on 2007-09-19 22:49:01
Not a tip for after you are on Digg but rather one to help you know whether you are ready for Digg.
If you receive steady, regular traffic, make sure your server's CPU usage rarely goes above 30%. This might seem low but remember that Digg can drive a lot of traffic to your site in a very short amount of time. Whenever the load on our servers reaches 40% at the peak time we buy another one and put it into the load balancer. This is a rule-of-thumb and works fairly well for us. We run 70-odd websites this way, some of which receive over 300,000 unique visitors per day and have survived day-long front page Diggings without degrading performance. We also go over 130MBits/sec while being Dugg although, to be fair, some of the pages could be a little lighter… 4MB is normal for a home page isn't it ? :-P
on 2007-09-16 15:05:39
@ Ray: I don't know if you need that with a RAM device, but it's a good tip anyway so thanks!
on 2007-09-16 05:01:51
Adding 'noatime' in /etc/fstab on your web and data drives. .. prevents file system updating 'access time' each and every time a file is accessed.
on 2007-09-07 15:22:41
on 2007-09-06 18:01:03
@ Simon: There I'm not talking about JS obfuscation or compression, but I'm talking about compression on the apache level, which cannot be cached.
on 2007-09-06 17:30:02
You mentioned that compressing JS and CSS will save bandwidth but use CPU.
Surely if you cache the compressed result then you only have to do it once. Everyones a winner then.
on 2007-08-06 11:12:51
Hi Nima, excelent idea, I've updated the article. Thanks!
on 2007-08-06 10:32:15
Storing session files on a ramdisk is also gain some performance.
on 2007-08-02 12:06:20
That php session class is gold :) I had something like that myself but its not half as good as that one!