Skip to content

Commit 380fc45

Browse files
[Cache] improve perf when using RedisCluster by reducing roundtrips to the servers
1 parent 4e4b216 commit 380fc45

File tree

1 file changed

+31
-31
lines changed

1 file changed

+31
-31
lines changed

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

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,7 @@ private function init($redisClient, $namespace, $defaultLifetime, ?MarshallerInt
5353
if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) {
5454
throw new InvalidArgumentException(sprintf('RedisAdapter namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0]));
5555
}
56-
if ($redisClient instanceof \RedisCluster) {
57-
$this->enableVersioning();
58-
} elseif (!$redisClient instanceof \Redis && !$redisClient instanceof \RedisArray && !$redisClient instanceof \Predis\Client && !$redisClient instanceof RedisProxy) {
56+
if (!$redisClient instanceof \Redis && !$redisClient instanceof \RedisArray && !$redisClient instanceof \RedisCluster && !$redisClient instanceof \Predis\Client && !$redisClient instanceof RedisProxy) {
5957
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)));
6058
}
6159
$this->redis = $redisClient;
@@ -182,18 +180,21 @@ public static function createConnection($dsn, array $options = array())
182180
*/
183181
protected function doFetch(array $ids)
184182
{
185-
if ($ids) {
186-
$values = $this->pipeline(function () use ($ids) {
187-
foreach ($ids as $id) {
188-
yield 'get' => array($id);
189-
}
190-
});
191-
foreach ($values as $id => $v) {
192-
if ($v) {
193-
yield $id => $this->marshaller->unmarshall($v);
194-
}
183+
if (!$ids) {
184+
return array();
185+
}
186+
187+
$i = -1;
188+
$values = $this->redis->mget($ids);
189+
$result = array();
190+
191+
foreach ($ids as $id) {
192+
if (false !== $v = $values[++$i]) {
193+
$result[$id] = $this->marshaller->unmarshall($v);
195194
}
196195
}
196+
197+
return $result;
197198
}
198199

199200
/**
@@ -209,9 +210,6 @@ protected function doHave($id)
209210
*/
210211
protected function doClear($namespace)
211212
{
212-
// When using a native Redis cluster, clearing the cache is done by versioning in AbstractTrait::clear().
213-
// This means old keys are not really removed until they expire and may need garbage collection.
214-
215213
$cleared = true;
216214
$hosts = array($this->redis);
217215
$evalArgs = array(array($namespace), 0);
@@ -220,21 +218,23 @@ protected function doClear($namespace)
220218
$evalArgs = array(0, $namespace);
221219

222220
$connection = $this->redis->getConnection();
223-
if ($connection instanceof PredisCluster) {
221+
if ($connection instanceof ClusterInterface && $connection instanceof \Traversable) {
224222
$hosts = array();
225223
foreach ($connection as $c) {
226224
$hosts[] = new \Predis\Client($c);
227225
}
228-
} elseif ($connection instanceof RedisCluster) {
229-
return false;
230226
}
231227
} elseif ($this->redis instanceof \RedisArray) {
232228
$hosts = array();
233229
foreach ($this->redis->_hosts() as $host) {
234230
$hosts[] = $this->redis->_instance($host);
235231
}
236232
} elseif ($this->redis instanceof \RedisCluster) {
237-
return false;
233+
$hosts = array();
234+
foreach ($this->redis->_masters() as $host) {
235+
$hosts[] = $h = new \Redis();
236+
$h->connect($host[0], $host[1]);
237+
}
238238
}
239239
foreach ($hosts as $host) {
240240
if (!isset($namespace[0])) {
@@ -261,7 +261,7 @@ protected function doClear($namespace)
261261
$keys = $keys[1];
262262
}
263263
if ($keys) {
264-
$host->del($keys);
264+
$this->redis->del($keys);
265265
}
266266
} while ($cursor = (int) $cursor);
267267
}
@@ -312,7 +312,16 @@ private function pipeline(\Closure $generator)
312312
{
313313
$ids = array();
314314

315-
if ($this->redis instanceof \Predis\Client && !$this->redis->getConnection() instanceof ClusterInterface) {
315+
if ($this->redis instanceof \RedisCluster || ($this->redis instanceof \Predis\Client && $this->redis->getConnection() instanceof RedisCluster)) {
316+
// phpredis & predis don't support pipelining with RedisCluster
317+
// see https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#pipelining
318+
// see https://github.com/nrk/predis/issues/267#issuecomment-123781423
319+
$results = array();
320+
foreach ($generator() as $command => $args) {
321+
$results[] = \call_user_func_array(array($this->redis, $command), $args);
322+
$ids[] = $args[0];
323+
}
324+
} elseif ($this->redis instanceof \Predis\Client) {
316325
$results = $this->redis->pipeline(function ($redis) use ($generator, &$ids) {
317326
foreach ($generator() as $command => $args) {
318327
\call_user_func_array(array($redis, $command), $args);
@@ -336,15 +345,6 @@ private function pipeline(\Closure $generator)
336345
foreach ($results as $k => list($h, $c)) {
337346
$results[$k] = $connections[$h][$c];
338347
}
339-
} elseif ($this->redis instanceof \RedisCluster || ($this->redis instanceof \Predis\Client && $this->redis->getConnection() instanceof ClusterInterface)) {
340-
// phpredis & predis don't support pipelining with RedisCluster
341-
// see https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#pipelining
342-
// see https://github.com/nrk/predis/issues/267#issuecomment-123781423
343-
$results = array();
344-
foreach ($generator() as $command => $args) {
345-
$results[] = \call_user_func_array(array($this->redis, $command), $args);
346-
$ids[] = $args[0];
347-
}
348348
} else {
349349
$this->redis->multi(\Redis::PIPELINE);
350350
foreach ($generator() as $command => $args) {

0 commit comments

Comments
 (0)