LAMP setup: Make it faster
After LAMP setup and Apache and PHP configuration, everything works as expected. Your site become more and more popular. Popularity in other words means more visitors (traffic) or we can say more requests per second. Did you ever measure how many requests per second your WEB server can handle and how you can improve it? This article should give you answer and show you how to easily increase quickness of your WEB application like WordPress, phpBB, Joomla ...
1. Benchmarking tool
The most common benchmarking tool in LAMP World is ab - Apache HTTP server benchmarking tool. It is command line utility and it comes in httpd-tools rpm package. Open terminal, write ab and press enter. You should get usage help like this:
Usage: ab [options] [http[s]://]hostname[:port]/path
Options are:
-n requests Number of requests to perform
-c concurrency Number of multiple requests to make
-P attribute Add Basic Proxy Authentication, the attributes
are a colon separated username and password.
-X proxy:port Proxyserver and port number to use
-V Print version number and exit
...
...
Now it's time to test your WEB application. Write ab with URL of your WEB site. Don't forget to add slash at the end because utility expects URL:
Without slash in first case (only WEB site name), you will get an error. Without slash in second case you will get document length 0 and wrong statistics. Why wrong statistics? Because without slash, ab will try to retrieve new-to-wordpress file and the WEB server will respond with 301 (permanent redirect) because "he knows" this is a directory. Instead of redirection, ab will display statistics of HTTP header (redirection) and as it says this is HTTP header with no body. However, browser will access pages (directories) without slashes because he understands redirection and you will see slash finally appears in URL after page is displayed. If you are sitting behind firewall and you have to use proxy please add options -P and -X.
[dbunic ~]$ ab www.redips.net/wordpress/new-to-wordpress/ Server Software: Apache/x.y.z Server Hostname: www.redips.net Server Port: 80 Document Path: /wordpress/new-to-wordpress/ Document Length: 21144 bytes Concurrency Level: 1 Time taken for tests: 0.332835 seconds Complete requests: 1 Failed requests: 0 Write errors: 0 Total transferred: 21341 bytes HTML transferred: 21144 bytes Requests per second: 3.00 [num/sec] (mean) Time per request: 332.835 [ms] (mean) Time per request: 332.835 [ms] (mean, across all concurrent requests) Transfer rate: 60.09 [Kbytes/sec] received
Without any switch, only ab and URL, ab utility will make 1 contact to WEB server. Lets make this more real. I will rise request number to 100 and concurrency to 10. WEB server will feel like 10 clients request same page in the same time. Each client will request the same page 10 times.
[dbunic ~]$ ab -n100 -c10 www.redips.net/wordpress/new-to-wordpress/ Concurrency Level: 10 Time taken for tests: 29.35572 seconds Complete requests: 100 Failed requests: 0 Write errors: 0 Total transferred: 2134100 bytes HTML transferred: 2114400 bytes Requests per second: 3.44 [num/sec] (mean) Time per request: 2903.557 [ms] (mean) Time per request: 290.356 [ms] (mean, across all concurrent requests) Transfer rate: 71.77 [Kbytes/sec] received
You can see how WordPress WEB application can give only 3.44 requests per second and time taken for test is about 30 seconds. With some easy magic, LAMP server can be 150% faster
2. MySQL caching
Lets focus on MySQL in LAMP server. MySQL is the most often used database because it has everything what WEB application expects from database. By default, caching is turned off. To check MySQL caching, please log in to MySQL console and list Qcache variables:
mysql> show status like 'Qcache%'; +-------------------------+-------+ | Variable_name | Value | +-------------------------+-------+ | Qcache_free_blocks | 0 | | Qcache_free_memory | 0 | | Qcache_hits | 0 | | Qcache_inserts | 0 | | Qcache_lowmem_prunes | 0 | | Qcache_not_cached | 0 | | Qcache_queries_in_cache | 0 | | Qcache_total_blocks | 0 | +-------------------------+-------+
To turn on MySQL query cache, open /etc/my.cnf file and add query-cache-type and query-cache-size options in [mysqld] section. After file is saved, restart MySQL server.
[mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock user=mysql # Default to using old password format for compatibility with mysql 3.x # clients (those using the mysqlclient10 compatibility package). old_passwords=1 # turn on query cache query-cache-type = 1 query-cache-size = 32M [mysqld_safe] log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid
query-cache-type variable has three options:
- 0 or OFF
- 1 or ON
- 2 or DEMAND
query-cache-size defines size of cache and 32Mb is enough for some average WEB application. After enabling MySQL cache, query cache variables should look:
mysql> show status like 'Qcache%'; +-------------------------+----------+ | Variable_name | Value | +-------------------------+----------+ | Qcache_free_blocks | 1 | | Qcache_free_memory | 33545600 | | Qcache_hits | 0 | | Qcache_inserts | 0 | | Qcache_lowmem_prunes | 0 | | Qcache_not_cached | 1 | | Qcache_queries_in_cache | 0 | | Qcache_total_blocks | 1 | +-------------------------+----------+
Lets see how ab statistics looks after enabling MySQL cache for WordPress:
Concurrency Level: 10 Time taken for tests: 25.884421 seconds Complete requests: 100 Requests per second: 3.86 [num/sec] (mean) Time per request: 2588.442 [ms] (mean) Time per request: 258.844 [ms] (mean, across all concurrent requests) Transfer rate: 80.51 [Kbytes/sec] received
Hmm, there is a little improvement for WordPress (from 3.44 to 3.86 requests per second), but I expected bigger acceleration. The reason for WordPress can be:
- empty / small database (currently only 5 articles in database)
- small number of database queries on / per page
- tested WordPress version doesn't have any additional modules
- small number of tables in database (WordPress has only 10 tables)
- optimized database queries
MySQL query cache setting will certainly give more speed for larger databases like phpBB and Joomla have.
3. PHP caching
As you know, for every HTTP request PHP 5 engine interprets (run time compile) requested page. Can you imagine amount of executed overhead by requesting the same PHP page? Caching engines prevents overhead and this is the key for speeding up. On the first request, PHP page is compiled to opcode and stored to cache. After that, PHP page is not compiled again, but pulled from cache and proceeded normally from that point. If you dig more about caching engines, you will find testing original file for modification, user variables, excluding from caching, garbage collecting, time to live ... Today exist several main PHP caching engines:
My favourite is APC. Why APC? Because I listened Rasmus Lerdorf's Architecture and Performance presentation on PHP conference in Zagreb. Few chapters was about APC
Second and more important is that APC will be included in the core of PHP 6.
In RedHat Linux family, APC installation goes very simply with yum utility. If you aren't sure about correct package name, you can find any packages matching a string in the description.
# how to find any packages matching a string in the description yum search apc # install APC package yum install php-pecl-apc # install gd package to have graphs in APC dashboard (optional) yum install php-gd
After installation and httpd restart, APC should run immediately. This is small package and you can see all files contained in package by rpm -ql command.
[dbunic ~]$ rpm -ql php-pecl-apc /etc/php.d/apc.ini /usr/lib/php/modules/apc.so /usr/share/doc/php-pecl-apc-3.0.19 /usr/share/doc/php-pecl-apc-3.0.19/CHANGELOG /usr/share/doc/php-pecl-apc-3.0.19/INSTALL /usr/share/doc/php-pecl-apc-3.0.19/LICENSE /usr/share/doc/php-pecl-apc-3.0.19/NOTICE /usr/share/doc/php-pecl-apc-3.0.19/TECHNOTES.txt /usr/share/doc/php-pecl-apc-3.0.19/TODO /usr/share/doc/php-pecl-apc-3.0.19/apc.php /usr/share/pear/.pkgxml/APC.xml
The three main files in package are:
- apc.ini - configuration file
- apc.so - apc module loaded by PHP
- apc.php - APC monitor page
Configuration file apc.ini is located in /etc directory and default APC cache size is fitted to 32Mb. For APC monitor purpose, you can copy apc.php file from installed location to document root. Before accessing apc.php, open file and edit authentication (few lines at the apc.php beginning). You can define new user name and password or you can disable authentication. This is pretty easy. Point browser to apc.php and you will get nice APC dashboard. If you haven't install php-gd package, then dashboard will be without graphs. After APC installation (and httpd restart), ab statistics finally looks:
Concurrency Level: 10 Time taken for tests: 11.653682 seconds Complete requests: 100 Total transferred: 2134100 bytes HTML transferred: 2114400 bytes Requests per second: 8.58 [num/sec] (mean) Time per request: 1165.368 [ms] (mean) Time per request: 116.537 [ms] (mean, across all concurrent requests) Transfer rate: 178.83 [Kbytes/sec] received
4. Conclusion
If you compare starting 3.44 requests per second and 8.58 requests per second with minimal MySQL configuration and simple APC installation, gain of about 150% is very impressive. To gain more speed from WordPress, you will have to install some WordPress caching modules like: WP Super Cache or WP-Cache and you can read it in my next article Make WordPress fly. Anyway, the main thing is to understand how to measure speed of WEB application and how to make it faster.