如何在多个 Symfony 实例之间共享应用程序缓存(共享缓存池)?
How to share the application cache between multiple Symfony instances (shared cache pool)?
我的 symfony 应用程序 有多个实例 运行 在单独的 docker 容器中 .
而且我已经配置我的 app.cache
来使用 redis:
framework:
cache:
app: cache.adapter.redis
我也一样prefix_seed
:
framework:
cache:
prefix_seed: 'dev'
结果我进入了这样的redis:
1605259288.470950 [0 172.18.0.28:55044] "MGET" "HnMEIyUlZ+:workers.restart_requested_timestamp"
1605259288.471680 [0 172.18.0.28:55044] "SET" "HnMEIyUlZ+:workers.restart_requested_timestamp" "d:1605259288.471522;"
1605259314.483389 [0 172.18.0.29:42884] "MGET" "8TMgMtnOAG:workers.restart_requested_timestamp"
正如您从上面看到的那样,2 个不同的实例正试图通过相同的键从 Redis 中获取值 workers.restart_requested_timestamp
,但是即使使用相同的 prefix_seed
.[=18=,前缀也不同]
在这个例子中,我使用的是信使组件,我想通过 stop-workers
命令(通过共享的 redis)在任何地方停止工作人员 运行。不过一般来说这跟缓存配置有关
如何克服这个问题并告诉两个应用程序使用同一个池?这是什么配置?
在 symfony 框架包的配置定义中,您可以找到:
private function addCacheSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('cache')
->info('Cache configuration')
->addDefaultsIfNotSet()
->fixXmlConfig('pool')
->children()
->scalarNode('prefix_seed')
->info('Used to namespace cache keys when using several apps with the same shared backend')
->example('my-application-name')
->end()
...
prefix_seed 正是您要找的。
在此处查看文档:https://symfony.com/doc/current/reference/configuration/framework.html#prefix-seed
终于,我找到了解决办法。有一个选项可以创建您自己的带有映射适配器的缓存池。这里的主要技巧是将带有 namespace
的标签传递给您的适配器(名称也应该是 cache.pool
):
framework:
cache:
pools:
cache.redis_shared_pool:
adapter: app.cache_shared_redis_adapter
services:
app.cache_shared_redis_adapter:
parent: 'cache.adapter.redis'
tags:
- { name: 'cache.pool', namespace: 'shared' }
就是这样!你在 redis 中的所有键都将以 shared:
为前缀。现在您应该将 @cache.redis_shared_pool
传递给您想要的任何服务。
至于信使组件,我们应该覆盖服务(但我不确定这是最好的方法):
console.command.messenger_stop_workers:
class: Symfony\Component\Messenger\Command\StopWorkersCommand
arguments:
$restartSignalCachePool: "@cache.redis_shared_pool"
messenger.listener.stop_worker_on_restart_signal_listener:
class: Symfony\Component\Messenger\EventListener\StopWorkerOnRestartSignalListener
arguments:
$cachePool: "@cache.redis_shared_pool"
我的 symfony 应用程序 有多个实例 运行 在单独的 docker 容器中 .
而且我已经配置我的 app.cache
来使用 redis:
framework:
cache:
app: cache.adapter.redis
我也一样prefix_seed
:
framework:
cache:
prefix_seed: 'dev'
结果我进入了这样的redis:
1605259288.470950 [0 172.18.0.28:55044] "MGET" "HnMEIyUlZ+:workers.restart_requested_timestamp"
1605259288.471680 [0 172.18.0.28:55044] "SET" "HnMEIyUlZ+:workers.restart_requested_timestamp" "d:1605259288.471522;"
1605259314.483389 [0 172.18.0.29:42884] "MGET" "8TMgMtnOAG:workers.restart_requested_timestamp"
正如您从上面看到的那样,2 个不同的实例正试图通过相同的键从 Redis 中获取值 workers.restart_requested_timestamp
,但是即使使用相同的 prefix_seed
.[=18=,前缀也不同]
在这个例子中,我使用的是信使组件,我想通过 stop-workers
命令(通过共享的 redis)在任何地方停止工作人员 运行。不过一般来说这跟缓存配置有关
如何克服这个问题并告诉两个应用程序使用同一个池?这是什么配置?
在 symfony 框架包的配置定义中,您可以找到:
private function addCacheSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('cache')
->info('Cache configuration')
->addDefaultsIfNotSet()
->fixXmlConfig('pool')
->children()
->scalarNode('prefix_seed')
->info('Used to namespace cache keys when using several apps with the same shared backend')
->example('my-application-name')
->end()
...
prefix_seed 正是您要找的。 在此处查看文档:https://symfony.com/doc/current/reference/configuration/framework.html#prefix-seed
终于,我找到了解决办法。有一个选项可以创建您自己的带有映射适配器的缓存池。这里的主要技巧是将带有 namespace
的标签传递给您的适配器(名称也应该是 cache.pool
):
framework:
cache:
pools:
cache.redis_shared_pool:
adapter: app.cache_shared_redis_adapter
services:
app.cache_shared_redis_adapter:
parent: 'cache.adapter.redis'
tags:
- { name: 'cache.pool', namespace: 'shared' }
就是这样!你在 redis 中的所有键都将以 shared:
为前缀。现在您应该将 @cache.redis_shared_pool
传递给您想要的任何服务。
至于信使组件,我们应该覆盖服务(但我不确定这是最好的方法):
console.command.messenger_stop_workers:
class: Symfony\Component\Messenger\Command\StopWorkersCommand
arguments:
$restartSignalCachePool: "@cache.redis_shared_pool"
messenger.listener.stop_worker_on_restart_signal_listener:
class: Symfony\Component\Messenger\EventListener\StopWorkerOnRestartSignalListener
arguments:
$cachePool: "@cache.redis_shared_pool"