Speed Up Magento 2 Times in 3 Simple Steps

Full page cache magento

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:

Simplehelix

Nexcess

Peer1Hosting

Zerolag

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.

 [root@magesrv ~] # 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.

Magento cache extension

•    First, replace Apache + mod_php  with Nginx + php fastcgi.

[root@magesrv ~] # 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.

[root@magesrv ~] # update-rc.d nginx defaults
[root@magesrv ~] # 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.

[root@magesrv ~] # chmod +x /etc/init.d/php5-fcgi
[root@magesrv ~] # update-rc.d php5-fcgi defaults
[root@magesrv ~] # invoke-rc.d php5-fcgi start

   Now you should see PHP processes running in OS processes list:

[root@magesrv ~] # 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.

[root@magesrv ~] # ln -s /etc/nginx/sites-available/magento-site-name /etc/nginx/sites-enabled/magento-site-name
[root@magesrv ~] # invoke-rc.d nginx reload

•   Install MySQL server and MySQL client.

[root@magesrv ~] # 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.

[root@magesrv ~] # 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.

[root@magesrv ~] # invoke-rc.d mysql restart
[root@magesrv ~] # update-rc.d mysql defaults

•   Now let’s create Magento database if it doesn’t exist yet.

[root@magesrv ~] # echo 'CREATE DATABASE `magento_db` DEFAULT CHARSET utf8 COLLATE utf8_general_ci' | mysql -u root -p
[root@magesrv ~] # 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)

[root@magesrv ~] # mkdir /var/www
[root@magesrv ~] # tar xf /root/magento-1.7.0.2.tar.bz2 -C /var/www
[root@magesrv ~] # mv /var/www/magento /var/www/magento-site-name

•   After unpacking the Magento archive set up permissions for all the files and directories.

[root@magesrv ~] # chown -R root:www-data magento-site-name
[root@magesrv ~] # find magento-site-name -type f -print0 | xargs -r0 chmod 640
[root@magesrv ~] # find magento-site-name -type d -print0 | xargs -r0 chmod 750
[root@magesrv ~] # chmod -R g+s magento-site-name
[root@magesrv ~] # chmod -R g+w magento-site-name/{app/etc,media,var}
[root@magesrv ~] # 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.

 [root@magesrv ~] # 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.

 [root@magesrv ~] # 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.

Magento full page cache extension

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.

[root@magesrv ~] # 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.

Using APC to speed up Magento Previous Post
Skills of a Software Developer Next Post