Please note, this article is intended for qualified professionals. You take full responsibility over the actions that you decide to undertake based on the suggestions from this article. Please note that Aitoc takes no responsibility for any possible damages to equipment or software, downtime or any losses. If you do not fully understand its content and what suggested changes will lead to, hire a qualified consultant or developer.
Online store’s slow performance may be a critical factor in your customer’s buying decision. Manifold studies, experience and just common sense can definitely prove it. Research from Google and Microsoft shows that slower websites has lower conversion. As we’ve already brought up the issue of Magento slow performance and stated the importance of server settings and hosting environment, this article will give you some useful tips by Aitoc’s team on how to adjust server configurations to your Magento on your own or you can order our Server Setting Optimization Service and/or Magento Server Migration service.
To maximize Magento performance, thus improve your customer experience, you should direct your attention to Magento server settings. In most cases hosting companies offer a standard hosting configuration called the LAMP (Linux, Apache, MySQL & PHP) with default settings. Some hosting companies offer high-quality Magento hosting solutions with an optimized server to ensure best Magento performance. Here are some examples that you might consider:
Peer1Hosting
If you already have a store running on the server that is not optimized for Magento and cannot change your hosting provider due to any reasons consider the below tune up instructions and how they can increase your site performance by making a few changes to the server's settings and installing some additional software like APC.
If you are not technically savvy enough consider hiring a qualified professional that will guide you through this process.
Debian Squeeze (6.0.6) OS was used for all tests performed in this article. Instructions are also given for Debian Squeeze OS. Please note that instructions and results may slightly differ for other Linux distributions.
Test server configuration:
CPU: dual core, 2.5GHz
RAM: 2GB
HDD: single HDD
To test Magento performance we installed Community Edition 1.7.0.2 with 10000 simple products. First test was performed on a standard hosting configuration (LAMP).
Standard LAMP:
Linux: Debian Squeeze (6.0.6)
Apache: 2.2.16
MySQL: 5.1.66 (community)
PHP: 5.3.3 (mod_php)
All the settings were default, except for php. PHP memory_limit was 256M.Stress testing was performed by Siege 2.70 with 20 simultaneous users to measure product page and catalog page load time.
[[email protected] ~] # siege -t 1M -c 20 -f urls.txt -i
Here are the results:
Transactions | 140 hits |
Availability | 100.00 % |
Elapsed time | 59.67 secs |
Data transferred | 0.63 MB |
Response time | 7.71 secs |
Transaction rate | 2.35 trans/sec |
Throughput | 0.01 MB/sec |
Concurrency | 18.08 |
Successful transactions | 140 |
Failed transactions | 0 |
Longest transaction | 10.89 |
Shortest transaction | 6.20 |
Server response time ranged from 6.2 to 10.89 seconds. Average time was 7.71.
Now let’s make some simple server configuration optimizations that will ensure better use of your server resources.
• First, replace Apache + mod_php with Nginx + php fastcgi.
[[email protected] ~] # aptitude install nginx spawn-fcgi php5-cgi php5-cli php5-mcrypt php5-gd php5-curl php5-mysql
• Then add Nginx to autostart and run it.
[[email protected] ~] # update-rc.d nginx defaults [[email protected] ~] # invoke-rc.d nginx start
• Create init script to start PHP in fastcgi mode (/etc/init.d/php5-fcgi).
#! /bin/sh ### BEGIN INIT INFO # Provides: php5-fcgi # Required-Start: $all # Required-Stop: $all # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: PHP FastCGI # Description: PHP FastCGI ### END INIT INFO # Author: AITOC <www.aitoc.com> PATH=/sbin:/usr/sbin:/bin:/usr/bin DESC="PHP FastCGI" NAME=php5-fcgi DAEMON=/usr/bin/spawn-fcgi FCGI_SOCKET=/var/run/php5-fcgi.sock FCGI_USER=www-data FCGI_MODE=0600 PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME DAEMON_ARGS="-s $FCGI_SOCKET -M $FCGI_MODE -u $FCGI_USER -U $FCGI_USER -P $PIDFILE -- /usr/bin/php5-cgi" [ -x "$DAEMON" ] || exit 0 [ -r /etc/default/$NAME ] && . /etc/default/$NAME . /lib/init/vars.sh . /lib/lsb/init-functions do_start() { start-stop-daemon --start --quiet --pidfile $PIDFILE --exec /usr/bin/php5-cgi --test >/dev/null \ || return 1 start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ $DAEMON_ARGS >/dev/null \ || return 2 } do_stop() { start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE RETVAL="$?" rm -f $PIDFILE $FCGI_SOCKET return "$RETVAL" } case "$1" in start) [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" do_start case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; stop) [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" do_stop case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; status) status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? ;; restart|force-reload) log_daemon_msg "Restarting $DESC" "$NAME" do_stop case "$?" in 0|1) do_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) # Failed to stop log_end_msg 1 ;; esac ;; *) echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 exit 3 ;; esac
• Now create php5-fcgi configuration file (/etc/default/php5-fcgi)
export PHP_FCGI_CHILDREN=10 export PHP_FCGI_MAX_REQUESTS=1000
• Add the script /etc/init.d/php5-fcgi to autorun and run it.
[[email protected] ~] # chmod +x /etc/init.d/php5-fcgi [[email protected] ~] # update-rc.d php5-fcgi defaults [[email protected] ~] # invoke-rc.d php5-fcgi start
• Now you should see PHP processes running in OS processes list:
[[email protected] ~] # ps f -u www-data PID TTY STAT TIME COMMAND 881 ? S 0:00 nginx: worker process 1127 ? Ss 0:00 /usr/bin/php5-cgi 1151 ? S 0:00 \_ /usr/bin/php5-cgi 1152 ? S 0:00 \_ /usr/bin/php5-cgi 1153 ? S 0:00 \_ /usr/bin/php5-cgi 1154 ? S 0:00 \_ /usr/bin/php5-cgi 1155 ? S 0:00 \_ /usr/bin/php5-cgi 1156 ? S 0:00 \_ /usr/bin/php5-cgi 1157 ? S 0:00 \_ /usr/bin/php5-cgi 1158 ? S 0:00 \_ /usr/bin/php5-cgi 1159 ? S 0:00 \_ /usr/bin/php5-cgi 1160 ? S 0:00 \_ /usr/bin/php5-cgi
• Let’s proceed with Nginx settings and create a Magento store site configuration (/etc/nginx/sites-available/magento-site-name).
server { listen 80; server_name magento-site-name; fastcgi_buffers 8 32k; fastcgi_buffer_size 64k; fastcgi_read_timeout 18000; client_max_body_size 10m; root /var/www/magento-site-name; location / { index index.html index.php; try_files $uri $uri/ @handler; } location ^~ /app/ { deny all; } location ^~ /includes/ { deny all; } location ^~ /lib/ { deny all; } location ^~ /media/downloadable/ { deny all; } location ^~ /pkginfo/ { deny all; } location ^~ /report/config.xml { deny all; } location ^~ /var/ { deny all; } location /var/export/ { #auth basic; #auth_basic_user_file htpasswd; autoindex on; } location /\. { return 404; } location @handler { rewrite / /index.php; } location ~ \.php/ { rewrite ^(.*.php)/ $1 last; } location /media/catalog/ { access_log off; } location /skin/ { access_log off; } location /js/ { access_log off; } location ~ \.php$ { if (!-e $request_filename) { rewrite / /index.php last; } expires off; fastcgi_param SCRIPT_FILENAME /var/www/magento-site-name$fastcgi_script_name; fastcgi_param QUERY_STRING $query_string; fastcgi_pass unix:/var/run/php5-fcgi.sock; fastcgi_param MAGE_RUN_CODE default; fastcgi_param MAGE_RUN_TYPE store; include /etc/nginx/fastcgi_params; } }
• Now enable Magento site configuration and restart Nginx.
[[email protected] ~] # ln -s /etc/nginx/sites-available/magento-site-name /etc/nginx/sites-enabled/magento-site-name [[email protected] ~] # invoke-rc.d nginx reload
• Install MySQL server and MySQL client.
[[email protected] ~] # aptitude install mysql-server mysql-client
• After installing the SQL server restrict remote database access to the root user, as well as anonymous login and test database. To perform these actions please use script mysql_secure_installation.
Read all the messages generated by the script and choose the appropriate options.
[[email protected] ~] # mysql_secure_installation
Keep in mind that only professional DBA can configure all MySQL server settings.. Do not change anything unless you know how it will influence the performance. Some changes may make MySQL slower or unstable.
In our test we performed the following optimizations (/etc/mysql/conf.d/optimizations.cnf)
[mysqld] skip-networking query-cache-type = 1 query_cache_limit = 4M query_cache_size = 256M thread_concurrency = 4 table_open_cache = 4096 innodb_buffer_pool_size = 512M join_buffer_size = 1M slow_query_log_file = /var/log/mysql/slow-queries.log long_query_time = 2 innodb_file_per_table = 1
• After making changes in MySQL configuration, restart it and add MySQL to startup.
[[email protected] ~] # invoke-rc.d mysql restart [[email protected] ~] # update-rc.d mysql defaults
• Now let’s create Magento database if it doesn’t exist yet.
[[email protected] ~] # echo 'CREATE DATABASE `magento_db` DEFAULT CHARSET utf8 COLLATE utf8_general_ci' | mysql -u root -p [[email protected] ~] # echo 'GRANT ALL PRIVILEGES ON `magento_db`.* TO `magento_user`@`localhost` IDENTIFIED BY "magento_pw"' | mysql -u root -p
• Next, upload Magento archive to your server. In our test case we uploaded it to /root/magento-1.7.0.2.tar.bz2. Then create a directory for Magento (we created /var/www/magento-site-name)
[[email protected] ~] # mkdir /var/www [[email protected] ~] # tar xf /root/magento-1.7.0.2.tar.bz2 -C /var/www [[email protected] ~] # mv /var/www/magento /var/www/magento-site-name
• After unpacking the Magento archive set up permissions for all the files and directories.
[[email protected] ~] # chown -R root:www-data magento-site-name [[email protected] ~] # find magento-site-name -type f -print0 | xargs -r0 chmod 640 [[email protected] ~] # find magento-site-name -type d -print0 | xargs -r0 chmod 750 [[email protected] ~] # chmod -R g+s magento-site-name [[email protected] ~] # chmod -R g+w magento-site-name/{app/etc,media,var} [[email protected] ~] # chmod g+w magento-site-name/{includes,includes/config.php}
• Now let’s proceed with Magento install.
• After the installation process is complete, set up APC and Memcache.
[[email protected] ~] # aptitude install php-apc memcached php5-memcache
• Change APC configuration in /etc/php5/conf.d/apc.ini file.
extension=apc.so apc.enabled = 1 apc.cache_by_default = 1 apc.shm_segments = 1 apc.shm_size = 128 apc.mmap_file_mask = /tmp/apc.XXXXXX ; set apc.stat=1 during development apc.stat = 0 apc.num_files_hint = 10000 apc.max_file_size = 5M apc.ttl = 7200 apc.user_ttl = 7200
• Restart PHP after you modified APC config.
[[email protected] ~] # invoke-rc.d php5-fcgi restart
• Now change Magento settings. Open /var/www/magento-site-name/app/etc/local.xml and add the following code to the config/global section:
<session_save><![CDATA[memcache]]></session_save> <session_save_path><![CDATA[tcp://localhost:11211?persistent=1&weight=2&timeout=10&retry_interval=10]]></session_save_path> <cache> <backend>apc</backend> <prefix>mage_</prefix> <fast_backend>apc</fast_backend> <slow_backend>database</slow_backend> <slow_backend_store_data>0</slow_backend_store_data> <auto_refresh_fast_cache>0</auto_refresh_fast_cache> </cache>
By using fast_backend/slow_backend/slow_backend_store_data you can disable Magento two-level caching. Please note that this step might lead to issues with Magento caching when APC lacks memory or other issues. Be aware of mighty consequences!
Now Magento cache is stored in APC, while sessions in the memcache.
• Let’s clean up and delete /var/www/magento-site-name/var/cache and /var/www/magento-site-name/var/session folders.
Let’s see if all the changes in server configuration enhanced Magento performance.
The second test for the configured server was performed on same Magento Community Edition 1.7.0.2 with 10000 simple products by Siege 2.70 with 20 simultaneous users, as we used for LAMP configuration.
[[email protected] ~] # siege -t 1M -c 20 -f urls.txt -i
Here are the results of the both tests:
Before server optimization |
After server optimization | |
Transactions | 140 hits | 238 hits |
Availability | 100.00 % | 100.00 % |
Elapsed time | 59.67 secs | 59.37 secs |
Data transferred | 0.63 MB | 1.24 MB |
Response time | 7.71 secs | 4.33 secs |
Transaction rate | 2.35 trans/sec | 4.01 trans/sec |
Throughput | 0.01 MB/sec | 0.02 MB/sec |
Concurrency | 18.08 | 17.38 |
Successful transactions | 140 | 238 |
Failed transactions | 0 | 0 |
Longest transaction | 10.89 | 6.44 |
Shortest transaction | 6.20 | 2.73 |
As a result of all our optimizations page load time decreased approximately two times (4.33 seconds against 7.71 with LAMP configuration). Min and Max page load time dropped to 2.73 and 6.44 seconds respectively against 6.20 and 10.89 seconds with LAMP.
These are great results, aren’t they? By introducing a few changes into default server settings we significantly improved Magento performance, minimized load time and gained in user experience.
You can download all files for server optimization here.
Please note, this article is intended for qualified professionals. You take full responsibility over the actions that you decide to undertake based on the suggestions from this article. Please note that AITOC takes no responsibility for any possible damages to equipment or software, downtime or any losses. If you do not fully understand its content and what suggested changes will lead to, hire a qualified consultant or developer.