#117067 Доработка редис на yii проектах RedisSentinel
This commit is contained in:
148
SentinelConnection.php
Normal file
148
SentinelConnection.php
Normal file
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace dominion\cache;
|
||||
|
||||
use Yii;
|
||||
use yii\helpers\Inflector;
|
||||
use Redis;
|
||||
use RedisException;
|
||||
use RedisSentinel;
|
||||
|
||||
class SentinelConnection extends Connection
|
||||
{
|
||||
/**
|
||||
* Команды достапные на любой ноде master или slave
|
||||
* @var array
|
||||
*/
|
||||
public $redisSlaveCommands = [
|
||||
'GET',
|
||||
'HGET',
|
||||
//нужно перечислить все, но пока так
|
||||
];
|
||||
|
||||
public $slaves = [];
|
||||
|
||||
public function executeCommand($name, $params = [])
|
||||
{
|
||||
$this->open();
|
||||
Yii::debug("Executing Redis Command: {$name} " . var_export($params, true), __METHOD__);
|
||||
|
||||
$redis = $this->redis; //мастер
|
||||
$redisCommand = strtoupper(Inflector::camel2words($name, false));
|
||||
if (in_array($redisCommand, $this->redisSlaveCommands))
|
||||
{
|
||||
if(!empty($this->slaves))
|
||||
{
|
||||
//читаем из произвольного раба
|
||||
$redis = $this->slaves[array_rand($this->slaves)];
|
||||
}
|
||||
}
|
||||
|
||||
return $redis->{$name}(...$params);
|
||||
}
|
||||
|
||||
protected function isValidServer(mixed $server): bool
|
||||
{
|
||||
return is_array($server) && isset($server['ip']) && isset($server['port']);
|
||||
}
|
||||
|
||||
public function createClient(array $config): Redis
|
||||
{
|
||||
$service = $config['sentinel_service'] ?? 'mymaster';
|
||||
|
||||
$hosts = is_array($config['sentinel_host']) ? $config['sentinel_host'] : [$config['sentinel_host']];
|
||||
foreach ($hosts as $host)
|
||||
{
|
||||
$newConfig = $config;
|
||||
$newConfig['sentinel_host'] = $host;
|
||||
$sentinel = $this->connectToSentinel($newConfig);
|
||||
|
||||
if ($sentinel->ping())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
$master = $sentinel->master($service);
|
||||
if (!$this->isValidServer($master))
|
||||
{
|
||||
throw new RedisException(sprintf("No master found for service '%s'.", $service));
|
||||
}
|
||||
$slaves = $sentinel->slaves($service);
|
||||
foreach ($slaves as $slave)
|
||||
{
|
||||
if ($this->isValidServer($slave))
|
||||
{
|
||||
//могут быть проблемв из-за большого количества подключений
|
||||
$this->slaves[] = parent::createClient(array_merge($config, [
|
||||
'host' => $slave['ip'],
|
||||
'port' => $slave['port'],
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
return parent::createClient(array_merge($config, [
|
||||
'host' => $master['ip'],
|
||||
'port' => $master['port'],
|
||||
]));
|
||||
}
|
||||
|
||||
private function connectToSentinel(array $config): RedisSentinel
|
||||
{
|
||||
$host = $config['sentinel_host'] ?? '';
|
||||
$port = $config['sentinel_port'] ?? 26379;
|
||||
$timeout = $config['sentinel_timeout'] ?? 0.2;
|
||||
$persistent = $config['sentinel_persistent'] ?? null;
|
||||
$retryInterval = $config['sentinel_retry_interval'] ?? 0;
|
||||
$readTimeout = $config['sentinel_read_timeout'] ?? 0;
|
||||
$username = $config['sentinel_username'] ?? '';
|
||||
$password = $config['sentinel_password'] ?? '';
|
||||
$ssl = $config['sentinel_ssl'] ?? null;
|
||||
|
||||
if (strlen(trim($host)) === 0)
|
||||
{
|
||||
throw new ConfigurationException('No host has been specified for the Redis Sentinel connection.');
|
||||
}
|
||||
|
||||
$auth = null;
|
||||
if (strlen(trim($username)) !== 0 && strlen(trim($password)) !== 0)
|
||||
{
|
||||
$auth = [$username, $password];
|
||||
}
|
||||
elseif (strlen(trim($password)) !== 0)
|
||||
{
|
||||
$auth = $password;
|
||||
}
|
||||
|
||||
if (version_compare(phpversion('redis'), '6.0', '>='))
|
||||
{
|
||||
$options = [
|
||||
'host' => $host,
|
||||
'port' => $port,
|
||||
'connectTimeout' => $timeout,
|
||||
'persistent' => $persistent,
|
||||
'retryInterval' => $retryInterval,
|
||||
'readTimeout' => $readTimeout,
|
||||
];
|
||||
|
||||
if ($auth !== null)
|
||||
{
|
||||
$options['auth'] = $auth;
|
||||
}
|
||||
|
||||
if (version_compare(phpversion('redis'), '6.1', '>=') && $ssl !== null)
|
||||
{
|
||||
$options['ssl'] = $ssl;
|
||||
}
|
||||
|
||||
return new RedisSentinel($options);
|
||||
}
|
||||
|
||||
if ($auth !== null)
|
||||
{
|
||||
/** @noinspection PhpMethodParametersCountMismatchInspection */
|
||||
return new RedisSentinel($host, $port, $timeout, $persistent, $retryInterval, $readTimeout, $auth);
|
||||
}
|
||||
|
||||
return new RedisSentinel($host, $port, $timeout, $persistent, $retryInterval, $readTimeout);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user