Drupal 7 + memcached + APC + NGINX + PHP5-FPM + Squeeze Optimization

By default, Drupal comes with a pretty extensive caching and aggregation system which affords even basic users the possibility of using what used to be advanced methods for improving their site performance.

Unfortunately, at some point these built-in methods are going to fall short, especially when a site has thousands of records and is displaying dynamic content for users on every page load. Enter memory-based caching.

APC (Alternative PHP Cache) is a PHP opcode caching application. There is a nice write-up on APC and the interface here, but that’s not the focus of this post. Rather, we are going to look at how to get all these various performance-enhancing systems to “play nice” with one another.

For this exercise, we will use a server running Debian 6.0.5 (squeeze) with Nginx and PHP5-FPM already installed. These are pretty straightforward installs, with minimal configuration required. The real trick is getting everything running WITH Drupal taking advantage!

First of all, let’s look at the /etc/php5/conf.d/apc.ini config file:

extension=apc.so
date.timezone='America/Los_Angeles'
apc.enabled=1
apc.shm_segments=1
apc.shm_size=512
apc.optimization=0
apc.num_files_hint=15360
apc.user_entries_hint=15360
apc.ttl=0
apc.user_ttl=0
apc.gc_ttl=3600
apc.cache_by_default=1
apc.slam_defense=0
apc.use_request_time=1
apc.mmap_file_mask=/dev/zero
apc.file_update_protection=2
apc.enable_cli=0
apc.max_file_size=10M
apc.stat=1
apc.write_lock=1
apc.report_autofilter=0
apc.include_once_override=0
apc.rfc1867=0
apc.rfc1867_prefix="upload_"
apc.rfc1867_name="APC_UPLOAD_PROGRESS"
apc.rfc1867_freq=0
apc.localcache=1
apc.localcache.size=256
apc.coredump_unmap=0
apc.stat_ctime=0
apc.canonicalize=1
apc.lazy_functions=1
apc.lazy_classes=1

 

This has been pulled from a multitude of sources around the web and is optimized for a machine with 12GB of RAM.

One issue with Debian installs is that by default, only 32MB of RAM is available as shared memory. This will present a problem if the config calls for 512MB of shared RAM! This needs to be fixed.

First, increase the shared RAM max in shmmax with: echo 2147483648 > /proc/sys/kernel/shmmax

Now, make the change permanent on reboot with: echo “kernel.shmmax=2147483648” >> /etc/sysctl.conf

Restart the nginx and php5-fpm services: service nginx restart && service php5-fpm restart

and go unpack the gzipped apc.php file into your webroot, then load apc.php and see if the configuration looks correct: http://localhost/apc.php

Next let’s look at the nginx config file at /etc/nginx/nginx.conf – it should be pretty standard, and it needs to be configured for your environment, but make sure the following lines are present:

gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_buffers 16 8k; gzip_http_version 1.1; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

 

Now, follow this tutorial on installing memcached:


1. Install memcached on your server.

  • Open the Terminal Window and enter : sudo apt-get install memcached libmemcached-tools

2. Install memcache PHP extension using PECL.

  • PECL is great for installing PHP extensions: sudo apt-get install php5-dev php-pear make
  • After you have installed PECL on your system, open the Terminal Window and enter: sudo pecl install memcache


3. Add memcache.so to php.ini

  • We must instruct PHP to load the extension.
  • You can do this by adding a file named memcache.ini to the configuration directory /etc/php5/conf.d
  • Open the Terminal Window and enter: sudo nano /etc/php5/conf.d/memcache.ini
  • Add the following line to the file and save: extension=memcache.so

If you intend to use memcached with Drupal also add the following line to your php.ini or memcache.ini file and save: memcache.hash_strategy=”consistent”


4. Open firewall port 11211.

  • The default port for the memcached server is TCP port 11211.
  • Configure your firewall to open port 11211 for TCP traffic.

 

5. Configure the memcached allowed memory.

  • All memcached configuration settings can be found in /etc/memcached.conf
  • The default memory setting for memcached is 64 MB.
  • Depending on the amount of RAM available on the server allocate a block of memory to memcached.
  • Open the Terminal Window and enter: sudo nano /etc/memcached.conf
  • Change the following line FROM:
# Start with a cap of 64 megs of memory. It's reasonable, and the daemon default 
# Note that the daemon will grow to this size, but does not start out holding this much
memory -m 64

TO the following by changing the -m 64 to -m 4096 to allow memcached 4 GB of RAM:

# Start with a cap of 64 megs of memory. It's reasonable, and the daemon default
# Note that the daemon will grow to this size, but does not start out holding this much
memory -m 4096

NOTE: Adjust the size in MB according to the memory that you have available. Save the file when done.

 

6. Start the memcached service.

  • Open the Terminal Window and enter: sudo service memcached start
  • OR on older systems: sudo /etc/init.d/memcached start

 

7. Restart Apache / Nginx.

  • Open the Terminal Window and enter: sudo service apache2 restart && sudo service nginx restart
  • OR on older systems: sudo /etc/init.d/apache2 restart && /etc/init.d/nginx restart

 

8. Check to see if memcached server is active and listening on port 11211.

  • Open the Terminal Window and enter: netstat -tap | grep memcached

 

9. Check the status and stats with memstat tool

  • Part of the memcached package is a handy tool called memstat.
  • You need to specify the host IP and port. In this case the host IP is 127.0.0.1 and the port 1211.
  • Open the Terminal Window and enter: memstat 127.0.0.1:11211

 

10. Activate the Drupal memcached module.

  • Install the Drupal Memcache module and activate. For more complete instructions visit the Drupal Memcache Documentation
  • Edit settings.php in your Drupal installation to include memcache.inc
  • For Drupal 6, edit the settings.php file and add the following: $conf[‘cache_inc’] =’sites/all/modules/memcache/memcache.inc’;
  • For Drupal 7, edit the settings.php file and add the following:
$conf['cache_backends'][] = 'sites/all/modules/memcache/memcache.inc';
$conf['cache_default_class'] = 'MemCacheDrupal';
$conf['memcache_key_prefix'] = 'something_unique';
$conf['cache_class_cache_form'] = 'DrupalDatabaseCache';

 * note : Replace the “something_unique” in the last line with your own unique memcache key prefix. The memcache_key_prefix is also needed for both Drupal 6 & 7 in a multi-site environment if you would like to use memcached for more than one Drupal installation on the same server.

Lastly, verify that your php.ini files are correct. The two config files for the web, /etc/php5/cgi/php.ini and /etc/php5/fpm/php.ini, need to have the following extensions:

extension=apc.so
extension=memcache.so
memcache.hash_strategy="consistent"

 

The command-line interface /etc/php5/cli/php.ini file needs at least the memcache extension so that Drush will function correctly.

extension=memcache.so

 

BONUS: You may want to look into tweaking your MySQL configuration as well. Here is a sample:

 [client]
 port            = 3306
 socket          = /var/run/mysqld/mysqld.sock[mysqld_safe]
 socket          = /var/run/mysqld/mysqld.sock
 nice            = 0[mysqld]
 user            = mysql
 pid-file        = /var/run/mysqld/mysqld.pid
 socket          = /var/run/mysqld/mysqld.sock
 port            = 3306
 basedir         = /usr
 datadir         = /var/lib/mysql
 tmpdir          = /tmp
 language        = /usr/share/mysql/english
 skip-external-locking
 old_passwords   = 1
 bind-address            = 127.0.0.1
 key_buffer              = 16M
 key_buffer_size         = 32M
 max_allowed_packet      = 16M
 thread_stack            = 128K
 thread_cache_size       = 64
 query_cache_limit       = 8M
 query_cache_size        = 64M
 query_cache_type        = 1
 join_buffer_size        = 512K
 max_connections         = 150
 log_slow_queries        = /var/log/mysql/mysql-slow.log
 skip-bdb
 skip-innodb[mysqldump]
 quick
 quote-names
 max_allowed_packet      = 16M[mysql]
 #no-auto-rehash # faster start of mysql but no tab completition[isamchk]
 key_buffer              = 16M

 

Adam Behnke

Adam Behnke

Adam is a mobile/web developer for Accella who has been developing telecom and web applications since the mid-90's, before the dot-com bust. With a heavy telecom background, Adam can speak fluently in 3GPP, ASN.1, SS7, and SIGTRAN as well.

5 Responses

  1. Hi there would you mind sharing which blog platform you’re working with? I’m planning to start my
    own blog soon but I’m having a difficult time making a decision between BlogEngine/Wordpress/B2evolution and Drupal. The reason I ask is because your design seems different then most blogs and I’m looking for something completely unique.

  2. It’s interesting to note that the php-apc version I installed using the most up to date debian squeeze x64 with nginx and php5-fpm does NOT like to see

    apc.shm_size=64M

    in apc.ini, so indeed, the M needs to be gone, as in your example config.

    apc.shm_size=64

    By the way, 512 MB is absurd for APC. I run a reasonably busy server with many busy sites/weblogs and webmail (most are php-based) and its shm never reaches beyond 48 M.

  3. Myrtis, this site is created with WordPress. I highly recommend it for folks who are just getting the hang of the “blogging thing”. Drupal has much more power from a developer perspective, but the learning curve is steep.

    Julius, you are absolutely correct that 512MB is absurd for APC. This article was written about a trial run configuration for an extremely busy site, so we wanted to be absolutely sure that we would not run out of space. In practice, even with that busy site, I’ve not seen the usage go above 100MB.

  4. Hi Adam,

    Just wondering if APC + Memcached can run at the same time. If yes, there are modules on drupal that utilizes the APC and Memcached. So do you use only Memcached module? How about APC? Just install it and do nothing in Drupal?

    Please clarify this to me.

    Thanks

  5. Yes, APC and Memcached can run at the same time. APC is a PHP command cache, whereas Memcached is an-in memory cache (rather than hard drive) cache utilized by Drupal. There is no APC module for Drupal — you just install it.

Leave a Reply

Your email address will not be published. Required fields are marked *

Categories

Search

Recent Posts

Most Common Tags