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.sodate.timezone='America/Los_Angeles'apc.enabled=1apc.shm_segments=1apc.shm_size=512apc.optimization=0apc.num_files_hint=15360apc.user_entries_hint=15360apc.ttl=0apc.user_ttl=0apc.gc_ttl=3600apc.cache_by_default=1apc.slam_defense=0apc.use_request_time=1apc.mmap_file_mask=/dev/zeroapc.file_update_protection=2apc.enable_cli=0apc.max_file_size=10Mapc.stat=1apc.write_lock=1apc.report_autofilter=0apc.include_once_override=0apc.rfc1867=0apc.rfc1867_prefix="upload_"apc.rfc1867_name="APC_UPLOAD_PROGRESS"apc.rfc1867_freq=0apc.localcache=1apc.localcache.size=256apc.coredump_unmap=0apc.stat_ctime=0apc.canonicalize=1apc.lazy_functions=1apc.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
5 Responses
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.
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.
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.
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
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.