Symfony meets APC (Alternative PHP Cache)
Up to last week I was exclusively an XCache user if we talk about PHP accelerators. Recently I needed to use APC with a symfony application. As symfony offers nice APC integration it went quite smooth.
Note that just enabling PHP accelerator (any) improves performance because of the opcode caching. That's why it should always be used on the production environment. Most of accelerators also offer API which enables us to cache anything.
PHP Accelerators in symfony
Taking advantage of the most popular accelerators is really easy in symfony. We are able to change caching strategies for several factories (view, internationalization, routing). We can also cache Doctrine's DQL queries and results.
Symfony not only offers APC support with sfAPCCache class but there are also drivers for XCache (sfXCacheCache), EAccelerator (sfEacceleratorCache), memcache (sfMemcacheCache) and SQLite (sfSQLiteCache). We can also quite easily implement our own driver by extending sfCache class.
This short tutorial could be also used for any other accelerator. It's just a matter of replacing sfAPCCache/Doctrine_Query_Cache with appropriate classes.
Enabling APC in Factories
All caching strategies are set to sfFileCache by default. We are able to change the settings for routing, view and i18n in a factory file (i.e. apps/frontend/config/factories.yml):
all:
routing:
class: sfPatternRouting
param:
generate_shortest_url: true
extra_parameters_as_query_string: true
cache:
class: sfAPCCache
param:
automatic_cleaning_factor: 0
lifetime: 31556926
view_cache:
class: sfAPCCache
i18n:
param:
cache:
class: sfAPCCache
param:
automatic_cleaning_factor: 0
lifetime: 31556926From now on our routing, view cache and translations will be stored in a memory instead of a hard drive. This way symfony makes a lot less disk operations (which are slow).
Enabling DQL and Result Cache in Doctrine
Enabling query cache in Doctrine is a quite safe operation. As long as we use prepared statements and don't create queries by string concatenation we don't have to worry. I think query cache can be enabled in most well written projects.
In symfony Doctrine is configured in configureDoctrine() method of the project configuration class (config/ProjectConfiguration.class.php). Enabling query cache is a matter of setting ATTR_QUERY_CACHE attribute:
/**
* @param Doctrine_Manager $manager
* @return null
*/
public function configureDoctrine(Doctrine_Manager $manager)
{
$manager->setAttribute(Doctrine_Core::ATTR_QUERY_CACHE, new Doctrine_Cache_Apc());
}Enabling result cache might be tricky. It really depends on the project. Various result sets could have different life times. Also, result cannot be cached if we work with quickly changing data ("once it's retrieved it's outdated" kind of thing). Enabling result cache for everything in most situations won't be the best solution:
$manager->setAttribute(Doctrine_Core::ATTR_RESULT_CACHE, new Doctrine_Cache_Apc());
It's worth to mention that both query and result caches can be enabled not only on a manager level but also on the connection and query levels:
// Connection level result cache $connection->setAttribute(Doctrine_Core::ATTR_RESULT_CACHE, new Doctrine_Cache_Apc()); // Query level query cache $query = Doctrine_Query::create() ->useQueryCache(new Doctrine_Cache_Apc()); // Query level result cache $query = Doctrine_Query::create() ->useResultCache(new Doctrine_Cache_Apc());
Doctrine's documentation offers detailed description of both query and result caches: Query Cache & Result Cache.
The Future of APC
Long time ago I chose XCache because at that time it was better maintained and there was no performance difference. Now that APC is actively developed and there are plans to include it in PHP core I have to reconsider my decision.
What do you use? Why? Did you run any benchmarks?
Comments
over 2 years ago wrote:This is good stuff. How do you clear the cache in this setup? symfony cc? As I recall the command line PHP can't access the same APC cache that is used by Apache etc., so I would expect that not to work.
over 2 years ago wrote:@Tom you're right. APC cannot share caches between processes. Usually restarting fastcgi does the trick for me (it's automated with capistrano).
over 2 years ago wrote:Nice post, Do you think it's a good idea to cache the partials cache in really large websites? I have 10 huges websites that use the same project and some of them is the same application too. But our production server has just 12gb of memory and normally we use just 6gb, How our sites are dinamic, we can't use actions cache, we just use some partials with cache. We already using APC but without configure in symfony, and I saw that APC are making cache of a lof of symfony's cache, I think we're not taking so much the advantages of apc. Do you think it's a good idea to configure the partial or just the doctrine querys with APC? thank you.
over 2 years ago wrote:@Nei Caching is always tricky. It really depends on your project and I don't think there's a one golden rule here.
I'm not sure how big your cache is but I'd definitely try turning on APC for partial and DQL query caches. Disk operations are often slower than the database lookups.
Remember that in many cases caching everything is not needed. What you usually need is to cache those key, heavily loaded areas of your website.
Sometimes adding more frontend or database servers is a better choice.
You could also try to distribute your caching servers with solutions like memcache(d).
Thanks for a comment!
over 2 years ago wrote:It is a documented bug when clearing apc cache from symfony cc:
http://trac.symfony-project.org/ticket/6572
over 2 years ago wrote:Thanks @Fiz. I didn't know that. I'm not sure if it's ever gonna be fixed though.
about 1 year ago wrote:Hi, I'm just experimenting with these advanced Caches. I use XCache and symfony 1.4.XCache itself is a great boost for php generally (even if APC is a little bit faster). But within symfony I see absolutely no performance boost on any of these caching strategies compared to the normal file cache. There is not even 1 more request per second. Isn't that weird???What are your benchmarks? Do you see any "big boosts" on your server?Thanx Jan
over 2 years ago wrote:http://www.symfony-project.org/more-with-symfony/1_4/en/08-Advanced-Doctrine-Usage#chapter_08_using_doctrine_result_caching
The link above shows that from Doctrine 1.2 we have some controll over query caching. I have not tried it yet, just wanted to add some info to the topic.
about 1 year ago wrote:@Jan at the time I profiled this the server was facing disk issues (I didn't know that at that time) and the performance boost was huge.
In general using APC or XCache limits number of I/O operations as everything is stored in memory (instead on disk). This is especially visible under high load.
Some time ago I experience no performance gain with APC. It was caused by a poor server configuration. Provider installed PHP as a CGI (not FastCGI) and PHP process died after every request. In such case APC cache is also cleared after every request and therefore you don't gain anything. I suppose you might experience something similar with XCache.
about 1 year ago wrote:Hi
Very useful article. I am using symfony with doctrine and facing a problem with APC. I'm in a multi database environment, and if i use APC to cache query or results, it crashes. That's because cache is always taking the latest database definition.
Is it possible to create a cache driver per database definition ?
about 1 year ago wrote:@Arnaud I never used it in such environment. If everything fails you can try caching queries per database connection. Use the connection name as the cache "namespace". Driver doesn't support it but it's fairly easy to extend it.
about 1 year ago wrote:I have tested many things but still don't manage to make it work ! Even insertion straight to the query does not work. It stills take the latest database connection, and it's bad :(
- Write a comment



















