aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoeland Jago Douma <rullzer@users.noreply.github.com>2017-04-26 08:27:30 +0200
committerGitHub <noreply@github.com>2017-04-26 08:27:30 +0200
commit752b219970bdcbea390dce3500a60fd87e1bbecc (patch)
tree73a1af4fea03bbaf041d1977a1bf02d749942229
parent527369be9c92d7574dbfbd35ab833e6f6b557ba3 (diff)
parent5da845609dbfa5b0ad53307c382fb665681732d3 (diff)
downloadnextcloud-server-752b219970bdcbea390dce3500a60fd87e1bbecc.tar.gz
nextcloud-server-752b219970bdcbea390dce3500a60fd87e1bbecc.zip
Merge pull request #4061 from nextcloud/downstream-26407
Redis cluster support
-rw-r--r--config/config.sample.php30
-rw-r--r--lib/private/Memcache/Redis.php28
-rw-r--r--lib/private/RedisFactory.php68
3 files changed, 86 insertions, 40 deletions
diff --git a/config/config.sample.php b/config/config.sample.php
index 0fbd3ffce07..84b98550fb0 100644
--- a/config/config.sample.php
+++ b/config/config.sample.php
@@ -1042,19 +1042,43 @@ $CONFIG = array(
'memcache.distributed' => '\OC\Memcache\Memcached',
/**
- * Connection details for redis to use for memory caching.
+ * Connection details for redis to use for memory caching in a single server configuration.
*
* For enhanced security it is recommended to configure Redis
* to require a password. See http://redis.io/topics/security
* for more information.
*/
-'redis' => array(
+'redis' => [
'host' => 'localhost', // can also be a unix domain socket: '/tmp/redis.sock'
'port' => 6379,
'timeout' => 0.0,
'password' => '', // Optional, if not defined no password will be used.
'dbindex' => 0, // Optional, if undefined SELECT will not run and will use Redis Server's default DB Index.
-),
+],
+
+/**
+ * Connection details for a Redis Cluster
+ *
+ * Only for use with Redis Clustering, for Sentinel-based setups use the single
+ * server configuration above, and perform HA on the hostname.
+ *
+ * Redis Cluster support requires the php module phpredis in version 3.0.0 or higher.
+ *
+ * Available failover modes:
+ * - \RedisCluster::FAILOVER_NONE - only send commands to master nodes (default)
+ * - \RedisCluster::FAILOVER_ERROR - failover to slaves for read commands if master is unavailable
+ * - \RedisCluster::FAILOVER_DISTRIBUTE - randomly distribute read commands across master and slaves
+ */
+'redis.cluster' => [
+ 'seeds' => [ // provide some/all of the cluster servers to bootstrap discovery, port required
+ 'localhost:7000',
+ 'localhost:7001'
+ ],
+ 'timeout' => 0.0,
+ 'read_timeout' => 0.0,
+ 'failover_mode' => \RedisCluster::FAILOVER_DISTRIBUTE
+],
+
/**
* Server details for one or more memcached servers to use for memory caching.
diff --git a/lib/private/Memcache/Redis.php b/lib/private/Memcache/Redis.php
index c3184e45856..d423b134f95 100644
--- a/lib/private/Memcache/Redis.php
+++ b/lib/private/Memcache/Redis.php
@@ -49,8 +49,8 @@ class Redis extends Cache implements IMemcacheTTL {
}
public function get($key) {
- $result = self::$cache->get($this->getNamespace() . $key);
- if ($result === false && !self::$cache->exists($this->getNamespace() . $key)) {
+ $result = self::$cache->get($this->getNameSpace() . $key);
+ if ($result === false && !self::$cache->exists($this->getNameSpace() . $key)) {
return null;
} else {
return json_decode($result, true);
@@ -59,18 +59,18 @@ class Redis extends Cache implements IMemcacheTTL {
public function set($key, $value, $ttl = 0) {
if ($ttl > 0) {
- return self::$cache->setex($this->getNamespace() . $key, $ttl, json_encode($value));
+ return self::$cache->setex($this->getNameSpace() . $key, $ttl, json_encode($value));
} else {
- return self::$cache->set($this->getNamespace() . $key, json_encode($value));
+ return self::$cache->set($this->getNameSpace() . $key, json_encode($value));
}
}
public function hasKey($key) {
- return self::$cache->exists($this->getNamespace() . $key);
+ return self::$cache->exists($this->getNameSpace() . $key);
}
public function remove($key) {
- if (self::$cache->delete($this->getNamespace() . $key)) {
+ if (self::$cache->delete($this->getNameSpace() . $key)) {
return true;
} else {
return false;
@@ -78,7 +78,7 @@ class Redis extends Cache implements IMemcacheTTL {
}
public function clear($prefix = '') {
- $prefix = $this->getNamespace() . $prefix . '*';
+ $prefix = $this->getNameSpace() . $prefix . '*';
$it = null;
self::$cache->setOption(\Redis::OPT_SCAN, \Redis::SCAN_RETRY);
while ($keys = self::$cache->scan($it, $prefix)) {
@@ -111,7 +111,7 @@ class Redis extends Cache implements IMemcacheTTL {
* @return int | bool
*/
public function inc($key, $step = 1) {
- return self::$cache->incrBy($this->getNamespace() . $key, $step);
+ return self::$cache->incrBy($this->getNameSpace() . $key, $step);
}
/**
@@ -125,7 +125,7 @@ class Redis extends Cache implements IMemcacheTTL {
if (!$this->hasKey($key)) {
return false;
}
- return self::$cache->decrBy($this->getNamespace() . $key, $step);
+ return self::$cache->decrBy($this->getNameSpace() . $key, $step);
}
/**
@@ -140,10 +140,10 @@ class Redis extends Cache implements IMemcacheTTL {
if (!is_int($new)) {
$new = json_encode($new);
}
- self::$cache->watch($this->getNamespace() . $key);
+ self::$cache->watch($this->getNameSpace() . $key);
if ($this->get($key) === $old) {
$result = self::$cache->multi()
- ->set($this->getNamespace() . $key, $new)
+ ->set($this->getNameSpace() . $key, $new)
->exec();
return ($result === false) ? false : true;
}
@@ -159,10 +159,10 @@ class Redis extends Cache implements IMemcacheTTL {
* @return bool
*/
public function cad($key, $old) {
- self::$cache->watch($this->getNamespace() . $key);
+ self::$cache->watch($this->getNameSpace() . $key);
if ($this->get($key) === $old) {
$result = self::$cache->multi()
- ->del($this->getNamespace() . $key)
+ ->del($this->getNameSpace() . $key)
->exec();
return ($result === false) ? false : true;
}
@@ -171,7 +171,7 @@ class Redis extends Cache implements IMemcacheTTL {
}
public function setTTL($key, $ttl) {
- self::$cache->expire($this->getNamespace() . $key, $ttl);
+ self::$cache->expire($this->getNameSpace() . $key, $ttl);
}
static public function isAvailable() {
diff --git a/lib/private/RedisFactory.php b/lib/private/RedisFactory.php
index 3ba637c4142..701e15325c3 100644
--- a/lib/private/RedisFactory.php
+++ b/lib/private/RedisFactory.php
@@ -39,32 +39,54 @@ class RedisFactory {
}
private function create() {
- $this->instance = new \Redis();
- // TODO allow configuring a RedisArray, see https://github.com/nicolasff/phpredis/blob/master/arrays.markdown#redis-arrays
- $config = $this->config->getValue('redis', array());
- if (isset($config['host'])) {
- $host = $config['host'];
- } else {
- $host = '127.0.0.1';
- }
- if (isset($config['port'])) {
- $port = $config['port'];
- } else {
- $port = 6379;
- }
- if (isset($config['timeout'])) {
- $timeout = $config['timeout'];
+ if ($config = $this->config->getValue('redis.cluster', [])) {
+ if (!class_exists('RedisCluster')) {
+ throw new \Exception('Redis Cluster support is not available');
+ }
+ // cluster config
+ if (isset($config['timeout'])) {
+ $timeout = $config['timeout'];
+ } else {
+ $timeout = null;
+ }
+ if (isset($config['read_timeout'])) {
+ $readTimeout = $config['read_timeout'];
+ } else {
+ $readTimeout = null;
+ }
+ $this->instance = new \RedisCluster(null, $config['seeds'], $timeout, $readTimeout);
+
+ if (isset($config['failover_mode'])) {
+ $this->instance->setOption(\RedisCluster::OPT_SLAVE_FAILOVER, $config['failover_mode']);
+ }
} else {
- $timeout = 0.0; // unlimited
- }
- $this->instance->connect($host, $port, $timeout);
- if (isset($config['password']) && $config['password'] !== '') {
- $this->instance->auth($config['password']);
- }
+ $this->instance = new \Redis();
+ $config = $this->config->getValue('redis', []);
+ if (isset($config['host'])) {
+ $host = $config['host'];
+ } else {
+ $host = '127.0.0.1';
+ }
+ if (isset($config['port'])) {
+ $port = $config['port'];
+ } else {
+ $port = 6379;
+ }
+ if (isset($config['timeout'])) {
+ $timeout = $config['timeout'];
+ } else {
+ $timeout = 0.0; // unlimited
+ }
+
+ $this->instance->connect($host, $port, $timeout);
+ if (isset($config['password']) && $config['password'] !== '') {
+ $this->instance->auth($config['password']);
+ }
- if (isset($config['dbindex'])) {
- $this->instance->select($config['dbindex']);
+ if (isset($config['dbindex'])) {
+ $this->instance->select($config['dbindex']);
+ }
}
}