Tuesday, June 25, 2013

Using Memcached with Symfony 2 (on CentOS 6)

The biggest problem, that I've been running into for years, is always performance. But sometimes optimizing your code isn't good enough, sometimes because you're depending on external libraries, which you don't want to change.

For one of our customers, I ran into this problem as well, so I had to find a solution. I've already heared about Memcached often, but I never had the time to look into it and I was kinda scared to have to implement it in an already existing application. Afterwards, I found using the basics of memcached was pretty simple, and it boosted my page speed by 50-75%(!), only by caching doctrine queries and results.

A quick Google search found me a bundle that claims to do exactly what I want: the LswMemcacheBundle. LswMemcacheBundle is developed by LeaseWeb, which leverages the power of the PHP 'memcached' extension (not the older 'memcache' PHP extension, the d make a huge difference as explained on http://code.google.com/p/memcached/wiki/PHPClientComparison).

The installation instructions looked quite simple: install memcached, install the memcached extension and add one line to your composer.json. For Debian based systems this is the case, but CentOS 6 has some obstacles in place.

With CentOS 6 there are a couple problems:
  1. The php extension 'memcached' requires libmemcached. Unfortunatly the version of libmemcached in yum is to old to meet the requirements
  2. The php memcached extension can't be installed trough yum, so this has to be installed trough pecl
  3. Installing the php memcached extension trough pecl threw some errors while compiling.

Installing memcached
Installing memcached is the easiest of all
# yum install memcached
# chkconfig memcached on
# service memcached start

Installing libmemcached
Installing libmemcached is pretty simple. First you have to make sure you've got make and gcc-c++ installed.
  1. Download libmemcached from https://launchpad.net/libmemcached/+download to your server (i.e. wget https://launchpad.net/libmemcached/1.0/1.0.17/+download/libmemcached-1.0.17.tar.gz)
  2. Extract the file using 'tar -zxvf libmemcached-1.0.17.tar.gz'
  3. Go into the extracted folder (cd libmemcached-1.0.17)
  4. Run './configure'
  5. Run 'make'
  6. And finally, run 'make install'
Tada, you've installed libmemcached (it wasn't that hard, was it)

Installing the memcached php extension
Before you can install the memcached php extension, make sure you've got the php-devel package installed via yum
  1. Download the latest version of the extension from http://pecl.php.net/package/memcached
  2. Extract the file and go into the directory
  3. We now have to alter one of the source files to allow the code to compile (I found this solution on https://github.com/php-memcached-dev/php-memcached/issues/69)
  4. Open up php_libmemcached_compat.h
  5. Right after '#define PHP_LIBMEMCACHED_COMPAT' add 'typedef const struct memcached_server_st *memcached_server_instance_st;'
  6. Save your file and quit your editor
  7. Now we can compile the code
  8. Run 'phpize'
  9. Run './configure'
  10. Run 'make'
  11. Run 'make install'
  12. All that's left is to enable the module
  13. Create a new file in /etc/php.d/ named memcached.ini and add the line 'extension=memcached.so' to it
  14. Restart apache (/etc/init.d/httpd restart)
You've now installed the memcached extension

Using memcached in Symfony

  1. First edit your AppKernel.php file and add 'new Lsw\MemcacheBundle\LswMemcacheBundle(),' to your bundles array
  2. Next edit your config.yml and add the following lines to the bottom, assuming you're using the default entity manager (this will enable caching for your doctrine queries and your session):
    lsw_memcache:
        session:
            client: default
            prefix: "session_"
            ttl: 7200
        clients:
            default:
                hosts:
                  - { dsn: localhost, port: 11211 }
        doctrine:
            metadata_cache:
                client: default
                entity_manager: default          # the name of your entity_manager connection
                document_manager: default        # the name of your document_manager connection
            result_cache:
                client: default
                entity_manager: [default]        # you may specify multiple entity_managers
                prefix: "result_"                # you may specify a prefix for the entries
            query_cache:
                client: default
                entity_manager: default
    
  3. Add the following line to your composer.json, as part of the require block:  "leaseweb/memcache-bundle": "1.1.*@dev"
  4. Run 'php composer.phar update leaseweb/memcache-bundle'
  5. Enjoy your boosted performance

5 comments:

  1. Don't you also have to modify your repositories to use the result cache? Or will that bundle somehow manage this for you?

    http://docs.doctrine-project.org/en/2.0.x/reference/caching.html#result-cache

    ReplyDelete
    Replies
    1. The bundle does this for you. It's enabled in the config file:

      result_cache:
      client: default
      entity_manager: [default] # you may specify multiple entity_managers
      prefix: "result_" # you may specify a prefix for the entries

      Delete
  2. I have followed the documentation and did the configurations in my sample symfony2 project. But since the scope of my sample project is limited, I am not able to identify whether my project is using memcache or not? As well as whether my results are being fetched from the memcache or not?

    ReplyDelete
  3. Help,

    I followed all the mentioned steps, but i'm getting this error

    [Symfony\Component\Config\Definition\Exception\InvalidConfigurationException]
    Unrecognized options "client" under "lsw_memcache.session"

    ReplyDelete
  4. that option isn't avaible anymore. Its called "pool" now. the section "clients" has to be renamed the same to "pools"

    ReplyDelete