Optimizing LAMP 101, step through tutorial guide
LAMP is an acronym for a solution stack of open source software: Linux, Apache, MySQL and PHP, principal components to build a general purpose web server.
This article describes basics of benchmarking and configuration optimisation for fairly recent hardware. Most tips fall in the “common sense” category of senior sysadmins. The main objective of this article is to make junior sysadmins sensible to the requirement of reviewing configurations of whatever installed software.
This article steps through the basic process of optimizing each software of the LAMP stack:
- benchmarking with wbox,
- Linux optimisations,
- Apache optimisations,
- PHP optimisations,
- MySQL optimisations.
The author recommends a different software stack when choosing is possible:
- FreeBSD instead of Linux,
- Nginx or Lighttpd instead of Apache,
- Python instead of PHP, or at least PHP with FastCGI,
- PostgreSQL instead of MySQL.
Benchmarking with wbox
Wbox is used in the next chapters of this articles for HTTP benchmarking.
Wbox aims to help you having fun while testing HTTP related stuff. You can use it to perform many tasks, including the following.
* Benchmarking how much time it takes to generate content for your web application. * Web server and web application stressing. * Test if the HTTP compression is working and if it is actually serving pages faster.Wbox is free software under the GPL version 2 license and was written in ANSI C (POSIX runtime required) by Salvatore ‘antirez’ Sanfilippo.
Example installation on FreeBSD:
jpic@natacha:~/src/wbox$ ls AUTHORS Makefile anet.c sds.h wbsignal.h COPYING README anet.h wbox.c Changelog TODO sds.c wbsignal.c jpic@natacha:~/src/wbox$ make cc -c -O2 -fno-strict-aliasing -pipe -march=prescott -g anet.c cc -c -O2 -fno-strict-aliasing -pipe -march=prescott -g sds.c cc -c -O2 -fno-strict-aliasing -pipe -march=prescott -g wbsignal.c cc -c -O2 -fno-strict-aliasing -pipe -march=prescott -g wbox.c cc -o wbox -O2 -fno-strict-aliasing -pipe -march=prescott -g anet.o sds.o wbsignal.o wbox.o jpic@natacha:~/src/wbox$ ./wbox Usage: wbox[options ...] options: — stop after requests compr — send Accept-Encoding: gzip,deflate in request showhdr — show the HTTP reply header dump — show the HTTP reply header + body silent — don't show status lines head — use the HEAD method instead of GET http10 — use HTTP/1.0 instead of HTTP/1.1 close — close the connection after reading few bytes host — use as Host: field in HTTP request timesplit — show transfer times for different data chunks wait — wait seconds between requests. Default 1. clients — spawn concurrent clients (via fork()). referer — Send the specified referer header. cookie — Set cookie name=val, can be used multiple times. -h or --help — show this help. -v — show version. SERVER MODE Usage: wbox servermode webroot [serverport (def 8081)] options: maxclients — Max concurrent clients in server mode (default 20). EXAMPLES wbox wikipedia.org (simplest, basic usage) wbox wikipedia.org 3 compr wait 0 (three requests, compression, no delay) wbox wikipedia.org 1 showhdr silent (just show the HTTP reply header) wbox wikipedia.org timesplit (show splitted time information) wbox 1.2.3.4 host example.domain (test a virtual domain at 1.2.3.4) wbox servermode webroot /tmp/mydocuments (Try it with http://127.0.0.1:8081) More docs? there is a tutorial at http://hping.org/wbox
Linux
Optimising the Linux kernel is a tedious task. The objective is to reduce it’s footprint. Kernel binaries shipped with most distribution (Debian, Ubuntu, Red Hat …) have a large footprint because it should be able to “boot the world”. On the other hand, a server with a precise purpose does not need “the world” to boot its system.
It is better to start with a vanilla (unpatched) stable version of the kernel. The process is simple and tedious. The help screen of each single option should be read, and understood in most cases.
- if the option is not needed then it can be disabled: [ ],
- if the option is needed at boot time then it should be compiled in the kernel binary: <*>,
- if the option is needed at run time then it can be compiled as module: [M],
Example options that should be compiled in:
- disk access drivers (SATA, PATA, SCSI, RAID…), like “Intel ESB, ICH, PIIX3, PIIX4 PATA/SATA support” for an intel “mobo” (motherboard).
- file system drivers for root, like “Ext3 journalling file system support” if the root partition is formated as ext3,
Example options that should be compiled as modules:
- Network devices like “Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support” for the ethernet card or “Dummy net driver support” for virtual systems,
- Hardware sensors like “Intel Core (2) Duo/Solo temperature sensor”,
Example options that should not be compiled at all:
- PCI Debugging and any verbose/debug option which bloat the kernel with strings,
- Kernel .config support, for security,
Detailing the kernel compile process or each kernel option is out of the scope of this article. Gentoo Kernel configuration manual contains some basics.
Apache
Apache HTTPD default configuration also loads many modules which are not needed for server specific purpose. Again the objective is to reduce its footprint so that it serves whatever HTTP application and nothing more.
Footprint
For example, a default Gentoo GNU/Linux Apache 2 configuration loads many modules which are not needed in most cases:
LoadModule authn_anon_module modules/mod_authn_anon.so LoadModule authn_dbd_module modules/mod_authn_dbd.so LoadModule authn_dbm_module modules/mod_authn_dbm.so LoadModule authn_default_module modules/mod_authn_default.so LoadModule authn_file_module modules/mod_authn_file.so LoadModule authz_dbm_module modules/mod_authz_dbm.so LoadModule authz_default_module modules/mod_authz_default.so LoadModule authz_groupfile_module modules/mod_authz_groupfile.so LoadModule authz_host_module modules/mod_authz_host.so LoadModule authz_owner_module modules/mod_authz_owner.so LoadModule authz_user_module modules/mod_authz_user.so LoadModule autoindex_module modules/mod_autoindex.so
Apache 2 provides a configtest command which won’t pass if the configuration (like vhost configurations) declare a setting of a module which is not loaded. A quick and easy Apache 2 basic configuration process is:
- comment out a LoadModule line in httpd.conf,
- run the configuration tests,
- uncomment the LoadModule line if the tests fail,
- move on to the next module if the tests pass.
Running the configuration tests is possible with the -t switch of the Apache 2 binary. Note that the path to the httpd.conf must be specified like so:
/usr/sbin/apache2 -f /etc/apache2/httpd.conf -t
The tests pass if the output of this command is:
Syntax OK
Example failure, if the following is commented:
LoadModule log_config_module modules/mod_log_config.so
And if a command defined by this module is called somewhere else in the configuration, like a vhost file:
LogFormat "%h %l %u %t \"%r\" %>s %b" common
Then the configuration tests will fail claiming a “Syntax error”:
yourhost / # /usr/sbin/apache2 -f /etc/apache2/httpd.conf -t Syntax error on line 9 of /etc/apache2/vhosts.d/01_yourvhost.conf: Invalid command 'LogFormat', perhaps misspelled or defined by a module not included in the server configuration
Important modules to compress the output are mod_gzip mod_deflate
Like for Linux kernel, it is best to read and understand the documentation of each module.
Compression
Compression of static files is handled by Apache mod_deflate which is shipped by default.
The following configuration enabled compression for css, javascript and html (be it dynamically generated or not):
LoadModule deflate_module modules/mod_deflate.so AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/x-javascript
Before:
$ ./wbox http://trikapalanet.feeder.ww7.be/squelettes/screen_aqua.css compr 5 WBOX trikapalanet.feeder.ww7.be (94.23.20.157) port 80 [compr] 0. 200 OK 7684 bytes 326 ms 1. 200 OK 7684 bytes 325 ms 2. 200 OK 7684 bytes 324 ms 3. 200 OK 7684 bytes 326 ms 4. 200 OK 7684 bytes 325 ms --- 5 replies received, time min/avg/max = 324/325.20/326 --- $ # with PHP generated contents $ ./wbox http://trikapalanet.feeder.ww7.be/ compr 5 WBOX trikapalanet.feeder.ww7.be (94.23.20.157) port 80 [compr] 0. 200 OK 17292 bytes 602 ms 1. 200 OK 17292 bytes 573 ms 2. 200 OK 17292 bytes 566 ms 3. 200 OK 17292 bytes 568 ms 4. 200 OK 17292 bytes 567 ms --- 5 replies received, time min/avg/max = 566/575.20/602 ---
After:
$ ./wbox http://trikapalanet.feeder.ww7.be/squelettes/screen_aqua.css compr 5 WBOX trikapalanet.feeder.ww7.be (94.23.20.157) port 80 [compr] 0. 200 OK 2185 bytes 206 ms compr 1. 200 OK 2185 bytes 205 ms compr 2. 200 OK 2185 bytes 206 ms compr 3. 200 OK 2185 bytes 206 ms compr 4. 200 OK 2185 bytes 207 ms compr --- 5 replies received, time min/avg/max = 205/206.00/207 --- $ # with php generated contents $ ./wbox http://trikapalanet.feeder.ww7.be/ compr 5 WBOX trikapalanet.feeder.ww7.be (94.23.20.157) port 80 [compr] 0. 200 OK 5383 bytes 369 ms compr 1. 200 OK 5383 bytes 354 ms compr 2. 200 OK 5382 bytes 365 ms compr 3. 200 OK 5384 bytes 437 ms compr 4. 200 OK 5384 bytes 599 ms compr --- 5 replies received, time min/avg/max = 354/424.80/599 ---
PHP
PHP opcode cache
An opcode (operation code) is the portion of a machine language instruction that specifies the operation to be performed. Their specification and format are laid out in the instruction set architecture of the processor in question (which may be a general CPU or a more specialized processing unit like PHP).
The APC module for PHP is responsible for bytecode caching.
Installation procedure of the APC module depends of the operating system. On Choco GNU/Linux:
emerge -K pecl-apc
It is important to configure APC, the configuration file is in /etc/php/cgi-php5/ext-active/apc.ini by default on Gentoo GNU/Linux, or in /etc/php/apache2-php5/ext-active/apc.ini for Apache mod_php.
Example settings for a Sysadmin II virtual server with an application like Magento:
apc.enabled = 1 apc.shm_segments = 1 apc.shm_size = 128 apc.max_file_size = 32M apc.stat=1
Output compression
There is no need to configure PHP level compression if Apache is already configured to use HTTP compression, which one can check with the compr switch of wbox. In that case it would just consume CPU for nothing.
Compression at PHP level is enabled by the following variables in PHP.ini, which are rarely set by default:
zlib.output_compression = 1 zlib.output_handler = On
One may believe that this kind of zlib PHP level HTTP compression is dangerous although it looks safe according to the manual:
zlib.output_compression boolean/integer
Whether to transparently compress pages. If this option is set to "On" in php.ini or the Apache configuration, pages are compressed if the browser sends an "Accept-Encoding: gzip" or "deflate" header. "Content-Encoding: gzip" (respectively "deflate") and "Vary: Accept-Encoding" headers are added to the output. In runtime, it can be set only before sending any output.
It is recommended to enable HTTP compression at the webserver level which does more exception checks (such as Accept-Encoding). The http server run by ChocolatePistachio is configured to do that well. Users with their own IP and webserver should enable it at their webserver level.
Enabling HTTP compression for other dynamic content generator than PHP is described in the Lighttpd mod_compress documentation.
Misc
It is possible to optimize the PHP parser with the following options:
short_open_tag = Off asp_tags = Off zend.ze1_compatibility_mode = Off
Detailing each option of PHP is out of the scope of this article. Like with Linux and Apache, a good sysadmin reads each option of the configuration file and the associated documentation in order to understand them.
MySQL
The default configuration shipped with MySQL on Gentoo GNU/Linux is suitable for servers with 64M of RAM. This is cute but probably far under what a recent server can offer (and far under your expectations).
Default configuration:
key_buffer = 16M max_allowed_packet = 1M table_cache = 64 sort_buffer_size = 512K net_buffer_length = 8K read_buffer_size = 256K read_rnd_buffer_size = 512K myisam_sort_buffer_size = 8M # the rest of the innodb config follows: # don't eat too much memory, we're trying to be safe on 64Mb boxes # you might want to bump this up a bit on boxes with more RAM innodb_buffer_pool_size = 16M # this is the default, increase it if you have lots of tables innodb_additional_mem_pool_size = 2M # you may wish to change this size to be more suitable for your system # the max is there to avoid run-away growth on your machine innodb_data_file_path = ibdata1:10M:autoextend:max:128M
Configuration example for a Sysadmin II virtual server with an application like Magento with around 5000 products:
key_buffer = 256M max_allowed_packet = 2M table_cache = 64 sort_buffer_size = 2M net_buffer_length = 8K read_buffer_size = 2M read_rnd_buffer_size = 2M myisam_sort_buffer_size = 64M innodb_buffer_pool_size = 128M innodb_data_file_path = ibdata1:128M:autoextend:max:128M innodb_additional_mem_pool_size = 64M
Also, note that the default fstab for virtual servers mounts a 16M tmpfs in the guest /tmp directory. The host system administrator should definitively change it. Setting it to 128M in the case of a Sysadmin II VPS is fair.
Detailing each option of MySQL is out of the scope of this article. Like with Linux, Apache and PHP: a good sysadmin reads each option of the configuration file and the associated documentation in order to understand them.
An excellent open source script helps for application specific optimizations, Mysqltuner:
» What can MySQLTuner do?
MySQLTuner is a script written in Perl that will assist you with your MySQL configuration and make recommendations for increased performance and stability. Within seconds, it will display statistics about your MySQL installation and the areas where it can be improved.
Credits
- stbuehler from #lighttpd@irc.freenode.net about HTTPds,
- Zurgutt about MySQL,
- Michael Maclean about Apache,
- Kore Nordmann about HTTP,
- Derick Rethans about PHP,
- William Waisse, for lending an apache server,
Errors? Comments?
Please post a comment or email the author directly any inaccuracy is found in this article.
Comments
Comment form for «Optimizing LAMP 101, step through tutorial guide»