Я запустил кластер Redis в AWS с двумя узлами: основным и репликой. Кластер имеет две точки входа: основную точку входа и точку входа читателя.
В моем приложении Symfony я использую основную точку входа в конфигурации .env.
REDIS_HOST=xxx-redis.yyy.ng.0001.zone.cache.amazonaws.com
REDIS_PORT=6379
и конфигурацию кеша в рамках framework.cache в кэше.yaml следующим образом:
app: cache.adapter.redis
default_redis_provider: redis://%env(REDIS_HOST)%:%env(int:REDIS_PORT)%
Приложение работает хорошо, кеш используется, но я заметил, что используется только основной узел, реплика не регистрирует никаких попаданий.
Я много искал в Google примеры конфигурации о том, как добавить точку входа только для чтения в конфигурацию Symfony Redis, но ничего не нашел.
Итак, я надеюсь, что у кого-то была такая же проблема и он нашел решение. Я думаю, может быть, стоит сделать специальный адаптер кэша или что-то в этом роде?






Чтобы использовать репликацию, вы можете предоставить несколько URL-адресов внутри Redis DNS, как указано в этой документации . Используйте AWS, предоставляя основные конечные точки Primary и Reader, а не конечные точки отдельных узлов. Итак, вам нужно только 2 URL-адреса, нет
default_redis_provider: 'redis:?host[xxx-redis.yyy.ng.0001.zone.cache.amazonaws.com]&host[xxx-redis.yyy-ro.ng.0001.zone.cache.amazonaws.com]'
Обратите внимание, что после // нет redis:. Всю эту информацию можно прочитать и отладить внутри /vendor/symfony/cache/Traits/RedisTrait.php метода createConnection.
Теперь самое интересное при использовании пакета Predis:
Для этого необходимо добавить ?role=master и, возможно, ?role=slave в URL-адрес хоста.
Итак, ваша конфигурация YAML будет выглядеть так:
default_redis_provider: 'redis:?host[xxx-redis.amazonaws.com%3Frole%3Dmaster]&host[xxx-redis-ro.amazonaws.com%3Frole%3Dslave]'
%host[xxx-redis.amazonaws.com][role]=master>-, к параметрам будут добавлены пробелы:default_redis_provider: >-
?host[xxx-redis.amazonaws.com][role]=master
&host[xxx-redis-ro.amazonaws.com][role]=slave
становится ?host[xxx-redis.amazonaws.com][role]=master &host[xxx-redis-ro.amazonaws.com][role]=slave
Для этого я сделал собственную реализацию RedisAdapter:
framework:
cache:
prefix_seed: '%env(ENVIRONMENT)%'
pools:
external.cache:
adapter: cache.adapter.redis_tag_aware
provider: App\Component\Cache\Adapter\RedisAdapter
services:
App\Component\Cache\Adapter\RedisAdapter:
factory: [null, 'createReplicaConnection']
arguments:
$primaryHost: '%app.cache.redis.host.primary%'
$readerHost: '%app.cache.redis.host.reader%'
use Predis\Client;
use Symfony\Component\Cache\Adapter\RedisAdapter as BaseRedisAdapter;
class RedisAdapter extends BaseRedisAdapter
{
public static function createReplicaConnection(
string|array $primaryHost,
null|string|array $readerHost = null,
array $options = [],
): \Redis|\RedisArray|\RedisCluster|ClientInterface|Relay {
$data = [
'host' => [],
'class' => Client::class,
'replication' => 'predis',
];
$primaryHost = array_merge(
['role' => 'master', 'alias' => 'primary'],
is_string($primaryHost) ? ['host' => $primaryHost] : $primaryHost,
);
$data['host'][$primaryHost['host']] = $primaryHost;
if ($readerHost !== null) {
$readerHost = array_merge(
['role' => 'slave', 'alias' => 'reader'],
is_string($readerHost) ? ['host' => $readerHost] : $readerHost,
);
$data['host'][$readerHost['host']] = $readerHost;
}
return static::createConnection('redis:?' . http_build_query($data), $options);
}
У Symfony 7.1 проблемы с Predis: https://github.com/symfony/symfony/issues/49238