10 Minutes to a Leaner LAMP stack
For this quick article I am only going to quickly cover the A and the M of the LAMP stack.
[caption id="attachment_318" align="alignnone" width="661" caption="web server under load"]
[/caption]
To see how much RAM MySQL actually wants, we restart it with Apache stopped
[caption id="attachment_315" align="alignnone" width="641" caption="MySQL running on it's own, gobbles up 21M RAM"]
[/caption]
Choosing to unload any of these modules is completely dependent of how you are using the server. But for many PHP developers can safely unload cgi.
<Directory /var/www/wordpress>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
AllowOverride None
</Directory>
Possible more appropriate settings for a little personal blog site. Overall you need to lower MaxClients to the amount you can run without paging. If this is too few, you probably need more RAM.
Now there are many, many MySQL config options that affect the amount of resource it uses. I'll just cover a couple here, the key buffer and the query cache
The stock settings for these are
For many types of sites, these can be a bit large, for small sites, some suggested settings might be:
To see what the runtime values are concerning the query cache and key buffer use (once server has been under load)
As you reduce key_buffer and query_cache_size, check the output of the SHOW STATUS command shown above while the server is under load to verify that you are not running low on Key_blocks_unused or Qcache_free_memory
The Setup
Assumptions: You have root on the server in question or you at least have enough server access to effect the configuration of Apache and MySQL.The test server setup:
- A Virtual Private server running on Rackspace cloud
- Ubuntu 9.04 (Jaunty Jackalope)
$ sudo apt-get update $ sudo apt-get upgrade $ sudo locale-gen en_US.UTF-8 $ sudo apt-get install apache2-mpm-prefork php5 php5-dev mysql-server-5.0 mysql-client-5.0 php5-mysql $ sudo a2enmod rewrite
- Installed latest Wordpress and added some test posts
Baseline Performance:
Before you start changing anything be sure to record the baseline performance ot the server. Place the server under load. I used http_load but anything similar can be usedThe Test URL's that http_load will draw from
$ cat pdxphp-test http://67.23.47.195/ http://67.23.47.195/2010/02/test-post-1/ http://67.23.47.195/2010/02/test-post-2/ http://67.23.47.195/2010/02/test-post-3/ http://67.23.47.195/2010/02/test-post-4/ http://67.23.47.195/2010/02/test-post-5/
Run the test
$ http_load -parallel 5 -seconds 20 pdxphp-test 83 fetches, 5 max parallel, 1.74373e+06 bytes, in 20.0009 seconds 21008.8 mean bytes/connection 4.14982 fetches/sec, 87182.7 bytes/sec msecs/connect: 80.6013 mean, 99.26 max, 71.974 min msecs/first-response: 795.394 mean, 5495.6 max, 225.29 min HTTP response codes: code 200 -- 82
Apache
Reduce the number of modules loaded
You can start with this. It will typically not give you incredible results but you will save some resource and it is a good security policy. You can list your loaded modules withapache2ctl -t -D DUMP_MODULES
Loaded Modules: core_module (static) log_config_module (static) logio_module (static) mpm_prefork_module (static) http_module (static) so_module (static) alias_module (shared) auth_basic_module (shared) authn_file_module (shared) authz_default_module (shared) authz_groupfile_module (shared) authz_host_module (shared) authz_user_module (shared) autoindex_module (shared) cgi_module (shared) deflate_module (shared) dir_module (shared) env_module (shared) mime_module (shared) negotiation_module (shared) php5_module (shared) rewrite_module (shared) setenvif_module (shared) status_module (shared)
$ sudo a2dismod cgi Module cgi disabled. Run '/etc/init.d/apache2 restart' to activate new configuration! sam@pdx-test:/etc/apache2/mods-enabled$ sudo apache2ctl start
Turn off htaccess
Explanation from Apache. So all you need to do is take the contents of the .htaccess file in your site's webroot and place that in the corresponding vhost. Then turn off htaccess files with AllowOverride None and rm the .htaccess file in the web root after restarting apache.sudo vi /etc/apache/sites-enabled/wordpress
rm /var/www/wordpress/.htaccess
Now, how to really affect apache
This is all well and good and Apache will be better off for it but if you had a server that was paging and dying under load, after making these changes, that will probably not change. The bigger issue shown in the top output above is that, for the amount of physical RAM, there are just too many 20+MB processes the apache conf file controls these settings (/etc/apache2/apache2.conf on Ubuntu) The stock settings:<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxClients 150
MaxRequestsPerChild 0
</IfModule><IfModule mpm_prefork_module>
StartServers 1
MinSpareServers 1
MaxSpareServers 5
MaxClients 5
MaxRequestsPerChild 1000
</IfModule>The Results thus far
[caption id="attachment_332" align="alignnone" width="651" caption="Top output with Apache Trimmed and under load"] [/caption]MySQL
Now onto MySQL. We saw above that MySQL is staring up and grabbing ~21M of RAM. A low to medium volume LAMP server probably doesn't need all that but, again every situation is different. Here though are some notes of how to tune the Low Hanging Fruit of MySQLIf you don't use it, Turn it off
Same as with Apache modules, turn off what you do not need. Storage engines are a great place to start. Very few frameworks (including WP), utilize InnoDB by default. Most use good old MyISAM. Stopping MySQl from loading the InnoDb engine (and its predecessor:bdb) is quite simple, the lines are in my.cnf, just uncomment themskip-innodb skip-bdb
# used for holding built indexes key_buffer = 16M # largest query that is cache-able query_cache_limit = 1M # used for caching queries query_cache_size = 16M
# used for holding built indexes key_buffer = 4M # largest query that is cache-able query_cache_limit = 500K # used for caching queries query_cache_size = 8M
mysql> SHOW STATUS WHERE Variable_name LIKE 'Key_blocks_%' OR Variable_name LIKE 'Qcache_%'; +-------------------------+----------+ | Variable_name | Value | +-------------------------+----------+ | Key_blocks_not_flushed | 0 | | Key_blocks_unused | 13369 | | Key_blocks_used | 27 | | Qcache_free_blocks | 4 | | Qcache_free_memory | 16326632 | | Qcache_hits | 5969 | | Qcache_inserts | 95 | | Qcache_lowmem_prunes | 0 | | Qcache_not_cached | 410 | | Qcache_queries_in_cache | 46 | | Qcache_total_blocks | 106 | +-------------------------+----------+ 11 rows in set (0.00 sec)
The Final result of our tinkering
So now that we have trimmed Apache and MySQL lets see what the top output looks like with the server under load Our CPU load has reduced (idle is up to ~65%). More importantly we are no longer paging and we still have a bit of RAM left over. MySQL is running with ~8M of RAM, down from ~21M. Also as seen below, we've roughly doubled our performance. Up to 6.85 req/sec and first response in down to 276ms.$ http_load-parallel 5 -seconds 20 pdxphp-test 137 fetches, 5 max parallel, 4.69493e+06 bytes, in 20 seconds 34269.6 mean bytes/connection 6.85 fetches/sec, 234747 bytes/sec msecs/connect: 80.6284 mean, 96.353 max, 73.043 min msecs/first-response: 276.766 mean, 447.707 max, 225.995 min HTTP response codes: code 200 -- 137


Comments (0)
Add a Comment