Have a distributed SF3.3 application running on multiple AWS EC2 instances with a central ElastiCache (redis) cluster.
Each EC2 instance also runs a local Redis instance which is used for Doctrine meta and query caching.
This application utilises Doctrines Second Level Cache, which works very well from a functional point of view. But performance is poor (900-1200ms page loads) on AWS due to the 400+ cache calls it makes to load in our Country and VatRate entities required on many of our pages.
As these Country and VatRate entities change rarely I'd like to utilise both the local Redis instance and ElastiCache for result caching by using different regions defined in the second level cache. This should reduce the latency problem with the 400+ cache calls as when running on a single box page loads are sub 100ms. Reading the documentation this all seems to be possible, just not entirely sure how to configure it with Symfony and PHP-Cache.
An example of the current configuration:
app/config/config.yml
doctrine:
dbal:
# .. params
orm:
auto_generate_proxy_classes: "%kernel.debug%"
entity_managers:
default:
auto_mapping: true
second_level_cache:
enabled: true
region_cache_driver:
type: service
id: doctrine.orm.default_result_cache
cache_adapter:
providers:
meta: # Used for version specific
factory: 'cache.factory.redis'
options:
host: 'localhost'
port: '%redis_local.port%'
pool_namespace: "meta_%hash%"
result: # Used for result data
factory: 'cache.factory.redis'
options:
host: '%redis_result.host%'
port: '%redis_result.port%'
pool_namespace: result
cache:
doctrine:
enabled: true
use_tagging: true
metadata:
service_id: 'cache.provider.meta'
entity_managers: [ default ]
query:
service_id: 'cache.provider.meta'
entity_managers: [ default ]
result:
service_id: 'cache.provider.result'
entity_managers: [ default ]
src/AppBundle/Entity/Country.php
/**
* @ORM\Table(name = "countries")
* @ORM\Cache(usage = "READ_ONLY")
*/
class Country
{
// ...
/**
* @var VatRate
*
* @ORM\OneToMany(targetEntity = "VatRate", mappedBy = "country")
* @ORM\Cache("NONSTRICT_READ_WRITE")
*/
private $vatRates;
// ...
}
src/AppBundle/Entity/VatRate.php
/**
* @ORM\Table(name = "vatRates")
* @ORM\Cache(usage = "READ_ONLY")
*/
class VatRate
{
// ...
/**
* @var Country
*
* @ORM\ManyToOne(targetEntity = "Country", inversedBy = "vatRates")
* @ORM\JoinColumn(name = "countryId", referencedColumnName = "countryId")
*/
private $country;
// ...
}
src/AppBundle/Entity/Order.php
/**
* @ORM\Table(name = "orders")
* @ORM\Cache(usage = "NONSTRICT_READ_WRITE")
*/
class Order
{
// ...
/**
* @var Country
*
* @ORM\ManyToOne(targetEntity = "Country")
* @ORM\JoinColumn(name = "countryId", referencedColumnName = "countryId")
*/
private $country;
// ...
}
Attempted Configuration
app/config/config.yml
doctrine:
dbal:
# .. params
orm:
auto_generate_proxy_classes: "%kernel.debug%"
entity_managers:
default:
auto_mapping: true
second_level_cache:
enabled: true
region_cache_driver: array
regions:
local:
type: service
service: "doctrine.orm.default_result_cache" # TODO: needs to be local redis
remote:
type: service
service: "doctrine.orm.default_result_cache" # TODO: needs to be remote redis
cache_adapter:
providers:
meta: # Used for version specific
factory: 'cache.factory.redis'
options:
host: 'localhost'
port: '%redis_local.port%'
pool_namespace: "meta_%hash%"
result: # Used for result data
factory: 'cache.factory.redis'
options:
host: '%redis_result.host%'
port: '%redis_result.port%'
pool_namespace: result
cache:
doctrine:
enabled: true
use_tagging: true
metadata:
service_id: 'cache.provider.meta'
entity_managers: [ default ]
query:
service_id: 'cache.provider.meta'
entity_managers: [ default ]
result:
service_id: 'cache.provider.result'
entity_managers: [ default ]
src/AppBundle/Entity/Country.php
/**
* @ORM\Table(name = "countries")
* @ORM\Cache(usage = "READ_ONLY", region = "local")
*/
class Country
{
// as above
}
src/AppBundle/Entity/VatRate.php
/**
* @ORM\Table(name = "vatRates")
* @ORM\Cache(usage = "READ_ONLY", region = "local")
*/
class VatRate
{
// as above
}
src/AppBundle/Entity/Order.php
/**
* @ORM\Table(name = "orders")
* @ORM\Cache(usage = "NONSTRICT_READ_WRITE", region = "remote")
*/
class Order
{
// as above
}
Which results in
Type error: Argument 1 passed to Doctrine\ORM\Cache\DefaultCacheFactory::setRegion() must be an instance of Doctrine\ORM\Cache\Region, instance of Cache\Bridge\Doctrine\DoctrineCacheBridge given,
Not too sure where to go from here, been working from the tests here: https://github.com/doctrine/DoctrineBundle/blob/74b408d0b6b06b9758a4d29116d42f5bfd83daf0/Tests/DependencyInjection/Fixtures/config/yml/orm_second_level_cache.yml but the lack of documentation for configuring this makes it a little more challenging!