Using Redis for Doctrine Caching in Symfony2

Redis is an open source key-value cache and storage, which designed to be very fast since it uses in-memory datasets. Of course, you can persist your data by dumping it to the disk if you need it. Redis supports different data structures such as strings, lists, sets/sorted sets, hashes; atomic operations on these types, master-slave asynchronous replication, transactions, etc.

If you are using Doctrine with Symfony, Redis is a great tool to be used for caching, which is very easy to setup and it can drastically improve performance of your application.

Doctrine supports 3 types of caching:

  • Metadata Cache – cache annotations, table names, columns, relations.
  • Query Cache – cache the transformation of a DQL query to its SQL counterpart.
  • Result Cache – cache the results of the queries.

So let’s try to configure Doctrine to work with Redis for caching.

Redis installation

If you under OS X, you can use homebrew:


1 2 3 4
brew update
brew install redis 
# start server 
redis-server 

For Ubuntu, you need to build it from sources:


1 2 3 4 5 6 7 8 9
wget http://download.redis.io/releases/redis-2.8.19.tar.gz
 tar xzf redis-2.8.19.tar.gz 
cd redis-2.8.19 
make sudo 
make install 
cd utils 
sudo ./install_server.sh 
# start server 
service redis_6379 start 

If you’ve used default config, now redis is running on your machine on 6379 port.

SncRedisBundle bundle

We will use this great bundle to work with Redis inside our application. Note, that SncRedisBundle bundle can work with both Predis orPHPRedis libraries to communicate with Redis, so it’s your choice which one to use. I went with Predis.

Let’s add bundle itself and Predis as a needed dependency inside our composer.json and run composer install after that:


1 2
"predis/predis": "0.8.x-dev",
 "snc/redis-bundle": "1.1.x-dev" 

Activate bundle in app/AppKernel.php:

<?php
public function registerBundles()
{
    $bundles = array(
        // ...
        new Snc\RedisBundle\SncRedisBundle(),
        // ...
    );
    ...
}

Configure Redis client itself and set it to be used for Doctrine in app/config/config.yml

snc_redis:
    # configure predis as client
    clients:
        default:
            type: predis
            alias: default
            dsn: redis://localhost
        doctrine:
            type: predis
            alias: doctrine
            dsn: redis://localhost
    # configure doctrine caching
    doctrine:
        metadata_cache:
            client: doctrine
            entity_manager: default
            document_manager: default
        result_cache:
            client: doctrine
            entity_manager: [default]
        query_cache:
            client: doctrine
            entity_manager: default

In the same file, we need to enable metadata and query caching for Doctrine:

doctrine:
    dbal:
        driver:   %database_driver%
        host:     %database_host%
        port:     %database_port%
        dbname:   %database_name%
        user:     %database_user%
        password: %database_password%
        charset:  UTF8
    orm:
        auto_generate_proxy_classes: %kernel.debug%
        auto_mapping: true
        # enable metadata caching
        metadata_cache_driver: redis
        # enable query caching
        query_cache_driver: redis

Result cache

In the most cases, you don’t need cache results from all of your queries, so let’s see how you can enable result cache for some individual one only. The best place to do it is inside of an entity repository class.

Let’s say we have Country entity with respective repository. In this repository, we have a method to find active countries and return a list with 3 items sorted by country’s sort field. Let’s add caching for the results of this method.

# use needed classes
use Snc\RedisBundle\Doctrine\Cache\RedisCache;
use Predis\Client;


class CountryRepository extends EntityRepository
{
  ...
    public function findMostPopular($limit = 3)
    {
      # init predis client
      $predis = new RedisCache();
      $predis->setRedis(new Client());
      # define cache lifetime period as 1 hour in seconds
      $cache_lifetime = 3600;


        return $this->getEntityManager()
            ->createQuery('SELECT c FROM AcmeBundle:Country c '
                . 'WHERE c.active = 1 ORDER BY c.sort DESC')
            ->setMaxResults($limit)
            # pass predis object as driver
            ->setResultCacheDriver($predis)
            # set cache lifetime
            ->setResultCacheLifetime($cache_lifetime)
            ->getResult();
    }  
  ...
}

That’s all. Now Doctrine will get countries data from the database for the first time, cache it in Redis for 1 hour and update it again after expiration.

Checking Doctrine cached values

Redis comes with redis-cli tool, which can be used to check cached values by running command KEYS *:

127.0.0.1:6379> KEYS *
1) "[AcmeBundle\\Entity\\Country$CLASSMETADATA][1]"
2) "DoctrineNamespaceCacheKey[]"
3) "[8358af94b8825e6f9413ed57f4ebc723][1]"
4) "[d16019c7f320a7d2389d8f279876190cdef26da4][1]"

To see what contains individual cache entity, you can run GET key_string command.

Another great thing to check Doctrine cache is Symfony Profiler toolbar.

你可能感兴趣的:(Using Redis for Doctrine Caching in Symfony2)