具有Doctrine 2二级缓存和Symfony 3.3的多个区域缓存

Nic*_*ick 12 php caching symfony doctrine-orm

在具有中央ElastiCache(redis)集群的多个AWS EC2实例上运行分布式SF3.3应用程序.

每个EC2实例还运行一个本地Redis实例,该实例用于Doctrine元和查询缓存.

该应用程序使用Doctrines二级缓存,从功能的角度来看,它非常有效.但是AWS上的性能很差(900-1200ms页面加载),因为它在我们的许多页面上所需的Country和VatRate实体中加载了400多个缓存调用.

由于这些Country和VatRate实体很少更改,我想通过使用二级缓存中定义的不同区域来利用本地Redis实例和ElastiCache进行结果缓存.这应该可以减少400+缓存调用的延迟问题,因为在单个框页面上运行时,加载次数为100毫秒.阅读文档这一切似乎都是可能的,只是不完全确定如何使用Symfony和PHP-Cache进行配置.

当前配置的一个示例:

应用程序/配置/ 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 ]
Run Code Online (Sandbox Code Playgroud)

SRC /的appbundle /实体/ 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;

    // ...
}
Run Code Online (Sandbox Code Playgroud)

SRC /的appbundle /实体/ 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;

    // ...
}
Run Code Online (Sandbox Code Playgroud)

SRC /的appbundle /实体/ 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;
    // ...
}
Run Code Online (Sandbox Code Playgroud)

尝试配置

应用程序/配置/ 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 ]
Run Code Online (Sandbox Code Playgroud)

SRC /的appbundle /实体/ Country.php

/**
 * @ORM\Table(name = "countries")
 * @ORM\Cache(usage = "READ_ONLY", region = "local")
 */
class Country
{
    // as above
}
Run Code Online (Sandbox Code Playgroud)

SRC /的appbundle /实体/ VatRate.php

/**
 * @ORM\Table(name = "vatRates")
 * @ORM\Cache(usage = "READ_ONLY", region = "local")
 */
class VatRate
{
    // as above
}
Run Code Online (Sandbox Code Playgroud)

SRC /的appbundle /实体/ Order.php

/**
 * @ORM\Table(name = "orders")
 * @ORM\Cache(usage = "NONSTRICT_READ_WRITE", region = "remote")
 */
class Order
{
    // as above
}
Run Code Online (Sandbox Code Playgroud)

结果如何

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,
Run Code Online (Sandbox Code Playgroud)

也不太清楚哪里何去何从,已经从测试工作在这里:https://github.com/doctrine/DoctrineBundle/blob/74b408d0b6b06b9758a4d29116d42f5bfd83daf0/Tests/DependencyInjection/Fixtures/config/yml/orm_second_level_cache.yml但缺乏文档配置这使它更具挑战性!

ori*_*nal -1

您收到的错误消息完全反映了问题的根源。当需要接口实例时,您正在传递DoctrineCacheBridge实例( 的底层类doctrine.orm.default_result_cacheDoctrine\ORM\Cache\Region

            second_level_cache:
                #...
                regions:
                    local:
                        type: service
                        service: "region_service_not_cache_service" # Here is a Region instance expected 
                    remote:
                        type: service
                        service: "region_service_not_cache_service" #Here is a Region instance expected
Run Code Online (Sandbox Code Playgroud)

在之前的配置中,doctrine.orm.default_result_cache缓存服务通过设置设置为默认缓存region_cache_driver\Doctrine\ORM\Cache\DefaultCacheFactory生成DefaultRegionon Flight 的实例(因为没有预先配置)并向它们提供默认缓存。

后一种配置预计具有预先配置的区域,并且可以通过多种方式进行修复。我建议下一个:

dbal:
    # .. params

orm:
    #...
            second_level_cache:
                #...
                regions:
                    local:
                        type: default
                        cache_driver: 
                            type: service
                            id: "doctrine.orm.default_query_cache" # NOTE that this is the service id of your local cache generated by PHP-Cache Bundle
                    remote:
                        type: default
                        cache_driver: 
                            type: service
                            id: "doctrine.orm.default_result_cache" # NOTE that this is the service id of your remote cache generated by PHP-Cache Bundle
Run Code Online (Sandbox Code Playgroud)

在这里,您告诉 Doctrine 在和键下创建 2 个DefaultRegion区域,并将和相应地传递给它们。localremotelocal_cacheremote_cache

最好返回region_cache_driver到以前的值,否则DefaultRegion飞行中生成的 s 将使用array缓存:

            second_level_cache:
                enabled: true
                region_cache_driver: 
                    type: service
                    id: doctrine.orm.default_result_cache
Run Code Online (Sandbox Code Playgroud)