2017-09-27 20 views
9

Có một ứng dụng SF3.3 được phân phối chạy trên nhiều cá thể AWS EC2 với một cụm ElastiCache trung tâm (redis).Nhiều vùng lưu trữ với Doctrine 2 cache cấp hai và Symfony 3.3

Mỗi cá thể EC2 cũng chạy một phiên bản Redis cục bộ được sử dụng cho siêu dữ liệu và truy vấn bộ đệm Doctrine.

Ứng dụng này sử dụng Doctrines Second Level Cache, hoạt động rất tốt từ quan điểm chức năng. Nhưng hiệu suất là tải (900-1200ms trang) kém trên AWS do có hơn 400 cuộc gọi bộ nhớ cache mà nó làm cho tải ở các quốc gia và các thực thể VatRate của chúng tôi được yêu cầu trên nhiều trang của chúng tôi.

Vì các thực thể Quốc gia và VatRate này hiếm khi tôi muốn sử dụng cả phiên bản Redis cục bộ và ElastiCache để lưu trữ kết quả bằng cách sử dụng các vùng khác nhau được xác định trong bộ nhớ cache cấp thứ hai. Điều này sẽ làm giảm vấn đề độ trễ với hơn 400 cuộc gọi bộ nhớ cache như khi chạy trên một trang tải hộp duy nhất là 100ms phụ. Đọc tài liệu này tất cả có vẻ là có thể, chỉ cần không hoàn toàn chắc chắn làm thế nào để cấu hình nó với Symfony và PHP-Cache.

Một ví dụ về cấu hình hiện tại:

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; 
    // ... 
} 

Cấu hình Cố gắng

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 
} 

mà kết quả trong

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, 

Không quá chắc chắn nơi cần đi từ đây, được làm việc từ các bài kiểm tra ở đây: https://github.com/doctrine/DoctrineBundle/blob/74b408d0b6b06b9758a4d29116d42f5bfd83daf0/Tests/DependencyInjection/Fixtures/config/yml/orm_second_level_cache.yml nhưng thiếu tài liệu để định cấu hình điều này làm cho nó khó khăn hơn một chút!

Trả lời

-1

Thông báo lỗi bạn đang phản ánh hoàn toàn gốc của sự cố.Bạn đang đi qua DoctrineCacheBridge trường (lớp cơ bản của doctrine.orm.default_result_cache) khi trường hợp của giao diện Doctrine\ORM\Cache\Region mong đợi:

  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 

Trong cấu hình cũ của bạn dịch vụ doctrine.orm.default_result_cache bộ nhớ cache được thiết lập như bộ nhớ cache mặc định thông qua các thiết lập region_cache_driver. \Doctrine\ORM\Cache\DefaultCacheFactory tạo các phiên bản DefaultRegion trên chuyến bay (vì không có cấu hình nào được định cấu hình trước) và cấp bộ nhớ cache mặc định cho chúng.

Cấu hình thứ hai được mong đợi có các vùng được định cấu hình trước và có thể được sửa một số cách. Tôi đề nghị tiếp theo:

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 

Ở đây bạn nói học thuyết để tạo ra 2 DefaultRegion vùng dưới các phím localremote và vượt qua local_cacheremote_cache cho họ tương ứng.

Và nó tốt hơn để trở region_cache_driver với giá trị cũ khác DefaultRegion s tạo ra trên chuyến bay sẽ sử dụng array cache:

  second_level_cache: 
       enabled: true 
       region_cache_driver: 
        type: service 
        id: doctrine.orm.default_result_cache 
+0

Cảm ơn, sự cố đã cố gắng tạo các dịch vụ đó một cách chính xác. Như đã đề cập trong nhận xét todo của tôi về cấu hình đã cố gắng - app/config/config.yml – Nick

1

Sau khi chơi nhiều xung quanh với các thư viện PHP-Cache, thì rõ ràng từ tìm kiếm trong CacheBundle trình biên dịch sẽ chỉ hỗ trợ một cá thể DoctrineBridge từ cấu hình. https://github.com/php-cache/cache-bundle/blob/master/src/DependencyInjection/Compiler/DoctrineCompilerPass.php

Giải pháp là tạo trình biên dịch của riêng tôi, không đẹp nhưng có vẻ như nó hoạt động.

src/AppBundle/DependencyInjection/biên dịch/DoctrineCompilerPass.php

namespace AppBundle\DependencyInjection\Compiler; 

use Cache\Bridge\Doctrine\DoctrineCacheBridge; 
use Cache\CacheBundle\Factory\DoctrineBridgeFactory; 
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; 
use Symfony\Component\DependencyInjection\ContainerBuilder; 
use Symfony\Component\DependencyInjection\Reference; 

class DoctrineCompilerPass implements CompilerPassInterface 
{ 
    /** @var ContainerBuilder */ 
    private $container; 

    public function process(ContainerBuilder $container) 
    { 
     $this->container = $container; 

     $this->enableDoctrineCache('local'); 
     $this->enableDoctrineCache('remote'); 
    } 

    private function enableDoctrineCache(string $configName) 
    { 
     $typeConfig = [ 
      'entity_managers' => [ 
       'default' 
      ], 
      'use_tagging' => true, 
      'service_id' => 'cache.provider.' . $configName 
     ]; 

     $bridgeServiceId = sprintf('cache.service.doctrine.%s.entity_managers.bridge', $configName); 

     $this->container->register($bridgeServiceId, DoctrineCacheBridge::class) 
      ->setFactory([DoctrineBridgeFactory::class, 'get']) 
      ->addArgument(new Reference($typeConfig['service_id'])) 
      ->addArgument($typeConfig) 
      ->addArgument(['doctrine', $configName]); 
    } 
} 

src/AppBundle/AppBundle.php

use AppBundle\DependencyInjection\Compiler\DoctrineCompilerPass; 
use Symfony\Component\DependencyInjection\ContainerBuilder; 
use Symfony\Component\HttpKernel\Bundle\Bundle; 

class AppBundle extends Bundle 
{ 
    public function build(ContainerBuilder $container) 
    { 
     parent::build($container); 

     $container->addCompilerPass(new DoctrineCompilerPass()); 
    } 
} 

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 
        regions: 
         remote: 
          cache_driver: 
           type: service 
           id: cache.service.doctrine.remote.entity_managers.bridge 
         local: 
          cache_driver: 
           type: service 
           id: cache.service.doctrine.local.entity_managers.bridge 

cache_adapter: 
    providers: 
     local: 
      factory: 'cache.factory.redis' 
      options: 
       host: '%redis_local.host%' 
       port: '%redis_local.port%' 
       pool_namespace: "local_%hash%" 
     remote: 
      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.local' 
      entity_managers: [ default ] 
     query: 
      service_id:   'cache.provider.local' 
      entity_managers: [ default ] 

Trong khi điều này dường như hoạt động ở một mức độ nào đó, có một số mâu thuẫn trong bộ nhớ cache cục bộ cuộc gọi dẫn đến 500 lỗi khi có thể có điều gì đó bị thiếu trong bộ nhớ cache. Nói chung nghĩ rằng tôi đang cố gắng để uốn cong bộ nhớ cache cấp thứ hai nhiều hơn nó được thiết kế để.

Các vấn đề liên quan