Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dacf179

Browse files
nicolas-grekasandrerom
authored andcommitted
[Cache] Fix perf when using RedisCluster by reducing roundtrips to the servers
This is slimmed down version of: #28269 _(many of the fixes here are already part of 3.4)_ Adds: - Test coverage for Predis with RedisCluster - Removes usage of key versioning when on RedisCluster, besides performance aspect of that simplify / aligning clear() handling across cases
1 parent 21d0197 commit dacf179

File tree

2 files changed

+46
-22
lines changed

2 files changed

+46
-22
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Cache\Tests\Adapter;
13+
14+
class PredisRedisClusterAdapterTest extends AbstractRedisAdapterTest
15+
{
16+
public static function setupBeforeClass()
17+
{
18+
if (!$hosts = getenv('REDIS_CLUSTER_HOSTS')) {
19+
self::markTestSkipped('REDIS_CLUSTER_HOSTS env var is not defined.');
20+
}
21+
self::$redis = new \Predis\Client(explode(' ', $hosts), ['cluster' => 'redis']);
22+
}
23+
24+
public static function tearDownAfterClass()
25+
{
26+
self::$redis = null;
27+
}
28+
}

src/Symfony/Component/Cache/Traits/RedisTrait.php

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
namespace Symfony\Component\Cache\Traits;
1313

1414
use Predis\Connection\Aggregate\ClusterInterface;
15-
use Predis\Connection\Aggregate\PredisCluster;
1615
use Predis\Connection\Aggregate\RedisCluster;
1716
use Predis\Connection\Factory;
1817
use Predis\Response\Status;
@@ -48,9 +47,7 @@ private function init($redisClient, $namespace = '', $defaultLifetime = 0)
4847
if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) {
4948
throw new InvalidArgumentException(sprintf('RedisAdapter namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0]));
5049
}
51-
if ($redisClient instanceof \RedisCluster) {
52-
$this->enableVersioning();
53-
} elseif (!$redisClient instanceof \Redis && !$redisClient instanceof \RedisArray && !$redisClient instanceof \Predis\Client && !$redisClient instanceof RedisProxy) {
50+
if (!$redisClient instanceof \Redis && !$redisClient instanceof \RedisArray && !$redisClient instanceof \RedisCluster && !$redisClient instanceof \Predis\Client && !$redisClient instanceof RedisProxy) {
5451
throw new InvalidArgumentException(sprintf('%s() expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\Client, %s given', __METHOD__, \is_object($redisClient) ? \get_class($redisClient) : \gettype($redisClient)));
5552
}
5653
$this->redis = $redisClient;
@@ -207,9 +204,6 @@ protected function doHave($id)
207204
*/
208205
protected function doClear($namespace)
209206
{
210-
// When using a native Redis cluster, clearing the cache is done by versioning in AbstractTrait::clear().
211-
// This means old keys are not really removed until they expire and may need garbage collection.
212-
213207
$cleared = true;
214208
$hosts = [$this->redis];
215209
$evalArgs = [[$namespace], 0];
@@ -218,21 +212,23 @@ protected function doClear($namespace)
218212
$evalArgs = [0, $namespace];
219213

220214
$connection = $this->redis->getConnection();
221-
if ($connection instanceof PredisCluster) {
215+
if ($connection instanceof ClusterInterface && $connection instanceof \Traversable) {
222216
$hosts = [];
223217
foreach ($connection as $c) {
224218
$hosts[] = new \Predis\Client($c);
225219
}
226-
} elseif ($connection instanceof RedisCluster) {
227-
return false;
228220
}
229221
} elseif ($this->redis instanceof \RedisArray) {
230222
$hosts = [];
231223
foreach ($this->redis->_hosts() as $host) {
232224
$hosts[] = $this->redis->_instance($host);
233225
}
234226
} elseif ($this->redis instanceof \RedisCluster) {
235-
return false;
227+
$hosts = [];
228+
foreach ($this->redis->_masters() as $host) {
229+
$hosts[] = $h = new \Redis();
230+
$h->connect($host[0], $host[1]);
231+
}
236232
}
237233
foreach ($hosts as $host) {
238234
if (!isset($namespace[0])) {
@@ -259,7 +255,7 @@ protected function doClear($namespace)
259255
$keys = $keys[1];
260256
}
261257
if ($keys) {
262-
$host->del($keys);
258+
$this->doDelete($keys);
263259
}
264260
} while ($cursor = (int) $cursor);
265261
}
@@ -331,7 +327,16 @@ private function pipeline(\Closure $generator)
331327
{
332328
$ids = [];
333329

334-
if ($this->redis instanceof \Predis\Client && !$this->redis->getConnection() instanceof ClusterInterface) {
330+
if ($this->redis instanceof \RedisCluster || ($this->redis instanceof \Predis\Client && $this->redis->getConnection() instanceof RedisCluster)) {
331+
// phpredis & predis don't support pipelining with RedisCluster
332+
// see https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#pipelining
333+
// see https://github.com/nrk/predis/issues/267#issuecomment-123781423
334+
$results = [];
335+
foreach ($generator() as $command => $args) {
336+
$results[] = \call_user_func_array([$this->redis, $command], $args);
337+
$ids[] = $args[0];
338+
}
339+
} elseif ($this->redis instanceof \Predis\Client) {
335340
$results = $this->redis->pipeline(function ($redis) use ($generator, &$ids) {
336341
foreach ($generator() as $command => $args) {
337342
\call_user_func_array([$redis, $command], $args);
@@ -355,15 +360,6 @@ private function pipeline(\Closure $generator)
355360
foreach ($results as $k => list($h, $c)) {
356361
$results[$k] = $connections[$h][$c];
357362
}
358-
} elseif ($this->redis instanceof \RedisCluster || ($this->redis instanceof \Predis\Client && $this->redis->getConnection() instanceof ClusterInterface)) {
359-
// phpredis & predis don't support pipelining with RedisCluster
360-
// see https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#pipelining
361-
// see https://github.com/nrk/predis/issues/267#issuecomment-123781423
362-
$results = [];
363-
foreach ($generator() as $command => $args) {
364-
$results[] = \call_user_func_array([$this->redis, $command], $args);
365-
$ids[] = $args[0];
366-
}
367363
} else {
368364
$this->redis->multi(\Redis::PIPELINE);
369365
foreach ($generator() as $command => $args) {

0 commit comments

Comments
 (0)