Every application have a bottle neck. It might be a database query, request to an external service, hard drive I/O or an expensive algorithm. Even if the software is running smoothly it might be necessary to optimise in order to handle higher traffic. Significant part of optimisation is caching.
Generally speaking cache can be stored on a hard drive or in RAM. Reading data from RAM is far much faster then from a hard drive. On the other hand hard drive has greater capacity. Usually there is no need to cache terabytes of data therefore 1 to 4GB of RAM should be more than enough.
Memcached is high-performance, distributed memory object caching system. It’s well established and respected software used by the biggest web services. It has very clear API and is super easy in use. The best way to access Memcached from PHP is through the extension.
If you would like to give a try to Memcached the first step would be installing the service with the PHP extension. You will probably notice there is other extension with a very similar name “memcache”. Don’t get confused. It’s similar but not the same.
$ apt-get install memcached $ apt-get install php5-memcached
If you would like to compile the extension you also need memcached headers.
$ apt-get install libmemcached-dev
The extension source expect headers to be in “libmemcached-1.0” directory. You might have to create a symlink.
$ cd /usr/include $ ln -s libmemcached libmemcached-1.0
Once everything is in place you might want to review memcached configuration.
$ vim /etc/memcached.conf
It’s very straight forward file with only few options.
# memcached default config file # 2003 - Jay Bonci # This configuration file is read by the start-memcached script provided as # part of the Debian GNU/Linux distribution. # Run memcached as a daemon. This command is implied, and is not needed for the # daemon to run. See the README.Debian that comes with this package for more # information. -d # Log memcached's output to /var/log/memcached logfile /var/log/memcached.log # Be verbose # -v # Be even more verbose (print client commands as well) # -vv # 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 # Default connection port is 11211 -p 11211 # Run the daemon as root. The start-memcached will default to running as root if no # -u command is present in this config file -u nobody # Specify which IP address to listen on. The default is to listen on all IP addresses # This parameter is one of the only security measures that memcached has, so make sure # it's listening on a firewalled interface. -l 127.0.0.1 # Limit the number of simultaneous incoming connections. The daemon default is 1024 # -c 1024 # Lock down all paged memory. Consult with the README and homepage before you do this # -k # Return error when memory is exhausted (rather than removing items) # -M # Maximize core file limit # -r
The most important setting is memory allocation “-m”. Default value is only 64MB. When changing the value make sure to leave enough memory for operating system. If you fail to do it your OS will start witting to SWAP instead of RAM which will effectively slow everything down.
Writing and reading from the cache is very simple.
addServer('localhost', 11211); $memcached->add('foo', 'Hello Cache', 60); $memcached->add('bar', array('a', 'b', 'c')); print_r( $memcached->get('foo') ); print_r( $memcached->get('bar') );
First added object “foo” will expire in 60 seconds. Second object “bar” has no expiration attached so will persists until service restart. Memcached can also release the object if it runs out of memory.
If you remember memcached was described as “distributed system”. It means that you can easily extend available memory by attaching more nodes. Lets assume you need another 64MB. You can run another memcached on a different server. The only change you have to do in your software is adding another server to the pool.
addServer('localhost', 11211); $memcached ->addServer('192.168.1.55', 11211);
Another cool thing about using memcached with PHP is it can store sessions.
By default PHP sessions are written to a local hard drive. It’s slow and problematic when scaling.
Memcached can be the central point for storing all sessions from all web host behind a load balancer. To achieve that add two lines into php.ini file.
session.save_handler = memcached session.save_path = "localhost:11211"
Caching with memcached is easy and very useful. I strongly recommend to give it a try. Be concision about security. Memcached doesn’t have any access control. It means that if port is exposed to the Internet anybody can connect and read/change data.